Questions about actions


#1

Hi,

I’m still discovering Ember and I am confused about the way actions are handled. To be more specific, I’m using a Bootstrap dropdown button provided by the ember-boostrap module. I’m looking for a way to have some items sorted depending on the option chosen by the user.

Here’s what the code looks like:

{{#bs-dropdown id="sort" as |dd|}}
   {{#dd.button}}Sort By {{/dd.button}}
   {{#dd.menu as |ddm|}}
       {{#ddm.item action "sortByPrice" low_to_high}}{{#ddm.link-to "index"}}Prix croissant{{/ddm.link-to}}{{/ddm.item}}
       {{#ddm.item}}{{#ddm.link-to "index" onclick="sort_by_price('high_to_low')"}}Prix décroissant{{/ddm.link-to}}{{/ddm.item}}
    {{/dd.menu}}
{{/bs-dropdown}}

As you can see on the second item, I used the very naive way with the normal JS “onclick” attribute, which didn’t work as the attribute wasn’t even displayed on the final HTML.

On the first item, I tried to create an action and pass it “low_to_high” as a parameter. However, I’m unable to have this action performed. I did check the documentation, but I’m a little confused by some aspects of it, and the architecture of the ember-bootstrap module is rather confusing.

I first tried to edit the node_modules/ember-bootstrap/addon/components/base/bs-dropdown.js file. The file starts with

import Component from '@ember/component';
import { computed } from '@ember/object';
import { bind } from '@ember/runloop';
import layout from 'ember-bootstrap/templates/components/bs-dropdown';

And then there is:

export default Component.extend({
layout,
classNameBindings: ['containerClass'],
....
actions: {
// My addition
sortByPrice(param){
  alert("sorting");
},

toggleDropdown() {
  if (this.get('isOpen')) {
    this.send('closeDropdown');
  } else {
    this.send('openDropdown');
  }
},

I wasn’t sure if it was the right file to edit and if it was actually used, but making changes to it impacts the actual web page. However, the added new action is never executed.

I then made the same changes to the node_modules/ember-bootstrap/addon/components/base/bs-dropdown/menu/item.js

import Component from '@ember/component';

/**
 Component for a dropdown menu item.
 See [Components.Dropdown](Components.Dropdown.html) for examples.

@class DropdownMenuItem
@namespace Components
@extends Ember.Component
@public
*/
export default Component.extend({
   actions:{
	sortByPrice(param){
      console.log("sorting");
    }
   }
});

So what confuses me is

  1. Why do these pages contain “extended” classes, and for example, what links the DropdownMenuItem to all the rest? I assume that there should be a file compiling several other files, but I can’t find any trace of this snippet in the generated JS file.
  2. Is there any way to add a classic “onclick” event?
  3. In this particular case, what is the relationship between the menu-item and the bootstrap-menu? Would it be possible for instance to use a menu_item outside of a bootstrap_menu

Thank you for going through all this, and feel free to ask me if I missed some explanations.


#2

I’ve never used ember-bootstrap before so I’m just hazarding a guess :grimacing:

If you want to fire an action when one of your ddm.item is clicked, you probably need to follow the pattern here from the docs. You add some HTML inside your ddm.item component and add the action handling to that.

{{#bs-dropdown id="sort" as |dd|}}
   {{#dd.button}}Sort By {{/dd.button}}
   {{#dd.menu as |ddm|}}
       {{#ddm.item}}
           <a href onclick={{action "sortByPrice" "low_to_high"}}>Prix croissant</a>
      {{/ddm.item}}
    {{/dd.menu}}
{{/bs-dropdown}}

#3

Thanks. I ended up with a similar approach.


#4

Just to clarify, here’s the code I have currently, and it does work:

{{#bs-dropdown id="sort" as |dd|}}
          {{#dd.button}}Trier par {{/dd.button}}
          {{#dd.menu as |ddm|}}
              {{#ddm.item action}}<a class="dropdown-item" {{action "sortByPrice" "low_to_high"}} href>Prix croissant</a>{{/ddm.item}}
              {{#ddm.item action}}<a class="dropdown-item" {{action "sortByPrice" "high_to_low"}} href>Prix décroissant</a>{{/ddm.item}}
            {{/dd.menu}}
 {{/bs-dropdown}}

Now I’d like to know why this works and the following one doesn’t:

{{#bs-dropdown id="sort" as |dd|}}
          {{#dd.button}}Trier par {{/dd.button}}
          {{#dd.menu as |ddm|}}
              {{#ddm.item action "sortByPrice" low_to_high}}{{#ddm.link-to "index"}}Prix croissant{{/ddm.link-to}}{{/ddm.item}}
          {{/dd.menu}}
{{/bs-dropdown}}

Here’s what the Controller looks like:

export default Controller.extend({
  actions:{
	sortByPrice(order){
		$grid.isotope({
			sortBy: "price",
			sortAscending: (order == "low_to_high")
		});
	}
  }
});

Thanks


#5

This addon may be helpful with what you are looking for: https://emberobserver.com/addons/ember-link-action

I have not tried it with the extended bootstrap link-to, but I think it should work just fine.


#6

Actually I’ve found a fix as I said previously, but I’m curious to know what’s the difference between the code examples in my last reply.


#7

The ddm.item component has no API at all, so it won’t do anything with the arguments you passed it. See: https://www.ember-bootstrap.com/api/classes/Components.DropdownMenuItem.html

Your first example works because you defined an action on a plain anchor tag. You did lose the routing action of link-to though (the link-to "index"). For more information on how the action helper works see: https://guides.emberjs.com/release/templates/actions/