Отображение нокаута нарушает наблюдаемые массивы - PullRequest
4 голосов
/ 27 января 2012

У меня странная проблема с подключаемым модулем Knockout.

Если я заполняю наблюдаемый массив путем сопоставления, я не могу перебрать массив или получить его длину, даже если пользовательский интерфейс обновлен правильно, массив кажется пустым.

Вы можете найти работающий jsFiddle здесь: http://jsfiddle.net/VsbsC/

Это разметка HTML:

<p><input data-bind="click: load" type="button" value="Load" /></p>
<p><input data-bind="click: check" type="button" value="Check" /></p>
<table>
    <tbody data-bind="foreach: items">
        <tr>
            <td data-bind="text: name"></td>
            <td data-bind="text: value"></td>
        </tr>
    </tbody>
</table>
<p data-bind="text: total"></p>

Это код JavaScript:

var ViewModel = function () {
    var self = this;
    self.items = ko.observableArray();
    self.load = function () {
        self.items([
            { "name": "joey", "value": 1 },
            { "name": "anne", "value": 2 },
            { "name": "paul", "value": 3 },
            { "name": "mike", "value": 4 }
        ]);
    };
    self.check = function () {
        alert(self.items().length);
    };
    self.total = ko.computed(function () {
        var total = 0;
        for (var i = 0; i < self.items().length; i++) {
            total += self.items()[i].value;
        }
        return total;
    });
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);

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

Однако, если я изменю

self.items([
    { "name": "joey", "value": 1 },
    { "name": "anne", "value": 2 },
    { "name": "paul", "value": 3 },
    { "name": "mike", "value": 4 }
]);

до

self.items(ko.mapping.fromJS([
    { "name": "joey", "value": 1 },
    { "name": "anne", "value": 2 },
    { "name": "paul", "value": 3 },
    { "name": "mike", "value": 4 }
]));

пользовательский интерфейс по-прежнему отображается правильно, но итоговое значение показывает ноль, щелкнув Проверить , также возвращает ноль, а console.info -ing self.items - пустой массив.

Как это возможно? Я перечитывал учебники бесчисленное количество раз и не могу понять, что я делаю неправильно.

P.s. Мне нужно заполнить наблюдаемый массив через подключаемый модуль сопоставления, потому что на реальной странице значения поступают из запроса AJAX.

Ответы [ 3 ]

11 голосов
/ 27 января 2012

Проблема, с которой вы сталкиваетесь, основана на том факте, что подключаемый модуль создания создает observableArray, если ему присвоен массив. Итак, вы устанавливаете значение self.items observableArray равным observableArray (а не просто массив). Итак, это завернуто в дополнительное время.

Вот один из способов сделать это:

var ViewModel = function () {
    var self = this;
    self.items = ko.mapping.fromJS([]);
    self.load = function () {
        ko.mapping.fromJS([
            { "name": "joey", "value": 1 },
            { "name": "anne", "value": 2 },
            { "name": "paul", "value": 3 },
            { "name": "mike", "value": 4 }
        ], self.items);
    };
    self.check = function () {
        alert(self.items().length);
    };
    self.total = ko.computed(function () {
        var total = 0, items = self.items();
        for (var i = 0; i < items.length; i++) {
            total += items[i].value();
        }
        return total;
    });
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);

Итак, вы инициализируете исходный массив observableArray с помощью подключаемого модуля отображения, чтобы он был готов к обновлению. Затем при обновлении вы вызываете ko.mapping.fromJS с обновленными данными и сопоставленным объектом для обновления.

Другим незначительным изменением в этой точке было просто использование value() в вашей вычисляемой наблюдаемой сейчас, когда это наблюдаемая из подключаемого модуля отображения.

Пример здесь: http://jsfiddle.net/rniemeyer/3La5K/

1 голос
/ 24 апреля 2012

Или вы можете попробовать knockout-data-projection

Это довольно хорошо подходит для отображения моделей на сопоставления массивов js !!

0 голосов
/ 27 января 2012

Вам необходимо передать items observableArray в функцию отображения, чтобы она могла отобразить в нее новые значения.

Рабочее решение здесь: http://jsfiddle.net/unklefolk/j9pdX/

self.load = function () {
    ko.mapping.fromJS([
        { "name": "joey", "value": 1 },
        { "name": "anne", "value": 2 },
        { "name": "paul", "value": 3 },
        { "name": "mike", "value": 4 }
    ], {}, self.items);
};
...