Измените объект js на модель представления js с вложенными наблюдаемыми массивами

Я получаю определенный JSON с сервера и хочу иметь возможность добавлять / редактировать / удалять элементы во вложенных массивах (списки вариантов, варианты и столбцы), но я не могу понять, как это сделать с knockout.js.

Я знаю, что мне нужно изменить свойства в этом объекте JSON на наблюдаемые, и я делаю это с помощью подключаемого модуля сопоставления, как показано в разделе «Привязка», и все значения были привязаны правильно, но если я изменю значение в поле ввода, модель / view не обновляется автоматически.

Почему? Я что-то упускаю?

Поддерживаются ли вложенные массивы нативными в knockout.js без необходимости писать собственный код? Как я могу получить из этого JSON полностью работающую модель представления knockout.js?

Я использую текущие доступные версии (нокаут: v2.1.0, плагин сопоставления: v2.3.2).

JSON

{
    "VariantList": [
        {
            "ColumnCount": 1,
            "Variants": [
                {
                    "Title": "One column 100%",
                    "Columns": [
                        "100 %"
                    ]
                }
            ]
        },
        {
            "ColumnCount": 2,
            "Variants": [
                {
                    "Title": "Two columns 50%/50%",
                    "Columns": [
                        "50%",
                        "50%"
                    ]
                },
                {
                    "Title": "Two columns 75%/25%",
                    "Columns": [
                        "75%",
                        "25%"
                    ]
                }
            ]
        }
    ]
}

HTML

<div data-bind="foreach: VariantList">
    <h2 data-bind="text: ColumnCount"></h2>
    <div data-bind="foreach: Variants">
        <h3 data-bind="text: Title"></h3>
        <table style="width:500px">
            <tr>
                <!-- ko foreach: Columns -->
                <th><input data-bind="value: $data"/></th>
                <!-- /ko -->
            </tr>
            <tr>
                <!-- ko foreach: Columns -->
                <td data-bind="style: {width:$data}, text:$data"></td>
                <!-- /ko -->
            </tr>
        </table>
   </div>
</div>

Привязка

var viewModel;
$(function(){
   viewModel = ko.mapping.fromJS(myJson);
   ko.applyBindings(viewModel);
});

person Marc    schedule 03.09.2012    source источник


Ответы (1)


Проблема в том, что подключаемый модуль сопоставления по умолчанию не превращает примитивные значения в массиве в наблюдаемые. Даже если это так, к тому времени, когда вы привяжете $data к своему вводу, у вас будет его развернутое значение, а не наблюдаемое.

Самый простой способ выполнить эту работу - структурировать данные примерно так:

var data = {
    "VariantList": [
        {
            "ColumnCount": 1,
            "Variants": [
                {
                    "Title": "One column 100%",
                    "Columns": [
                        { value: "100 %" }
                    ]
                }
            ]
        },
        {
            "ColumnCount": 2,
            "Variants": [
                {
                    "Title": "Two columns 50%/50%",
                    "Columns": [
                        { value: "50%" },
                        { value: "50%" }
                    ]
                },
                {
                    "Title": "Two columns 75%/25%",
                    "Columns": [
                        { value: "75%" },
                        { value: "25%" }
                    ]
                }
            ]
        }
    ]
};

Затем вы должны выполнить привязку к value в своем цикле на Columns. Вот пример: http://jsfiddle.net/rniemeyer/MCnMX/

Если вы не можете извлечь свои данные в эту структуру, вы можете рассмотреть возможность использования параметров сопоставления, чтобы превратить их в такую ​​структуру. Вот пример: http://jsfiddle.net/rniemeyer/sH3r2/

var mappingOptions = {
    Columns: {
        create: function(options) {
            return { value: ko.observable(options.data) };  
        }
    }        
};

var viewModel = ko.mapping.fromJS(data, mappingOptions);

Если вам нужно отправить свой JSON обратно на сервер в том же формате, в котором вы его получили, есть несколько вариантов. Мне нравится делать это вот так: http://www.knockmeout.net/2011/04/controlling-how-object-is-converted-to.html. Вот образец ваших данных: http://jsfiddle.net/rniemeyer/Eed2R/

var Value = function(val) {
    this.value = ko.observable(val);  
};

Value.prototype.toJSON = function() {
    return ko.utils.unwrapObservable(this.value);  
};

var mappingOptions = {
    Columns: {
        create: function(options) {
            return new Value(options.data);
        }
    }        
};

var viewModel = ko.mapping.fromJS(data, mappingOptions);
person RP Niemeyer    schedule 03.09.2012
comment
Большое спасибо за отличный ответ! Я думаю, что изменение столбца на объект - правильное решение, поэтому я изменил свой проект таким образом, и теперь он отлично работает! Я все еще борюсь с использованием классов и инициализацией json-объектом, но я думаю, что опубликую еще один вопрос, если я не смогу сделать это самостоятельно. Нокаут - это здорово! Мне просто нужно потратить немного больше времени, чтобы научиться этому. :) - person Marc; 06.09.2012