KnockoutJS: добавление наблюдаемых свойств и функций к объектам в созданном сопоставлении ObservableArray
Я новичок в KnockoutJS, и я застреваю, пытаясь добавить дополнительные свойства и методы к сгенерированным объектам в ko.observableArray()
, созданный плагином mapping
.
Здесь, где я до:
- У меня есть массив JSON
Users
- Я создал
ko.observableArray()
с плагином отображения
- У меня есть шаблон, который создает таблицу строк для каждого
User
, пока что так хорошо: o)
Вот что я пытаюсь сделать:
Каждый User
имеет свойство, называемое 'IsActive'
- я хотел бы data-bind
событие click для метода для каждого объекта User
, который переключает это свойство 'IsActive'
.
Этот вопрос выглядел многообещающим, но мне кажется, что ненужное дублирование мне нужно объявить всю модель View в JS (если только это не так, как я должен это делать!) - возможно ли просто продлить сгенерированный объект?
Я думал больше об этих строках, где есть способ объявить дополнительные свойства или методы и расширить их mapping
но эта статья посвящена отдельным объектам, а не расширению объектов в сгенерированном массиве.
Здесь код: http://jsfiddle.net/yZkSf/2/ (пока не работает в скрипте JS, но я буду продолжать играть с ним и обновите эту ссылку, когда я получу ее работу).
Спасибо за помощь
Ответы
Ответ 1
Есть несколько вариантов, которые вы могли бы рассмотреть.
-Один должен использовать create
обратный вызов, чтобы управлять созданием ваших "пользовательских" объектов. Вы можете либо определить наблюдаемые самостоятельно, либо добавить дополнительные функции, либо вызвать плагин сопоставления для отдельного пользовательского объекта, а затем добавить дополнительные функции.
Будет что-то вроде: http://jsfiddle.net/rniemeyer/fkVaK/
- В противном случае вы можете поместить функцию "toggle" на свой viewModel, а затем передать ему "пользовательский" объект.
Хорошим способом с 1.3 является использование ko.dataFor
вместе с чем-то вроде функции jQuery live/delegate/on делегирование событий. Было бы так: http://jsfiddle.net/rniemeyer/FkjNr/
//unobtrusive event handler
$(".toggle").live("click", function() {
var user = ko.dataFor(this);
if (user) {
viewModel.toggleIsActive(user);
}
});
Если вы не хотите использовать делегирование событий, вы можете передать элемент напрямую с помощью анонимной функции, например: http://jsfiddle.net/rniemeyer/GpQtN/
EDIT: начиная с версии 2.0 текущие данные автоматически передаются обработчику при использовании привязок/событий, поэтому вы можете просто:
<a href="#" data-bind="click: $root.toggleIsActive"><span data-bind="text: IsActive"></span></a>
Ответ 2
Это то, что я придумал, используя как ваши, так и ответы Райана... кажется, работает. Пожалуйста, оставьте отзыв, так как я новичок в Knockout и любопытно, если это хороший подход.
JS:
$(function() {
$.get("users/getUsers", function(r){
var vm = ko.mapping.fromJS(r, {
users: {
create: function(user){
var methods = {
toggleIsActive: function(u){u.IsActive(!u.IsActive());},
foo: function(u){console.log(u);},
bar: function(u){/*whatever*/},
}
return $.extend(ko.mapping.fromJS(user.data), methods);
}
}
});
ko.applyBindings(vm);
}, 'json');
});
DOM:
<!-- ko foreach: users -->
<a href="#" data-bind="click: toggleIsActive"><span data-bind="text: IsActive"></span></a>
<!-- /ko -->
Ответ 3
Я нашел способ сделать это, но это означает, что вы можете сгенерировать объекты в массиве после их создания. Я бы предпочел, чтобы способ достичь того же результата без дополнительного цикла.
EDIT: Как утверждает РП Нимейер в своем ответе!; o)
В любом случае одним из способов добавления свойств к существующему объекту является использование jQuery extend() для объединения объектов.
Сначала объявите дополнительные свойства и функции в новом объекте:
var userModel = {
toggleIsActive: function() {
console.log('toggleIsActive called: before: ' + this.IsActive());
this.IsActive(!this.IsActive());
// todo: save!
console.log('toggleIsActive called: after: ' + this.IsActive());
}
}
Затем, после вызова ko.mapping.fromJS()
, , но перед вызовом ko.applyBindings()
, пропустите объекты в сгенерированном массиве и продолжите их:
viewModel.users = ko.mapping.fromJSON(/* get JSON */);
for (var i = 0; i < viewModel.users().length; i++) {
$.extend(viewModel.users()[i], userModel);
}
ko.applyBindings(viewModel);