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

Component two-way binding edge case #277

Closed
Rich-Harris opened this issue Feb 2, 2017 · 0 comments
Closed

Component two-way binding edge case #277

Rich-Harris opened this issue Feb 2, 2017 · 0 comments
Assignees
Labels

Comments

@Rich-Harris
Copy link
Member

This might be a wontfix (it's a niche problem, and it's very easily worked around) but I don't have time to fully investigate it right now, so just leaving myself some breadcrumbs:

<p>y: {{y}}</p>

{{#if x}}
  <Foo bind:y/>
{{else}}
  <Bar bind:y/>
{{/if}}

<Baz bind:x/>

<script>
  import Foo from './Foo.html';
  import Bar from './Bar.html';
  import Baz from './Baz.html';

  export default {
    components: {
      Foo,
      Bar,
      Baz
    }
  };
</script>

// Foo.html
<p>y: {{y}}</p>

<script>
  export default {
    data: () => ({
      y: 'foo'
    })
  };
</script>

// Bar.html
<p>y: {{y}}</p>

<script>
  export default {
    data: () => ({
      y: 'bar'
    })
  };
</script>

// Baz.html
<script>
  export default {
    data: () => ({
      x: true
    })
  };
</script>

That looks like it should result in this...

<p>y: foo</p>
<p>y: foo</p>

...but in fact it ends up like this:

<p>y: undefined</p>
<p>y: foo</p>

That's because on the initial pass, the {{else}} part is rendered, which initialises the binding between Main and Bar (because x doesn't yet have a value). Then, Svelte encounters the <Baz bind:x> component, and creates a new binding.

Bindings are flushed, which means that x has a value, which means that Bar is torn down (which has the effect of setting its _state to {}). Then the Bar binding is triggered, and y is set to undefined in Main.

As a starting point, no observer should be created when triggering a binding on a torn down component. (Perhaps observing a torndown component should also have no effect, or even throw — possibly a separate question.)

Changing the order of things in the template in Main.html yields different results:

<p>y: {{y}}</p>

<Baz bind:x/>

{{#if x}}
  <Foo bind:y/>
{{else}}
  <Bar bind:y/>
{{/if}}
<p>y: bar</p>
<p>y: bar</p>

(bar and not foo because by the time <Foo bind:y/> is created, y has a value in the parent component, and the child won't override the parent. Removing the phantom observer would presumably fix that as well.)

@Rich-Harris Rich-Harris added the bug label Feb 2, 2017
@Rich-Harris Rich-Harris self-assigned this Feb 2, 2017
Rich-Harris added a commit that referenced this issue Feb 3, 2017
Don't trigger bindings for torn-down components
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant