Chris
Chris

Reputation: 3657

Emberjs trying to create "radio button" type functionality

When a user clicks a model, set isActive:true and set all other models isActive:false.

I have two components and a route involved in trying to achieve this.

Starting at the top I have a distro-item which is a single model item

//components/distro-item
export default Component.extend({
  classNames: 'column is-2',
  tagName: 'div',
  isActive: false,

  actions: {
    toggleActive (distro) {
      this.sendAction('toggleActive', distro);
    }
  }

});

I then have a holder component which holds all the distro-items

// components/distro-holder
export default Ember.Component.extend({
  sortedDistros: Ember.computed.sort('distros', 'sortDefinition'),
  sortDefinition: ['sortOrder:acs'],

  distros: computed('[email protected]', function () {
    console.log("triggered");
  }),

  actions: {
    toggleActive(distro) {
      this.sendAction('toggleActive', distro);
    }
  }

});

Finally the route

//route/new
export default Route.extend(AuthenticatedRouteMixin, {

  selectedDistro: undefined,

  model() {
    return RSVP.hash({
      distros: get(this, 'store').findAll('distro'),
    });
  },

  setupController(controller, models) {
    controller.setProperties(models);
  },

  actions: {
    toggleActive(distro) {
      this.set('selectedDistro', distro);
    },
  }

});

I'm not sure which of the three things should be responsible for each part of the processes. initial thinking is the distro-holder should be responsible for figuring out which state each distro should be in, and sending that back to the route. However no matter what I try, I can't get the computed property to trigger. Should this be on the route, or elsewhere?

The documentation example seems to have it on the equivalent to the distro-holder. When I change the state of isActive it doesn't fire as I expect...

Any help is appreciated!

Upvotes: 1

Views: 81

Answers (1)

jacefarm
jacefarm

Reputation: 7451

Instead of a computed property in distro-holder, set a selectedDistro property, and pass it to each distro-item. Then, each distro-item can be aware and set a selected state to true if its data is the same as the selectedDistro data, or false if it is not (similar to how an individual radio is aware of its radio group value).

In the distro-item component, when a distro-item is clicked, it sends its data to the distro-holder via the toggleActive action:

actions: {
  toggleActive(distro) {
    this.sendAction('toggleActive', distro); // goes up to distro-holder
  },
}, 

The distro-holder component receives this data and sets the selectedDistro property:

selectedDistro: null,

actions: {
  toggleActive(distro) {
    this.set('selectedDistro', distro);
    this.sendAction('setName', distro); // goes up to the controller
  }
}

The distro-item component has its selected computed property listening to selectedDistro, and sets selected, for itself, to true or false (which means, only one distro-item will be selected at any given time):

selected: Ember.computed('selectedDistro', function() {
  return this.get('selectedDistro.name') === this.get('distro.name');
}),

To demonstrate taking the data further up into the controller, distro-holder sends the setName action, which the controller receives and executes:

selectedDistro: null,

actions: {
  setName(distro) {
    this.set('selectedDistro', distro.name);
  }
}

If not aware, this approach utilizes the Ember convention of Data Down, Actions Up. Ensuring that you are passing data (and the actions to be used) down into each component, and then sending the action back up (with data) can be tricky to understand and get right at first.

I've created an Ember Twiddle example to demonstrate.

Upvotes: 1

Related Questions