Is conditional `fn` helper possible in Ember 3.24?

I usually did this approach to handle with actions that are optionals:

<MyComponent class=“my_component_class” @onChange={{if @changeHandler (fn @changeHandler this.param)}} />

This worked fine until Ember 3.20, starting in Ember 3.24 I got a Assertion Failed: You must pass a function as the fn helpers first argument, you passed undefined

I fixed it using an if block with the component without the @onChange parameter in else. This is a bug?

I think I may have run into something like this recently too. Not sure what changed but maybe helpers are evaluated more eagerly now.

For actions I’d typically use ember-composable-helpers {{optional}} helper:

<MyComponent class=“my_component_class”
  @onChange={{fn (optional @changeHandler) this.param}}
/>

Which should fix this issue as it just uses a no-op (but still defined) function if the changeHandler isn’t passed.

1 Like

Very helpful! Thank you!

This is one of the use cases motivating RFC 676: Return noop function from {{fn}} helper if invoked without arguments.

Some alternatives for completness

ember-truth-helpers

<MyComponent class=“my_component_class”
  @onChange={{fn (or @changeHandler (noop)) this.param}}
/>

no addon

<MyComponent class=“my_component_class”
  @onChange={{if @changeHandler (fn @changeHandler this.param)}}
/>

Where noop is

export default helper(function noop() {
  return () => {};
});

I think you are missing the branch if @changeHandler is not set in no addon example. It should be

<MyComponent class=“my_component_class”
  @onChange={{if @changeHandler (fn @changeHandler this.param) noop}}
/>

Depends on how MyComponent is designed. Who is to say who is responsible for optional logic, the use of it or the producer of it?

In my example I made the assumption that @onChange is optional thus the second part of the {{if can be undefined. While in your example it is assumed that @onChange is not optional thus requiring the consumer to provide a noop alternative.

Both are valid options and depends on the architecture of the MyComponent implementation.

The only concrete thing here is that the fn helper requires a function. Thus the need for the noop in the first example. And the assumed not-need in the second.