Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ember.js how to display different filtered lists for a view? complex setup

I have a an app where i have a car view and i have a list of countries with a checkbox against each that when i check a country it displays a view below with a list of parts available in that country.

Checking more countries displays the parts in more countries down the page.

The parts are all stored in one place but need to be filtered by coutry field to just display parts in that section for that country.

I can create the list of countries and when checked it displays a country section below with the parts list in it but how do i filter to only display for that country. Do i need to create views for each country and a controller for each countries parts to display ??

Surely there is a better way.

EDIT :

This is how i need the page to be displayed :

Coutries : UK <- selected

           USA

           China <- selected


Parts available in UK:

....

Parts available in China

....

So i need seperate lists displayed ofr each country selected.

Please help Rick

like image 271
Rick Moss Avatar asked Mar 01 '12 18:03

Rick Moss


3 Answers

This would probably be best solved using nested views. You can see my jsFiddle here.

I don't think it's a terribly complicated approach, but if you have any questions about the design please let me know.

Handlebars:

<script type="text/x-handlebars">
    {{#each App.countriesController}}
        {{view Ember.Checkbox titleBinding="name" valueBinding="isChecked"}}
    {{/each}}
    <hr />
    {{#each App.countriesController}}
    {{#if isChecked}}
        {{view App.PartsByCountryView contentBinding="this" partsListBinding="App.partsController"}} <br />      
    {{/if}}
{{/each}}
</script>

<script type="text/x-handlebars" data-template-name="selected-country">
    Country: {{content.name}} <br />
    Parts:
    {{#each filteredParts}}
        {{name}}
    {{/each}}
</script>
​

App Code:

window.App = App = Ember.Application.create();
/**************************
* Models
**************************/
App.Country = Ember.Object.extend({
    id: null,
    name: "",
    isChecked: null
});

App.Part = Ember.Object.extend({
    id: null,
    name: "",
    countryId: null
});

/**************************
* Views
**************************/
App.PartsByCountryView = Ember.View.extend({
    content: null,
    partsList: null,
    templateName: 'selected-country',

    filteredParts: function() {
        return this.get("partsList").filterProperty('countryId', this.getPath('content.id'))
    }.property('partsList.@each').cacheable() 
});

/**************************
* Controllers
**************************/
App.set('countriesController', Ember.ArrayController.create({
    content: Ember.A()
}));

App.set('partsController', Ember.ArrayController.create({
    content: Ember.A()
}));

/**************************
* App Logic
**************************/
$(function() {
    App.get('countriesController').pushObjects([
        App.Country.create({id: 1, name: "USA"}),
        App.Country.create({id: 2, name: "UK"}),
        App.Country.create({id: 3, name: "FR"})
    ]);

    App.get('partsController').pushObjects([
        App.Part.create({id: 1, name: "part1", countryId: 1}),
        App.Part.create({id: 2, name: "part2", countryId: 1}),
        App.Part.create({id: 3, name: "part3", countryId: 1}),
        App.Part.create({id: 4, name: "part4", countryId: 2}),
        App.Part.create({id: 5, name: "part5", countryId: 2}),
        App.Part.create({id: 6, name: "part6", countryId: 2}),
        App.Part.create({id: 7, name: "part7", countryId: 2}),
        App.Part.create({id: 8, name: "part8", countryId: 3}),
        App.Part.create({id: 9, name: "part9", countryId: 3}),
        App.Part.create({id: 10, name: "part10", countryId: 3}),
        App.Part.create({id: 11, name: "part11", countryId: 3})
    ]);
});
​
like image 157
Roy Daniels Avatar answered Sep 30 '22 12:09

Roy Daniels


I would structure your application like this:

  1. A model with just a list o part objects. Each object holds how many of that part exist in each country.
  2. A controller that filters that list depending on countries selected.
  3. A view that sets in the controller which countries are selected.
  4. A view that displays a list from the controller with the selected parts.

I've done that here:

http://jsfiddle.net/NPeeQ/2/

window.App = Ember.Application.create();

App.model = Ember.Object.create({

    parts: Ember.ArrayProxy.create({
        content: [
        {
            name: 'wheel',
            stock: {
                uk: 3,
                fi: 2,
                se: 0
            }
        },
        {
            name: 'windscreen',
            stock: {
                uk: 0,
                fi: 1,
                se: 3
            }
        }
    ]}),

    countries: ['uk', 'fi', 'se']

});

App.partController = Ember.Object.create({

    filterBy: {},

    setFilterBy: function (country, on) {

        var filterBy = $.extend({}, this.get('filterBy'));

        if (on) {
            filterBy[country] = true;
        } else {
            delete filterBy[country];
        }

        this.set('filterBy', filterBy);

    },

    // returns all available parts filtered by filterBy.
    availableParts: function () {

        var parts = App.model.parts;

        var filter = this.filterBy;

        var arr = [];

        App.model.countries.forEach(function(c) {

            if (!filter[c]) return;

            arr.push({heading:c});

            var tmp = App.model.parts.filter(function(p) {
                return p.stock[c] && p.stock[c] > 0;
            });

            arr = arr.concat(tmp);

        });            

        return arr;

    }.property('filterBy', 'App.model.parts').cacheable()

});

App.SelectorView = Ember.View.extend({
    templateName: 'selector',

    click: function(event) {

        if (event.target.tagName !== 'INPUT')
            return;

        var clicked = $(event.target).closest('label');
        var index = this.$().find('label').index(clicked);

        var country = App.model.countries[index];
        var on = event.target.checked;

        App.partController.setFilterBy(country, on);

    }
});

App.PartsView = Ember.View.extend({
    templateName: 'parts'
});


$(function() {

    App.selectorView = App.SelectorView.create();
    App.partsView = App.PartsView.create();

    App.selectorView.append();
    App.partsView.append();

})

And the handlebars:

<script type="text/x-handlebars" data-template-name="selector">
    {{#each App.model.countries}}
    <label><input type="checkbox"/> {{this}}</label>
    {{/each}}
</script>

<script type="text/x-handlebars" data-template-name="parts">

    {{#each App.partController.availableParts}}

      {{#if heading}}
        <h2>{{heading}}</h2>
      {{else}}
    {{name}} <br/>
      {{/if}}

    {{/each}}

</script>
like image 39
Martin Algesten Avatar answered Sep 30 '22 12:09

Martin Algesten


For the parts list, you could use an #each helper bound to a collection on a controller. The controller could observe a controller bound to the currently selected countries. When the selection changes, it would update the collection, which would automatically update your parts list.

like image 33
Luke Melia Avatar answered Sep 30 '22 13:09

Luke Melia