This is a feature request, but it needs some fleshing out.
I want to be able to interact with the selectedItem in a multiple-select. My particular case needs to allow the user to click/touch the selected items to do "things".
Using selectedItemComponent makes this easy, however I want to trigger actions from the component and bubble them up.
Should there be a way to pass actions closures into the selectedItemComponent? Or is the right way to do this using Evented or a Service?
Yeah, it's a reasonable request. Pass the publicAPI (the select) object to this component too in this line: https://github.com/cibernox/ember-power-select/blob/master/addon/templates/components/power-select/trigger.hbs#L3
Out of curiosity, customizing the triggerComponent doesn't work for you? Or is just that looks more involved?
Great little fix there, thanks. I will give it a go and submit a PR if it works out.
As for customizing the triggerComponent, that was my first idea too, but it is quite involved. It is a lot of code to duplicate just to hook the selectedItemComponent.
Sounds fair. Precisely this component exists to not force people to create their own trigger.
I haven't added to the docs any doc about how to customize components components, specially the complex ones, but in general the best thing to do is make your component extend from the default trigger (unless your behaviour is very very different) and just copy the template, and start modifying the bits you want.
Whenever you do this PR add a test to assert that the selectedItemComponent receives an object named select with the expected properties/actions, so I don't remove it by mistake, both in single and multiple selects.
How do I attach my own action to the publicAPI object. It looks like maybe I need to get it in dropdown.actions but I'm not seeing how to inject that.
Replace this line by
{{component selectedItemComponent selected=selected lastSearchedText=lastSearchedText select=select}}
All the actions are already closures around the dropdown as first argument. You don't need to care about that once inside the subcomponents, everything is done in the {{power-select}}
Yea, I've got that much.. but how do I inject my own actions into the select object and use them in the selectedItemComponent?
For example, this is what I mean, though it doesn't work of course:
{{#power-select-multiple
options=options
selected=selected
selectedItemComponent="my-actionable-component"
onchange=(action (mut selected))
onMyCustomAction=(action "myCustomAction")
as |item|
}}
{{item.name}}
{{/power-select-multiple}}
in my-actionable-component.js:
export default Component.extend({
...
click() {
this.get('select.onMyCustomAction')(); // Or something else here?
}
...
});
There is no support for that, although there is workaround using the extra property.
But if you are in 2.3+ there is an ideal solution.
Yup, 2.4.1.
I'm guessing its probably best if I extend the multiple trigger component, though I wanted to avoid duplicating all the template code.
But what's the workaround? :smiley:
Contextual components are ideal for this.
{{#power-select options=opts
selected=foo onchange=(...)
selectedItemComponent=(component "my-custom-component" doStuff=(action "foobar")) as |opt|}}
{{opt}}
{{/power-select}}
If you end up extending the trigger I suggest you to install 0.10.0.
There was a breaking change yesterday and you want to copy the new template.
Woah, that's great. I had no idea the component helper could also be used that way.
I'm using 0.10.0-beta.2 at the moment. I'll still need to extend the trigger to prevent the dropdown for appearing when the item component is clicked.
Thanks a ton!
@Ramblurr Instead of that, you should use mousedown in your selectedItemComponent and just call e.stopPropagation()
@cibernox I tried that first, but it seems like the handleOpen / open action is getting triggered before the mouseDown in my itemComponent.
I tried with this rather overkill mouseDown, and it doesn't work as the open event is happening first:
mouseDown(e) {
console.log("MOUSEDOWN");
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
return false;
},
Reading the source, it seems the trigger isn't even responsible for opening the dropdown. I assumed that because of the name. "trigger", ah well.
In the main power-select-multiple component there is the handleOpen action. But it doesn't seem cancel-able in anyway. Perhaps I will have to extend power-select-multiple and not the trigger.
That's unexpected. I (intentionally) use only the bubbling phase in this component precisely to allow people to capture events inside their own components and stop the propagation to highjack the default behaviour, like you in this case.
You should be able to capture this mousedown event before it's handled by the trigger. Can you (only for paranoia) check if doing
didInsertElement() {
this._super(...arguments);
this.element.addEventListener('mousedown', function() {
console.log('mousedown');
});
}
Makes any difference? I think I remember that jquery events do some weird things with the bubbling phase.
Yea! That fixes it. Strange, why would this work and not the ember "mouseDown" method?
/// in my selectedItemComponent
didInsertElement() {
this._super(...arguments);
this.element.addEventListener('mousedown', function(e) {
e.stopPropagation(); // this prevents the open event
console.log('other mousedown!');
return false;
});
},
jQuery is amazing in many ways but the event model is fundamentally un-aligned with the native event bubbling.
Another "LOL javascript" moment
@Ramblurr Can this be closed?
Yup, thanks for the support @cibernox.
For those that land here eventually, here is how I was able to interact with my selectedItemComponent without having to extend the trigger. In my case "interact" meant handling click events on the selected items.
// in my-select-component.hbs
{{#power-select-multiple
...
selectedItemComponent=(component "selected-item" onItemClicked=(action "itemClicked") someValues=stuff)
...
Then in selected-item.js
...
didInsertElement() {
this._super(...arguments);
this.element.addEventListener('mousedown', (e) => {
e.stopPropagation();
return false;
});
},
...
btw, it's just enough to call e.stopPropogation() inside mousedown callback
Most helpful comment
Yup, thanks for the support @cibernox.
For those that land here eventually, here is how I was able to interact with my selectedItemComponent without having to extend the trigger. In my case "interact" meant handling click events on the selected items.
Then in selected-item.js