Подтвердить что ты не робот

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, но я буду продолжать играть с ним и обновите эту ссылку, когда я получу ее работу).

Спасибо за помощь

4b9b3361

Ответ 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);