Мне почти каждый день приходится писать различные виджеты для манипуляции с данными — динамические таблицы, списки из красиво оформленных однотипных элементов и т.п. Конечно же, в этих элементах были кнопки или поля ввода, которые влияли на данные, связанные с этим элементом.
Для небольших виджетов я нашел оптимальным отделять этап создания представления и подключения контролера.
var obj = [], i;
obj.push('<div class="wrapper">');
for (i = 0; i < model.lenght; i++) {
obj.push('<div class="item">');
obj.push('<h1>', model[i].title, '</h1>');
obj.push('<div class="input"><input type="text" value="', model[i].value, '" /></div>');
obj.push('</div>');
}
obj.push('</div>');
$(root).html(obj.join(''));
$('div.input input', root).change(function () {
// нужно сохранить значение в модель
});
В обработчике нужно сохранить значение поля ввода в соответствующее поле модели. Но как узнать, какое поле было изменено? Некоторое время я при создании представления использовал атрибут id , по которому можно было впоследствии определить порядковый индекс в модели или перебором найти аналогичное значение у идентификационного поля элемента модели. Тут в бой вступали сложные регулярные выражения, различные проверки и т.п. Внутри я понимал, что это далеко не самый лучший способ и решил найти более эффективное решение. Оно в итоге действительности оказалось простым.
(function () {
var uidx = 1, storage = {};
/**
* Generate an id that is unique among application
* @method guid
* @param pre {String} optional guid prefix
* @return {String} the guid
*/
APP.guid = function (pre) {
var p = (pre) || 'app';
return p + '-' + uidx++;
};
/**
* Make a save point for linking DOMNodes and Objects via IDs
* @param obj {Object}
* @param pre {String} optional guid prefix
* @return {String} the guid
*/
APP.savepoint = function (obj, pre) {
var guid = APP.guid(pre);
storage[guid] = obj;
return guid;
};
/**
* Recall data for save point
* @param guid {String} id of save point
* @return {Object} stored data
*/
APP.recall = function (guid) {
return (guid in storage) ? storage[guid] : null;
};
})();
Теперь поле ввода я создаю с уникальным id.
obj.push('<div class="input"><input type="text" value="', model[i].value, '" id="', APP.savepoint(model[i]), '" /></div>');
А реализация обработчика выглядит не менее сложной.
function () {
var o = APP.recall(this.id);
o.value = this.value;
}
В jQuery есть методы для связывания уже существующих объектов с моделью. Но чтобы подключить контроллер пришлось бы делать еще один цикл по элементам, что в общем случае может быть крайне сложным.