Добавление свойств в модель представления, созданных с помощью плагина отображения Jockout JS
Я работаю над примером плагина сопоставления на веб-сайте Knockoutjs.
Это пример данных.
Плагин для новичков JS Mapping
var data = {
name: 'Scott',
children: [
{ id : 1, name : 'Alice' }
]
}
В этом примере показано, как переопределить отображение для одного из дочерних элементов, но как изменить сопоставление для базового объекта.
Если, например, я хотел добавить свойство "FavouriteChild" Скотту, как бы я это сделал?
Я предполагаю, что мне нужно использовать функцию create в базовом сопоставлении, но я не могу найти пример синтаксиса где-нибудь.
var myChildModel = function(data) {
ko.mapping.fromJS(data, {}, this);
this.nameLength = ko.computed(function() {
return this.name().length;
}, this);
}
var mapping = {
'children': {
create: function(options) {
return new myChildModel(options.data);
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
EDIT: Из принятого ниже ответа я нашел, что это работает
<span data-bind='text: AdditionalProperty'>
Код нокаута
var mapping = {
create: function (options) {
//customize at the root level.
var innerModel = ko.mapping.fromJS(options.data);
innerModel.AdditionalProperty = 'Hello World';
return innerModel;
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
//use this as our model bindings
ko.applyBindings(viewModel);
Ответы
Ответ 1
Вам нужно использовать метод create
для самого объекта сопоставления, например:
var mapping = {
//customize at the root level.
create: function(options) {
//first map the vm like normal
var vm = ko.mapping.fromJS(options.data);
//now manipulate the returned vm in any way that you like
vm.someProperty = "test";
vm.someComputed = ko.computed(function() {
return vm.first() + " " + vm.last();
});
//return our vm that has been mapped and tweaked
return vm;
}
};
Ответ 2
Вот продолжение этого ответа на основе решения RP Niemeyer
Этот ответ здесь основан на решении выше и на его блоге - Спасибо за это! Я думал, что должен добавить некоторые детали, потому что он обращается, когда массив не является объектом первого уровня.
var data = {
person: {
children: [{ id: 1, firstName: 'Scot', lastName: 'Weise'}]
}
};
var mapping = {
'children': {
create: function(options) {
return (new (function() {
// setup the computed binding for some reason I had
// to use ko.dependentObservable instead of ko.computed
// or errors showed up.
this.fullName = ko.dependentObservable(function() {
return this.firstName() + ' ' + this.lastName();
}, this);
ko.mapping.fromJS(options.data, { }, this);
})(/* call the ctor here */));
}
}
};
// Create view model and map the data object to the model.
var viewModel = ko.mapping.fromJS(data, {});
// update the viewModel with the mapping object that contains
// some a computed property(s)
viewModel.person = ko.mapping.fromJS(viewModel.person, mapping);
ko.applyBindings(viewModel);
Обратите внимание, что человек является объектом первого уровня, а дочерние объекты являются дополнительным свойством этого человека. Строка viewModel.person = ko.mapping.fromJS(viewModel.person, mapping) сначала не была интуитивной.
И вот небольшая вариация
Объект person является наблюдаемым, который добавляется или обновляется после того, как он был первоначально создан из данных сервера json.
var viewModel = {};
$(document).ready(function () {
var person = getPerson();
// selected person is added to the viewModel
viewModel.selectedPerson = ko.observable(person);
ko.applyBindings(viewModel);
});
function getPerson() {
// you would probably pass this into the function as a parameter.
var person =
{
name: 'jim',
children: [{ id: 1, firstName: 'jane', lastName: 'bob'}]
};
var mapping = {
'children': {
create: function (options) {
return (new (function () {
// setup the computed binding
this.fullName = ko.dependentObservable(function () {
return this.firstName() + ' ' + this.lastName();
}, this);
ko.mapping.fromJS(options.data, {}, this);
})(/* call the ctor here */));
}
}
};
var result = ko.mapping.fromJS(person, mapping);
return result;
}
Некоторый код привязки в html
В конечном счете вам нужно будет использовать его в какой-то момент следующим образом:
<div data-bind="foreach:viewModel.selectedPerson().children">
<span data-bind="text:fullName"></span>
</div>
Спасибо за вашу помощь! Я не мог бы сделать это так далеко, не имея вашего сообщения в блоге.
Ответ 3
Обратите внимание, что для определения дополнительных вычисленных наблюдаемых данных для ребенка вам нужно будет передать другой набор параметров отображения
var mapping = {
create: function(options) {
//customize at the root level.
var mapping2 = {
'children': {
create: function(options) {
//customize children also
}
}
}
//call ko.mapping.fromJS on the options.data as well with further customization
ko.mapping.fromJS(options.data, mapping2, this);
}
};
Ответ 4
Другой пример, основанный на примерах, представленных Джейсоном и Р. П. Нимейером.
data
- это то, что мы получаем после ajax-запроса, на котором мы добавляем два вложенных наблюдаемых (viewModel.weekly.selectedWeek
и viewModel.monthly.selectedMonth
):
var data = {
"date": "2017-03-28",
"weekly": {
"weeks": [
{
"id": "201701",
"label": "Week 1"
},
{
"id": "201702",
"label": "Week 2"
}
]
},
"monthly": {
"months": [
{
"id": "201701",
"label": "01/2017"
},
{
"id": "201702",
"label": "02/2017"
}
]
}
}
var viewModelMapping = {
create: function (options) {
return (new (function () {
// viewModel root level
var mapping2 = {
'weekly': {
create: function (options) {
// viewModel.weekly
return new function () {
var model = ko.mapping.fromJS(options.data, {}, this);
model.selectedWeek = ko.observable();
return model;
};
}
},
'monthly': {
create: function (options) {
// viewModel.monthly
return new function () {
var model = ko.mapping.fromJS(options.data, {}, this);
model.selectedMonth = ko.observable();
return model;
};
}
}
};
ko.mapping.fromJS(options.data, mapping2, this);
})());
}
};
var viewModel = ko.mapping.fromJS(data, viewModelMapping);
ko.applyBindings(viewModel);