bem / bem-mvc

Yet another MVC for i-bem
29 stars 26 forks source link

isEqual() #159

Closed mightyaleksey closed 8 years ago

mightyaleksey commented 8 years ago

Столкнулся с необычным поведением, но потом почитал код и понял что оно предусмотрено :) Вообщем хочу поговорить про реализацию данной функции: https://github.com/bem/bem-mvc/blob/master/common.blocks/i-model/i-model.js#L502-L515

Мой кейс такой. Я использую коллекцию моделек (models-list) и когда вызываю метод set, в который передаю новый список моделек, то получается, что если новые модельки совпадают по значению, а также совпадает их количество, то данные в коллекции не обновляются.

А смущает тем, что у меня разные биндинги навешаны на разные дочерние модельки и когда я ожидаю, что коллекция обновиться (а она не обновляется) у меня возникает небольшой колапс: интерфейс перестает реагировать.

Собственно вопрос такой, можем ли мы доработать models-list, чтобы он сравнивал модели по id или мне лучше пересмотреть мою реализацию интерфейса?

dosyara commented 8 years ago

Извини, что сразу не ответил, пропустил ишью. Мне кажется это баг и его нужно чинить. Коллекция должна перезаписаться новыми моделями, даже если у них совпадают данные. Будем чинить. Но будет лучше, если ты приложишь пример с проблемой, иначе рискуем разойтись в понимании проблемы.

mightyaleksey commented 8 years ago

Хорошо, спасибо. Над примером подумаю, у меня там довольно своеобразная реализация SPA (на одной странице :)) и не знаю в каком виде описать его. Попробую pr прислать. Думаю, чуть проще будет.

dosyara commented 8 years ago

Правильно я понимаю, что в твоем случае должен исполняться такой тест:

BEM.MODEL.decl('item', { f: 'string' });

BEM.MODEL.decl('model', {
    list: {
        type: 'models-list',
        modelName: 'item'
    }
});

var model = BEM.MODEL.create('model', {
    list: [{ f: 1 }]
});

var onChangeSpy = sinon.spy();

model.on('list', 'change', onChangeSpy);

var newItem = BEM.MODEL.create('item', { f: 1 });

model.set('list', [newItem]);

expect(onChangeSpy.called).to.equal(true);

Сейчас вызов onChangeSpy не происходит, а должен.

dosyara commented 8 years ago

Посмотри коммит https://github.com/bem/bem-mvc/commit/b52cc87e38bcf96d22caa67e132a4740f1e83759 пожалуйста. Я попробовал исправить проблему. Он в ветку server-side-models, но вроде там должно быть понятно.

mightyaleksey commented 8 years ago

Возвращаясь к той истории с интерфейсом. У меня есть небольшой фрагмент страницы, который содержит несколько чекбоксов. Каждый связан с соответствующей моделькой, которые хранятся в коллекции. По состоянию чекбоксов в колекции вычисляется состояние командной строки (еще один элемент интерфейса).

В интерфейсе есть возможность переключить набор настроек и как результат этот фрагмент страницы меняется на другой, а с ним и меняется набор чекбоксов, но командная строка остается. Таких наборов у меня несколько и все они отрисованы в html - я только меняю набор моделек в коллекции по необходимости. По сути, я дергаю метод .set() у колекции и отдают туда набор проинициализированных моделек.

Если привязываться к коду, то получилось бы как то так:

BEM.MODEL.decl('item', { f: 'string' });

BEM.MODEL.decl('model', {
    list: {
        type: 'models-list',
        modelName: 'item'
    }
});

var model = BEM.MODEL.create('model', {
    list: []
});

var childModel1 = BEM.MODEL.create('item', {f: 'STATE'});
var childModel2 = BEM.MODEL.create('item', {f: 'STATE'});

model.set('list', [childModel1]);

var onChangeSpy = sinon.spy();

model.on('list', 'change', onChangeSpy);

model.set('list', [childModel2]);

expect(onChangeSpy.called).to.equal(true);

Я чуть-чуть доработал твой пример для наглядности.

Я решил эту проблему довольно просто путем предварительного сброса содержимого коллекции.

mightyaleksey commented 8 years ago

Сейчас опробую твой коммит :)

mightyaleksey commented 8 years ago

@dosyara работает, спасибо!