0

My situation is I have a table where the user can add suppliers, and edit any existing ones (so there are potentially multiple records). Three of the fields (Type, Name, Version) come from a lookup object returned by the API (which is one table in the backend database).

Before clicking 'edit' Before clicking edit

In edit mode In edit mode for a single row

The thing is, I need these select elements to be "chained" (or cascading), but since they're populated from the same object, it's more like the selection of "Type" will filter the options available for "Name" and likewise selecting Name will further restrict the options available for Version.

However, since this is just one record being edited, these selects are in an {{#each supplier in suppliers}} block to generate the rows, and show selects if that record's isEditing property is true, so the value or selection is the per-record value, e.g. supplier.type and not a single property on the whole controller.

I've tried to come up with multiple ways to do this, but so far haven't found a solution to cascading dropdowns with multiple records since that means the value of any one select is dependent on the record.

I think I could get the option filtering to work if I knew how to reference the value of say the Type dropdown from within the controller, but then again it's conceivable that two records could be in edit mode at once, so modifying any property on the controller to populate the selects would affect the others too, and that's not good. I just really wanted to figure this out so I didn't have to pop up a modal dialog to edit the record.

redOctober13
  • 3,662
  • 6
  • 34
  • 61

2 Answers2

0

You should use components to handle each row seperately.

Let's say that you have something like this:

{{#each suppliers as |supplier|}}
  // .. a lot of if's, selects and others
{{/each}}

If you find yourself using {{#each}} helper and your block passed to that helper is more than one line, than it's a good sign you probably need a component there.

If you create a component named, let's say, SupplierRow you could make it as follow:

module export Ember.Component({
  editing: Ember.computed.alias('model.isEditing'),
  types: Ember.computed('passedTypes', function() {
    // .. return types array for that exact supplier 
  }),
  names: Ember.computed('passedNames', 'model.type', function() {
    // .. return names array for that exact supplier based on possibleNames and model.type
  }),
  versions: Ember.computed('passedVersions', 'model.type', 'model.name', function() {
    // .. return versions array for that exact supplier based on possibleVersions and model.type and model.name
  }),
  actions: {
    saveClicked() {
      this.sendAction('save', this.get('model'));
    }
  }
});

The template would basically look similiary to what you have currently in your {{#each}} helper. It would be rendered something like this:

{{#each suppliers as |supplier|}}
  {{supplier-row model=supplier possibleTypes=types possibleNames=names possibleVersions=versions save="save"}}
{{/each}}
Kuba Niechciał
  • 974
  • 7
  • 9
  • Not sure who voted this answer down, because it seems like it's the right direction to me. I'm not very comfortable with components yet, but I need to get there if I'm going to move past Ember 1.11. I'm not sure I'd need to pass in three different things though, since to filter Names, I need Types, and to filter Version, I need Name and Type. – redOctober13 Sep 18 '15 at 10:10
  • 1
    As possibleSomething I meant that you need all of the possibilities to filter. If you have them in one object, you can pass just one. Do not use itemControllers unless you want to stuck your app on Ember 1.11 - think about future and maintenance :) – Kuba Niechciał Sep 18 '15 at 10:13
  • What's the difference between `suppliers as |supplier|` and `supplier in suppliers`? – redOctober13 Sep 18 '15 at 11:07
  • It's new syntax for iterating through an enumerable in Handlebars. `supplier in suppliers` is depreciated in newer versions of Ember. [Take a look at this question](http://stackoverflow.com/questions/30144035/what-is-the-each-as-syntax-in-ember/30144548#30144548) – Kuba Niechciał Sep 18 '15 at 11:23
  • And is that `computed` you have for isEditing shorthand? Doesn't computed always have to have a function to return the thing? – redOctober13 Sep 18 '15 at 12:00
  • 1
    Oh, it was a typo. It should be `Ember.computed.alias('model.isEdititng')`. [Take a look here to see all the Ember computed makros](http://emberjs.com/api/classes/Ember.computed.html). – Kuba Niechciał Sep 18 '15 at 12:15
  • Components to the rescue! This was definitely the way to go. – redOctober13 Sep 18 '15 at 16:02
-1

Seems like you are using an old version of Ember wich allows context switching in {{#each}} helpers. Assuming that, you can set itemController for each iteration and handle selectable values for each row separately:

{{#each suppliers itemController="supplierController"}}
    // this == supplierController, this.model == supplier
{{/each}}

So inside the supplierController you can calculate select content for each single supplier. You can also access main controller from item controller by this.parentController property.

Artur Smirnov
  • 804
  • 5
  • 14
  • Thanks for chiming in. I should have specified the version (1.11), so context-switching is already out, and itemControllers are deprecated, so this isn't a good option for the future for me. – redOctober13 Sep 18 '15 at 10:17
  • Even if someone is using old version of Ember I don't think it's responsible to use depreciated features. Eventually, everybody will need to migrate to new versions so if the proper solution according to new versions is available, why not use it? – Kuba Niechciał Sep 18 '15 at 10:20
  • @JakubNiechciał it was not deprecated in older versions. Some projects don't have sufficient time to update, so they have to solve problems using the old API. Assuming the syntax for `each` helper in the question (`{{#each supplier in suppliers}}`) i suggested, this is the case. And that's why I proposed old-fashioned solution - just to help the requester. The solution with components might work for him as well, but it's more complicated. – Artur Smirnov Sep 18 '15 at 10:27