Прослушивание изменений из атрибутов вложенной модели

У меня есть атрибут модели, который является объектом:

name : "testing",
orderCondition: {
  minOrderAmount: 20, 
  deliveryCostRequire: "MIN_ORDER_AMOUNT", 
  deliveryCostAmount: 5.55
}

Когда я использую listenTo вот так, функция render не вызывается

this.listenTo(this.model, "change:orderCondition", this.render); // NO FIRING

Но когда я использую listenTo для других атрибутов, это работает.

this.listenTo(this.model, "change:name", this.render); // FIRING

Почему listenTo не видит изменений во вложенных объектах, а видит их в простых атрибутах?


person Przemek eS    schedule 17.01.2017    source источник


Ответы (2)


Простой способ заставить атрибут вложенного объекта инициировать событие change - заменить весь объект новым. Самый простой способ с простым set:

model.set('orderCondition', _.extend({}, model.get('orderCondition'), {
    deliveryCostRequire: "TOTAL_ORDER_AMOUNT"
}));

Создание функции для установки вложенных атрибутов в модели - хороший способ инкапсулировать эту сложность.

var Model = Backbone.Model.extend({

    setDeliveryCostRequire: function(value, options) {
        // build a new object for 'orderCondition'
        var newOrderCondition = _.extend({}, this.get('orderCondition'), {
            deliveryCostRequire: value
        });
        // replace 'orderCondition' with the new object.
        this.set({ orderCondition: newOrderCondition }, options);
        // optionally trigger a custom event for it.
        this.trigger('change:deliveryCostRequire', this, value, options);
        return this;
    },
});

Это основная концепция.

Backbone.epoxy - это библиотека двустороннего связывания, которая также предлагает вычисляемые поля для моделей, которые достигают того же уровня, что и выше, но с дополнительным преимуществом полной прозрачности извне модели.

var Model = Backbone.Model.extend({
    computeds: {
        deliveryCostRequire: {
            deps: ['orderCondition'],
            get: function(orderCondition) {
                return orderCondition && orderCondition.deliveryCostRequire;
            },
            set: function(value) {
                return {
                    orderCondition: _.extend({}, this.get('orderCondition'), {
                        deliveryCostRequire: value
                    })
                };
            },
        },
        deliveryCostAmount: { /* ...other computed... */ },
    }
});

С помощью этой модели вы могли делать следующее:

model.set('deliveryCostRequire', 'TOTAL_ORDER_AMOUNT');
model.get('deliveryCostRequire');
this.listenTo(model, 'change:deliveryCostRequire', this.render);

Я также сделал простой способ всплывать в пузырьки событий вложенных моделей и коллекций.

person Emile Bergeron    schedule 17.01.2017

Просто потому, что Backbone не работает с вложенными объектами. Например, вы не можете set атрибут свойства объекта через model.set().

Ваш this.listenTo слушает только изменение всего объекта, а не его свойств.

Вы можете попробовать использовать такие библиотеки, как backbone-deep-model для поддержки вложенных объектов.

person T J    schedule 17.01.2017
comment
Я могу установить атрибут с помощью model.get вот так this.model.get("orderCondition").minOrderAmount = Some value; - person Przemek eS; 17.01.2017
comment
@ ThePrzemyslaw94 . не является установщиком магистрали. Backbone позволяет вам получить доступ только к прямым атрибутам свойств, здесь this.model.get("orderCondition") события и все остальное по умолчанию не работает ниже этого уровня. - person T J; 17.01.2017