Accessing templates as data

Let’s say I have the following template:

<DropdownList as |List|>
  <List.item>
    One
  </List.item>
  <List.item>
    Two
  </List.item>
  <List.item>
    Three
  </List.item>
</DropdownList>

Is it possible for DropdownList to have a computed property that iterates over its children Item components?

I’ve seen some “registration” patterns

{{yield (hash
  item=(component 'dropdown-list/item'
    did-insert=(action 'registerItem')
  )
)}}

but I sometimes hit the “you modified X twice in a since render” error with this pattern, and I’m just wondering if there’s any other approaches.

Shut up and show me the code!

Ok here ya go:

This is one way I’ve hacked around this problem, but feel there must be a better way.

I guess one way to sum up the problem: a parent’s rendered output depends on actually rendering its children.

You can see I use run.next to basically re-render the template n times (where n is the amount of children). If you re-run the app you’ll see a bit of flicker.

Any way around this?

Just use didInsertElement instead of init.

I made a twiddle but github is dead.

Replace:

  init() {
    this._super(...arguments);
    
    next(() => {
      this.list.items.pushObject(this);
    });
  }

with

  didInsertElement() {
    this.list.items.pushObject(this);
  }

and all works fine

1 Like

Thanks @alexspeller! Confirm github is borked but I tried it locally and it seemed to work…

I swear I’ve run into issues with this before but I’ll try this back in my app and report back. Thanks again :+1: