Невозможно изменить данные модели с помощью Ember API Kit

Я уже несколько недель пытаюсь изучить основы Ember, и в настоящее время я сталкиваюсь с проблемой изменения данных в моей модели с помощью действия в контроллере.

Все примеры, которые я нашел, похоже, используют одномерные приборы. Приборы, которые я использую, выглядят так:

App.ClassGroup = DS.Model.extend({
    className: DS.attr('string'),
    isActive: DS.attr('number'),
    students: DS.hasMany('Students',{async:true}),
    selected: DS.hasMany('Students',{async:true})
});

App.ClassGroup.FIXTURES = [
    {
        id: 123,
        className: 'Class 1',
        isActive: 1,
        students: [11, 22, 33, 44, 55],
        selected: [11, 22, 33, 44, 55]
    },
    {
        id: 456,
        className: 'Class 2',
        isActive: 0,
        students: [66, 77, 88, 99],
        selected: [66, 88, 99]
    },
    {
        id: 789,
        className: 'Group 1',
        isActive: 0,
        students: [77, 22],
        selected: []
    }
];

App.Students = DS.Model.extend({
    first: DS.attr('string'),
    last: DS.attr('string'),
    classes: DS.hasMany('ClassGroup')
});

App.Students.FIXTURES = [
    {
        id: 11,
        first: 'Student',
        last: 'One',
        classes: [123]
    },
    {
        id: 22,
        first: 'Student',
        last: 'Two',
        classes: [123, 789]
    },
    {
        id: 33,
        first: 'Student',
        last: 'Three',
        classes: [123]
    },
    {
        id: 44,
        first: 'Student',
        last: 'Four',
        classes: [123]
    },
    {
        id: 55,
        first: 'Student',
        last: 'Five',
        classes: [123]
    },
    {
        id: 66,
        first: 'Student',
        last: 'Six',
        classes: [456]
    },
    {
        id: 77,
        first: 'Student',
        last: 'Seven',
        classes: [456, 789]
    },
    {
        id: 88,
        first: 'Student',
        last: 'Eight',
        classes: [456]
    },
    {
        id: 99,
        first: 'Student',
        last: 'Nine',
        classes: [456]
    }
];

Мой контроллер выглядит так:

var IndexController = Ember.ArrayController.extend({
    actions: {
        isActiveTog: function(id){
            console.log(this);
            console.log(this.store.get('model'));

            var getter = this.get('classgroup');
            console.log(getter);
        }
    },
    classCount: function(){
        return this.get('length');
    }.property('@each')
});

export default IndexController;

Это наш роутер:

import Students from "appkit/models/students";
import ClassGroup from "appkit/models/classgroup";

export default Ember.Route.extend({
    model: function() {
        return this.store.find('classgroup');
    },
    setupController: function(controller, model){
        this._super(controller, model);

        controller.set('students', this.store.find('students'));
        controller.set('classgroup', this.store.find('classgroup'));
    }
});

Здесь each Блок в нашем шаблоне руля (я удалил остальное, потому что он слишком громоздкий):

{{#each classgroup}}
            <li id="c_{{unbound this.id}}" class="classMenu manageMenuWidth">
                <span class="classSA" id="c_{{unbound this.id}}_sas"><input type="checkbox" name="c_{{unbound this.id}}_chk" id="c_{{unbound this.id}}_chk" /></span>
                <span id="c_{{unbound this.id}}_nam" {{bind-attr class=":classLayout isActive:activeSelection"}} {{action "isActiveTog" this.id on="click"}}>{{unbound this.className}}</span>
                {{#view 'toggleclass'}}<span class="togControl" id="c_{{unbound this.id}}_tog"></span>{{/view}}
            </li>
            <ul id="c_{{unbound this.id}}_sts" class="students manageMenuWidth">
                {{#each students}}
                    <li class="student" id="s_{{unbound this.id}}_c_{{unbound classgroup.id}}">
                        <span class="studentChk" id="s_{{unbound students.id}}_c_{{unbound classgroup.id}}_img">{{unbound this.last}}, {{unbound this.first}}</span>
                        <input type="checkbox" name="s_{{unbound students.id}}_c_{{unbound classgroup.id}}_chk" id="s_{{unbound students.id}}_c_{{unbound classgroup.id}}_chk" />
                    </li>
                {{/each}}

Я включил как можно больше нашего кода, потому что я все еще очень плохо знаком с Ember, и я хочу убедиться, что у вас есть вся информация, необходимая для ответа на этот вопрос, даже если это означает, что вы будете давать слишком много.

Чтобы вы не копали слишком много, вот еще немного информации. В шаблоне руля есть строка {{action "isActiveTog" this.id on="click"}} внутри нашего диапазона.

Это вызовет функцию в нашем контроллере, isActiveTog, который мы хотели бы использовать для переключения значения isActive в модели для любой записи "группа классов" была нажата в each петля.

Например, пользователь нажимает на "Класс 1", который вызывает действие isActiveTog, передав ID = 123. Я хочу, чтобы мои действия в контроллере переключали значение ClassGroup[123][isActive] с 0 на 1 или наоборот.

Я могу сказать, что мой контроллер вызывается правильно, потому что я могу поставить {{classCount}} в моем шаблоне и увидеть "3" в выходной. Таким образом, проблема в том, что я не могу найти способ переключения значения в контроллере.

Как я могу использовать this.store.find() искать classgroup строка с идентификатором, равным тому, что было передано действию, а затем доступ к значению isActive этой записи класса. Тогда мне нужно использовать this.store.set() написать обратно в модель.

2 ответа

Решение

Похоже, вы пришли из jQuery из-за того, как вы пытаетесь внедрить id ваших записей ClassGroup в DOM через шаблон (конечно же, в этом нет ничего плохого, поскольку именно этим я и занимался, когда впервые начал работать с Ember из jQuery). Если вы замечаете, что делаете это, вы, вероятно, делаете что-то не угасающее. Как правило, доступ к элементам DOM следует осуществлять только по ID, если вам необходимо интегрировать какую-либо стороннюю библиотеку jQuery.

Хорошо, теперь вы знаете, на что обращать внимание, как мы должны выполнить то, что вы хотите, способом Эмбер?

Вероятно, есть несколько способов сделать это, но для меня хорошо создать еще один контроллер для каждой отдельной ClassGroup, который расширяет ObjectController вместо ArrayController. Так что вы бы

ClassGroupsController (ArrayController) -> ClassGroupController (ObjectController)

Обратите внимание, что контроллер массива является множественным. Это позволяет вам управлять состоянием каждой отдельной записи ClassGroup, поскольку каждая запись ClassGroup теперь имеет свой собственный контроллер и свое собственное представление.

Итак, сначала создайте контроллер массива, который управляет коллекцией ClassGroups:

App.ClassGroupsController = Ember.ArrayController.extend({

});

ClassGroupController (Object) должен иметь представление, которое прослушивает события щелчка. Когда мы получаем событие click, мы запускаем действие на контроллере (ClassGroupController) с именем selected,

App.ClassGroupView = Ember.View.extend({
    templateName: 'classGroup',
    /*
    By specifying the tagName for this view we are telling ember
    we want to wrap the view in a <tr> element.  This is because
    each classGroup is going to be a row in our table.  By default
    each view is wrapped in a <div>
    */    
    tagName: 'tr',
    /*
    This is the click handler that is called whenever the user
    clicks on this view (in this case one of our <tr> elements
    that is displaying our ClassGroup Model for us.  The event
    parameter is the jQuery event object.
    */
    click: function(event){
        /*
        We want to forward this event to the controller where
        we can do some logic based on the fact that it was clicked.        
        */
        this.get('controller').send('selected');   
    }
});

Теперь мы создаем наш ObjectController для ClassGroup, который ждет и слушает selected действие, которое отправляется из ClassGroupView когда пользователь нажимает на этого человека ClassGroup,

App.ClassGroupController = Ember.ObjectController.extend({    
    actions:{
        /*
        This is the action we received from our view which was
        based on the user clicking on one of the <li> elements
        representing a ClassGroup Model
        */
        selected: function(){            
            console.info("You selected: " + this.get('className'));    
            /*
            Now we can easily toggle the isActive state of our model
            */
            this.toggleProperty('isActive');
            console.info("My isActive state is now: " + this.get('isActive'));
        }
    }
});

Теперь нам нужно подключить это в нашем шаблоне.

{{#each itemController="classGroup"}}
    {{view App.ClassGroupView}}  
{{/each}}

Обратите внимание, как я указываю, что я хочу использовать classGroup в качестве itemController для моего ArrayController. Здесь я указываю это прямо в шаблоне. Вы также можете указать его в самом ArrayController, используя itemController имущество. Так, например:

App.ClassGroupsController = Ember.ArrayController.extend({
    itemController: 'classGroup'   
});

Вот рабочий JSFIddle, использующий ваши приборы для демонстрации всей концепции:

http://jsfiddle.net/NQKvy/872/

Чтобы прямо ответить на ваш вопрос

Вы можете найти запись по идентификатору и изменить ее, используя

this.store.find('classgroup', id).then(function (classgroup) {
    classgroup.toggleProperty('isActive');
});

Однако в вашем случае вам это не нужно, поскольку вы можете просто передать запись

так что на ваш взгляд использовать

{{action "isActiveTog" this on="click"}}

вместо this.id а затем просто напрямую изменить его в контроллере

isActiveTog: function(classgroup){
    classgroup.toggleProperty('isActive');
    // classgroup.save();
}
Другие вопросы по тегам