Нокаут, как установить значение в дочернем наблюдаемом

Я пытаюсь реализовать встроенное редактирование с использованием шаблонов. В моей модели просмотра у меня есть метод: self.changeMode. Я запускаю это из события нажатия кнопки (внутри шаблона). Параметр данных, который передается функции changeMode, содержит ожидаемые данные, но мне нужно изменить наблюдаемое. Как мне это сделать?

var MyViewModel = function (data) {
    var self = this;

    self.managingAgentId = ko.observable(data.managingAgentId);
    self.companyName = ko.observable(data.companyName);
    self.companyNumber = ko.observable(data.companyNumber);
    self.isActive = ko.observable(data.isActive);
    self.agents = ko.observableArray(data.agents);
    
    // Change to Edit or Display mode
    self.changeMode = function (data,event) {
        event.preventDefault();
        // => need to change mode here!
    };
}


$(function () {

        $.ajax({
            type: "GET",
            url: ma.Urls.LoadManagingAgent
        }).done(function (result) {
            $.each(result.agents, function (index, element) {
                element.mode = "display";
            });
            
            ko.applyBindings(new MyViewModel(result));
        }).error(function (response) {
            addMessage(response);
        });
    });
<script type="text/html" id="display">
    <td data-bind="text: managingAgentMemberId"></td>
    <td data-bind="text: applicationUser.userName"></td>
    <td data-bind="text: applicationUser.email"></td>
    <td data-bind="text: applicationUser.emailConfirmed"></td>
    <td data-bind="text: isActive"></td>
    <td>
        <button class="btn btn-success btn-sm" data-bind="click:$root.changeMode">
            <i class="fa fa-edit"></i>
            Edit
        </button>
    </td>
</script>

<script type="text/html" id="edit">
    <td data-bind="text: managingAgentMemberId"></td>
    <td data-bind="text: applicationUser.userName"></td>
    <td data-bind="text: applicationUser.email"></td>
    <td data-bind="text: applicationUser.emailConfirmed"></td>
    <td><input type="checkbox" data-bind="checked: isActive" /> </td>
    <td>
        <button class="btn btn-success btn-sm kout-update">
            <i class="fa fa-save"></i>
            Update
        </button>
        <button class="btn btn-danger btn-sm kout-cancel">
            <i class="fa fa-stop"></i>
            Cancel
        </button>
    </td>
</script>

введите здесь описание изображения


person Greg    schedule 26.03.2016    source источник
comment
не уверен, что понимаю, что вы имеете в виду. applyBindings вызывается для возвращаемого ajax?   -  person Greg    schedule 26.03.2016
comment
Я удалил комментарий примерно через 5 секунд после его написания, кажется, есть некоторая задержка, пока вы не увидите удаление.   -  person Tomalak    schedule 26.03.2016
comment
На что вы хотите изменить mode? Кроме того, mode даже не является наблюдаемым в вашей модели просмотра.   -  person Tomalak    schedule 26.03.2016
comment
У меня есть 2 значения, передаваемые в шаблон - редактировать и отображать. Итак, когда нажата кнопка (в строке агента), я хочу изменить отображаемое значение для редактирования, которое, надеюсь, изменит строку для использования шаблона редактирования. Существует второй шаблон под названием edit   -  person Greg    schedule 26.03.2016
comment
ОК, значит, установка observableArray([data.agents]) не использует свойство режима, установленное после вызова Ajax? Итак, как я могу добавить это как новое свойство для каждого агента?   -  person Greg    schedule 26.03.2016
comment
Нет, наблюдаемый массив не волшебным образом превращает все в графе объектов в наблюдаемый рекурсивно (это то, что сделал бы плагин сопоставления, если бы вы хотели его использовать, но я не вижу, чтобы вы его использовали). Мне нужно увидеть вашу модель данных, чтобы настроить работающий пример.   -  person Tomalak    schedule 26.03.2016
comment
Давайте продолжим обсуждение в чате.   -  person Greg    schedule 26.03.2016


Ответы (1)


Каноническое решение:

function Child(data) {
    var self = this;
    self.name = ko.observable();
    self.mode = ko.observable('display');
    ko.mapping.fromJS(data, Child.mapping, self);
}
Child.prototype.toggleMode = function () {
    this.mode(this.mode() === 'display' ? 'edit' : 'display');
};
Child.mapping = {
    // mapping rules, if applicable
};
function Parent(data) {
    var self = this;
    self.children = ko.observableArray();
    ko.mapping.fromJS(data, Parent.mapping, self);
}
Parent.mapping = {
    children: {
        create: function (options) {
            return new Child(options.data);
        }
    }
};

ko.applyBindings(new Parent({
    children: [
        {name: 'Child 1'}, {name: 'Child 2'}, {name: 'Child 3'}
    ]
}));
td:first-child {
    width: 200px;
}
button {
    width: 6em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<table>
    <tbody data-bind="foreach: children">
        <tr data-bind="template: mode"></tr>
    </tbody>
</table>

<script type="text/html" id="display">
    <td data-bind="text: name"></td>
    <td>
        <button data-bind="click: toggleMode">Edit</button>
    </td>
</script>

<script type="text/html" id="edit">
    <td><input data-bind="value: name"></td>
    <td>
        <button data-bind="click: toggleMode">Save</button>
    </td>
</script>

person Tomalak    schedule 26.03.2016
comment
Принять, но не проголосовать? Не то чтобы я зависел от этого, но мне интересно, в чем причина этого. - person Tomalak; 26.03.2016
comment
просто пытаюсь подключить вашу логику к моему сценарию - голосую сейчас - person Greg; 26.03.2016
comment
Вы меня неправильно поняли, я просил не столько плюсов, сколько объяснений. Я видел это не раз и, предполагая, что средства голосования были полезны, я не могу понять сообщение, которое должно передаваться без одобрения. - person Tomalak; 26.03.2016
comment
Насколько я понимаю, человек с вопросом принимает ответ, а другие, которые читают пост и находят его полезным, голосуют за - ?? - person Greg; 26.03.2016
comment
Ясно, это могло бы объяснить это. Хотя я не уверен, что согласен с этим. Я вижу это так: если что-то полезное, проголосуйте за это. Если что-то не очень полезно, не голосуйте за это. Если что-то откровенно плохое, проголосуйте за это. Если что-то не очень полезно или откровенно плохо, не нажимайте «Принять». (Если вы обнаружите, что пишете «Спасибо» в комментариях, проголосуйте «за». Голоса «за» — это благодарность этому сайту.) - person Tomalak; 26.03.2016
comment
Я применил вашу методологию к своему коду, и большая ее часть работает. Единственная проблема заключается в том, что шаблон не меняет местами при нажатии кнопки, но ошибок не возникает. Какие-либо предложения? - person Greg; 26.03.2016
comment
Я был АФК. Что это было? - person Tomalak; 26.03.2016
comment
Классическая ошибка нуба с нокаутом - я не поставил скобки после mode =› this.mode(this.mode === 'display' ? 'edit' : 'display'); это никогда не сработает - person Greg; 26.03.2016
comment
Ха-ха! :] Думаю, учусь через боль. С положительной стороны, вы больше не совершите эту ошибку, я почти уверен. - person Tomalak; 26.03.2016