Difference between {{did-update}} and <div {{did-update}}> in Ember JS

Viewed 31

When I use did-update without wrapping using <div>, the action using in did-update fall into infinite loop. After wrapping with <div>, the problem has solved.

Here's an example code: (current is service which shows the current status)

Does not work: (when this.current.locationId changed, this.updateStates be executed infinitly)

{{did-update this.updateStates this.current.locationId}}

Does work:

<div {{did-update this.updateStates this.current.locationId}}>
</div>

JS file:

@tracked property;

@action
updateStates() {
  //do something with `this.current.locationId`
  //change value of `property`
  //so template re-render cause of `property` changed
  ...
}

I guess the problem happens because of the tracking frame. But I can not exactly see why that kind of problem is happening.

1 Answers

Depending on which addon is bringing in {{did-update}}, it looks like it only defines a modifier.

When using the globals resolver (where you don't need to import anything), the syntax matters more than the name of the thing you're typing.

So, {{did-update}} in a template is a helper. This will be looked up in app / addon's helpers directories. <div {{did-update}}> is a modifier. This will be looked up in app / addon's modifiers directories.

I made this little explainer for how to read the syntax:

<div {{this.modifierName a b=(this.helperName c)}}>
{{!--  │                 │ │  │               └─── positional argument
       │                 │ │  └─── helper
       │                 │ └─── named argument key
       │                 └─── positional argument
       └─── modifier --}}
  {{yield to="default"}}
{{!--  │  │   └─── value
       │  └─── named argument key
       └─── helper --}}
</div>

<div {{@modifierName a b=(@helperName c)}}>
{{!--  │             │ │  │           └─── positional argument
       │             │ │  └─── helper
       │             │ └─── named argument key
       │             └─── positional argument
       └─── modifier --}}
  {{yield to="default"}}
{{!--  │  │   └─── value
       │  └─── named argument key
       └─── helper --}}
</div>

From: https://cheatsheet.glimmer.nullvoxpopuli.com/docs/templates


There is a slight difference when you a local value. For example:

class Demo extends Component {
  foo = () => {};
}

using this function, foo, we can use it the following ways

{{this.foo}} renders, but is a function, so it doesn't render nicely
{{ (this.foo) }} invokes the function and renders the output, or nothing if undefined

<div {{this.foo}}></div> errors, because the function, foo, is not a modifier
<div {{ (this.foo) }}></div> invokes foo, because it is a function / helper, returns undefined, which is now in "modifier space", undefined modifiers are no-ops, and does nothing. This is useful for when you want to do conditional modifiers
<div {{ (if this.someCondition this.myModifier}}) }}></div> this will collapse down to (if some condition is true):
<div {{this.myModifier}}></div>

<this.foo /> errors, because the function, foo, does not have an associated component manager / foo is not a component.
Related