Using `or` to provide a default event handler for `on`

Hey there,

I’m making a ModalDialog component which takes a onOverlayClick argument. The passed in function will be called when the overlay is clicked (I’m sure you’re surprised :stuck_out_tongue:):

<div role="button" {{on "click" @onOverlayClick}}>
   {{!-- ... --}}
</div> 

Since on throws an error if it’s second argument (the function to call) doesn’t exist, a fallback event handler needs to be provided. Here is my first try:

<div role="button" {{on "click" (or @onOverlayClick (fn))}}>
   {{!-- ... --}}
</div> 

Unfortunately, fn cannot be called without arguments to create an empty function (I think it’d be great if it did), so I went ahead and created a helper that does just that.

I named it noop:

import { helper } from '@ember/component/helper';

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

Armed with nothing (very funny) I rewrote the template snippet as follows:

<div role="button" {{on "click" (or @onOverlayClick (noop))}}>
   {{!-- ... --}}
</div> 

This doesn’t work, however, and the following error is raised:

Compile Error: Unexpected Helper or @ 0…0

To me, this suggests that Glimmer doesn’t expect a helper call as an argument to or. If that is so, I’m not sure I understand why.

Slightly disappointed by the misbehavior of or, I replaced it with the mother of all conditionals, if:

<div role="button" {{on "click" (if @onOverlayClick @onOverlayClick (noop))}}>
   {{!-- ... --}}
</div>

That works but it’s needlessly verbose and more prone to typos.

Alternatively, I could create the “do nothing” fallback function in the backing class of the component, but it’s so far a template-only component and it’d be kind of funny to create a component class just to do that.

Can you explain why on wouldn’t work like above? If it’s the wrong idea, is there a way to provide the fallback function in template-land, that’s more elegant than my solution with if?

Thank you.

2 Likes

Did you install ember-truth-helpers? As far as I can remember or is not included as a default helper (yet?).

Also is the nested on click helper call accidental or am I misunderstanding? :thinking:

1 Like

or is part of Ember, not sure since when but for a while now.

How clumsy :man_facepalming: , yes, that wasn’t intentional, I fixed it, thanks. It wasn’t the source of the error, though, it still doesn’t work with the elegant or.

1 Like

You 100% sure? or is not listed on Ember.Templates.helpers - 4.6 - Ember API Documentation

1 Like

Nick, you’re so right, that was it, or is indeed not part of the framework (but there at least must be an RFC to include it, else where did I get this from?)

I read the error message the wrong way:

Compile Error: Unexpected Helper or @ 0…0

Here, “or” refers to the or helper but I thought it was part of the sentence and meant the error is either an unexpected helper or @0…0 (I told myself @0..0 was kind of cryptic :joy: )

I also think the error message for a helper that’s not found has changed so I didn’t even consider this possibility mentally. Anyway, thanks a ton!

3 Likes

You’re welcome! There were indeed a couple of RFC’s. It seems they have not gone through yet though. The original was closed in favour of splitting them it into multiple RFC’s.

The revelant one here is: Adding Logical Operators to Templates by cibernox · Pull Request #562 · emberjs/rfcs · GitHub

2 Likes

There is: Adding Logical Operators to Templates by cibernox · Pull Request #562 · emberjs/rfcs · GitHub

1 Like

There are some helpers in ember-composable-helpers that might be of interest!

For one, it ships a noop helper that can be used without your app defining it manually.

Even better though is the optional helper that explicitly is intended for wrapping an action that may not exist. The result is the same as using or and noop but I think that the intention of the template reads a little more cleanly with a purpose-built helper for this task!

2 Likes

Thanks, Alex, that’s great.