Нокаутирующие:Добавление наблюдаемых свойств и функций к объектам в сгенерированном отображением observableArray
-
28-10-2019 - |
Вопрос
Я новичок в Нокаутирующие, и я застрял, пытаясь добавить дополнительные свойства и методы к сгенерированным объектам в ko.observableArray()
как создано с помощью mapping
плагин.
Вот чем я занимаюсь:
- У меня есть массив JSON из
Users
- Я создал
ko.observableArray()
с помощью картографического плагина - У меня есть шаблон, который создает строку таблицы для каждого
User
, пока все хорошо :o)
Вот что я пытаюсь сделать:
Каждый User
обладает свойством, называемым 'IsActive'
- Я бы хотел data-bind
событие щелчка по методу в каждом User
объект, который переключает это 'IsActive'
собственность.
Этот вопрос выглядел многообещающим, но мне кажется ненужным дублированием необходимость объявлять всю модель представления в JS (если только я не должен это делать именно так!) - возможно ли просто расширить сгенерированный объект?
Я больше размышлял в этом направлении, где есть способ объявить дополнительные свойства или методы и заставить их расширить mapping
сгенерированные объекты, но эта статья посвящена отдельным объектам, а не расширению объектов в сгенерированном массиве.
Вот код: http://jsfiddle.net/yZkSf/2/ (пока не работает в JS fiddle - но я продолжу играть с ним и обновлю эту ссылку, когда она заработает).
Спасибо вам за вашу помощь
Решение
Есть несколько вариантов, которые вы могли бы рассмотреть.
- Один из них заключается в использовании create
обратный звонок чтобы контролировать, как создаются ваши "пользовательские" объекты.Вы можете либо самостоятельно определить наблюдаемые объекты и добавить дополнительную функциональность, либо вызвать плагин сопоставления для отдельного пользовательского объекта, а затем добавить дополнительную функциональность.
Было бы что-то вроде: http://jsfiddle.net/rniemeyer/fkVaK/
-В противном случае вы можете поместить функцию "toggle" в свою ViewModel, а затем передать ей объект "user".
Хороший способ с версией 1.3 - использовать ko.dataFor
наряду с чем-то вроде функциональности делегирования событий live/delegate/on в jQuery.Было бы похоже: 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/
РЕДАКТИРОВАТЬ:начиная с версии 2.0, текущие данные автоматически передаются обработчику при использовании привязок click/event, так что вы можете просто сделать:
<a href="#" data-bind="click: $root.toggleIsActive"><span data-bind="text: IsActive"></span></a>
Другие советы
Это то, к чему я пришел, используя ваши ответы и ответы Райана...кажется, это работает.Пожалуйста, оставьте отзыв, так как я новичок в 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');
});
дом:
<!-- ko foreach: users -->
<a href="#" data-bind="click: toggleIsActive"><span data-bind="text: IsActive"></span></a>
<!-- /ko -->
Я нашел способ сделать это, но это означает перебор сгенерированных объектов в массиве после того, как они были созданы..Я бы предпочел способ достижения того же результата без дополнительного цикла..
РЕДАКТИРОВАТЬ: Как предполагает Р.П. Нимейер в своем ответе! ;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);