Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

running {#await} inside an {#if} #1496

Closed
kaisermann opened this issue May 25, 2018 · 8 comments · Fixed by #3142
Closed

running {#await} inside an {#if} #1496

kaisermann opened this issue May 25, 2018 · 8 comments · Fixed by #3142
Labels

Comments

@kaisermann
Copy link
Member

REPL

If we have a {#await} block running inside a truthy {#if} and, for some reason, the {#if} evaluates to false while the promise is still running, we get an error:

Uncaught (in promise) TypeError: Cannot read property 'removeChild' of null
    at detachNode (eval at createComponent (repl.1.js:1), <anonymous>:296:19)
    at Object.destroy [as d] (eval at createComponent (repl.1.js:1), <anonymous>:116:6)
    at update (eval at createComponent (repl.1.js:1), <anonymous>:332:17)
    at promise.then.value (eval at createComponent (repl.1.js:1), <anonymous>:347:5)
@Conduitry Conduitry added the bug label May 29, 2018
@Conduitry
Copy link
Member

I think it makes sense to work on this right after or alongside #1514, because that's going to touch the await block code anyway. I just have yet to find a way of dealing with that issue that I'm happy with.

@aseem2625
Copy link

aseem2625 commented Sep 6, 2018

Using svelte": "2.13.2"

I'm facing same issue:

{#if $someStoreData}
  <componentA />
{:else}
  <componentB />
  <componentC />
{/if}

Initially, componentB and componentC are rendered. On $someStoreData becoming true, componentA is getting rendered fine. But the other components are creating trouble by getting destroyed twice. So, second time when it starts to destroy, it throws error: Cannot read property 'removeChild' of null.

Any idea, how to resolve?


I tried the same thing with following:

{#await promise}
	<ComponentA />
{:then answer}
         <ComponentB />
         <Component C/>
{:catch error}
         <ComponentB />
         <Component C/>>
{/await}

<script>
	export default {
		data() {
			return {
				promise: new Promise(fulfil => {
					setTimeout(() => fulfil(42), 3000);
				})
			};
		}
	};
</script>

Same issue is there. It tries to remove the element twice.

In the following code:

  function detachNode(node) {
    node.parentNode.removeChild(node);
  }

First time when it detaches Node, node is getting destroyed rightly but it automatically tries to detach second time as well. 2nd time when it does, it is Text Node:

image

Issue also comes with await example in documentation.

@aseem2625
Copy link

After few hours of trying, got a resolution.
Solution:
Wrap those elements inside div element. Therefore:

<div>
  {#if $someStoreData}
    <ComponentA />
  {:else}
    <ComponentB />
    <ComponentC />
  {/if}
</div>

Why?
I tried to go for alternate solution, which was:

{#if $someStoreData}
  <componentA />
{/if}
<!-- Inside corresponding files for below, as per condtion, add class to "display:none" -->
<componentB />
<componentC />

Results were same, but it popped up different error this time, which was of insertBefore of null. It essentially wanted some DOM to be present. Once, it also gave error on removeChild of null which was node.parentNode(target..). It essentially meant that it was trying to find relative paths corresponding to node (other Component)in the same file. So, only solution was to wrap it in parent div, so it doesn't have to find relative path w.r.t other siblings which were getting removed, hence error.

@hperrin
Copy link
Contributor

hperrin commented May 9, 2019

How's the progress on this? I've just been avoiding {#await} in Svelte 3, cause the wrapping div fix no longer works.

@ciri
Copy link

ciri commented May 10, 2019

You may be able to apply this quick hack to get the project running: #2086 (comment)

@Rich-Harris
Copy link
Member

The original gist is 404ing — does anyone know if it's still happening, and can repro?

@Conduitry
Copy link
Member

Conduitry commented Jun 29, 2019

IIRC the original repro - converted into v3 - was something like this:

<script>
	let promise = new Promise(res => setTimeout(res, 2000));
	let flag = true;
	setTimeout(() => flag = false, 1000);
</script>

{#if flag}
	{#await promise then _}DONE{/await}
{/if}

which does seem to still be an issue. We're trying to do target.insertBefore when target is null.

@Rich-Harris
Copy link
Member

Fixed at last in 3.6.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants