-
-
Notifications
You must be signed in to change notification settings - Fork 405
Description
Short version
Closure actions break if you give them an undefined value, making it impossible to have optional actions:
{{x-foo on-bar=(action attrs.not-passed baz)}}Long Version
Consider a hypothetical image component which sends an action when it's loaded:
{{x-image image=image on-load=(action "imageLoaded")}}Now consider an image-list component which displays a list of images:
{{#each attrs.images as |image|}}
{{x-image image=image on-load=(action "imageLoaded" image)}}
{{/each}}So far so good, now this component wants to just pass the loaded event up to its parent component.
Nice and easy to do with closure actions:
{{#each attrs.images as |image|}}
{{x-image image=image on-load=(action attrs.on-image-loaded image)}}
{{/each}}This is called as so:
{{x-image-list images=images on-image-loaded=(action "imageLoaded")}}But we don't want to require having on-image-loaded being passed in, this now breaks:
{{x-image-list images=images}}I know, we'll make the action optional:
{{#each attrs.images as |image|}}
{{x-image image=image on-load=(if attrs.on-image-loaded (action attrs.on-image-loaded image))}}
{{/each}}No dice, (if) isn't lazily evaluated, so the (action) helper gets called with undefined regardless.
Now we're stuck, we can't use closure actions anymore and have to go back to using (action "imageLoaded") and sendAction which is happy if the action isn't wired up.
Possible Solutions
In order of personal preference:
1. Make (if) lazily evaluate
Currently the (if) helper executes both branches before testing (as helpers receive values and not streams), regardless of whether the predicate is interpreted as true or false.
If this instead lazily evaluated then it would be safe to use the action keyword inside an if as the action keyword would only be called if valid:
{{x-image on-load=(if attrs.on-image-loaded (action attrs.on-image-loaded image))}}2. Add optional=true flag to action keyword
{{x-image on-load=(action attrs.on-image-loaded image optional=true)}}This would disable the checks in the action keyword.
I personally prefer this to 3. because it doesn't require an entirely new keyword but still makes it clear what's going on.
3. Add (optional-action) helper/keyword
{{x-image on-load=(optional-action attrs.on-image-loaded image)}}This simply guards against undefined actions before passing along to the action keyword, but is an entirely new helper/keyword just for a guard clause