Skip to content

fix: when directive: child bindings may evaluate with no controller after teardown/recreate #7422

@albertor24

Description

@albertor24

🐛 Bug Report

Template bindings may evaluate on a child element with no controller, crashing when a parent when directive tears down and recreates the child.

💻 Repro or Code Sample

https://stackblitz.com/edit/typescript-fuiufsk7?file=index.ts

Conditions required to reproduce:

  1. A parent component uses a when directive to conditionally render a child custom element, with a property binding that pushes data onto the child:
    ${when(x => x.currentData, html`<my-child :data=${x => x.currentData}></my-child>`)}
  2. The parent's when condition toggles — tearing down the child and then recreating it — while the property binding immediately pushes data onto the newly created child
  3. The child's template reads a property from the pushed data (e.g. ${x => x.data?.label})

When the when directive creates a new <my-child> element, the parent's :data binding sets .data on it at some point where the controller is undefined.

Steps to reproduce:

  1. Open the repro page
  2. Click Toggle (tears down <my-child>, sets currentData = undefined)
  3. Click Toggle (rebuilds <my-child>, sets currentData = { label: "A" })
  4. Click Cycle data (swaps currentData to { label: "B" })
  5. Click Togglecrash: the binding x.data?.label evaluates with x as undefined
class MyChild extends FASTElement {
    @observable data: { label: string } | undefined;
}

// Template reads from the pushed data
const childTemplate = html<MyChild>`
  <div>
    <p>Data: ${x => x.data?.label ?? "(none)"}</p>
  </div>
`;

🤔 Expected Behavior

When the parent's when directive rebuilds the child element and the property binding pushes data, template bindings on the child should not evaluate until the Controller is available.

😯 Current Behavior

The parent's when directive creates a new child element and the :data binding immediately sets .data on it. The observable change notification causes the child's template bindings to evaluate before the controller is available. At that point the Controller is not connected, and the binding's source (x) is undefined, causing a crash.

Call sequence:

  1. Parent sets currentDatawhen condition becomes truthy → new <my-child> element created
  2. Parent :data binding sets .data on the new element (before it's connected to the DOM?)
  3. data change fires an observable notification → child template bindings evaluate
  4. The binding x => x.data?.label runs with x as undefined → crash

💁 Possible Solution

Framework-level fix: FAST's binding/observable system should defer template binding evaluation on a custom element until its Controller is connected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions