Почему foreach работает не так, как ожидалось?

#javascript #jquery #html #knockout.js #foreach

#javascript #jquery #HTML #knockout.js #foreach

Вопрос:

Я получаю json ответ от своего сервера и пытаюсь сопоставить его с наблюдаемым массивом, а затем отобразить результаты внутри HTML таблицы. Что я получаю от сервера, так это эту строку:

 {"ids":[1,2,3,4],"names":["1","2","test tracker","test1"],"creators":["1","test","test","test"],"projectNames":["1","1","test project","test"]}
  

Теперь вот что я пытаюсь сделать в своей модели представления:

У меня есть этот объект, который должен содержать значения:

 trackersObj = function(item){
         this.trackerId = item.ids;
         this.trackerName = item.names;
         this.trackerCreator = item.creators;
         this.projectNames = item.projectNames;
};
  

И это ko.observableArray должно содержать результаты и зацикливать их в теле таблицы:

 trackersObjArray = ko.observableArray([])
  

И вот как я делаю сопоставление:

 loadActiveTrackers = function () {
    $.ajax({
        type: 'POST',
        url: 'controller.php',
        dataType: 'json',
        data: {
            action: "loadActiveTs"
        },
        success: function (data) {
            trackersObjArray.push(new trackersObj(data));
            console.log(trackersObjArray());
            $('#allTrackers').show();

        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            alert('Something got wrong!');
        }
    });
};
  

Наконец, это мой HTML :

 <table class="dataTable" id="CADataTable">
    <thead>
        <tr>
            <th>Test</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: trackersObjArray">
        <tr>
            <td>
                <input type="text" name="test" data-bind="value: trackerName">
            </td>
        </tr>
    </tbody>
</table>
  

Проблема в том, что в tbody ‘s td все результаты отображаются в одной строке.

Вот что я имею в виду:

Странная проблема с foreach

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

PS

Вот вывод console.log(trackersObjArray());

структура json

Ответ №1:

Ваш сервер отправляет несколько объектов, а не один. Он просто делает это необычным способом:

 {
    "ids": [1,2,3,4],
    "names": ["1","2","test tracker","test1"],
    "creators": ["1","test","test","test"],
    "projectNames": ["1","1","test project","test"]
}
  

действительно должно выглядеть так

 [
   {"id": 1, "name": "1", "creator": "1", "projectName": "1"}, 
   {"id": 2, "name": "2", "creator": "test", "projectName": "1"}, 
   {"id": 3, "name": "test tracker", "creator": "test", "projectName": "test project"}, 
   {"id": 4, "name": "test1", "creator": "test", "projectName": "test"}
]
  

Следовательно, вы должны помещать свои trackersObj объекты в цикл. Для этого есть несколько вариантов.

Сначала вы должны решить, хотите ли вы

  1. Обновите код вашего сервера, чтобы сразу отправить правильную структуру объекта (предпочтительно), или
  2. оставьте сервер как есть и преобразуйте объект на клиенте.

Поскольку я не вижу ваш серверный код, я выбираю вариант 2

 loadActiveTrackers = function () {
    $.post('controller.php', {
        action: "loadActiveTs"
    }).then(function (rawData) {
        // transformation step. if you fix your server to send proper data
        // you can drop the entire then().
        var i, transformedData = [];

        for (i = 0; i < rawData.ids.length; i  ) {
            transformedData.push({
                id: rawData.ids[i],
                name: rawData.namess[i],
                creator: rawData.creators[i],
                projectName: rawData.projectNames[i]
            });
        }

        return transformedData;
    }).done(function (transformedData) {
        ko.utils.arrayForEach(transformedData, function (tracker) {
            trackersObjArray.push(new trackersObj(tracker));
        });
    }).fail(function (XMLHttpRequest, textStatus, errorThrown) {
        alert('Something got wrong!');
    });
};
  

Это «ручной» способ. Вы могли бы обойтись без цикла for-each и вместо этого заменить значение trackersObjArray за один шаг ( trackersObjArray(transformedData);) . Вы также можете использовать плагин сопоставления для более сложных сопоставлений данных с viewmodel.


Вы не должны использовать jQuery в своей модели представления (или каким-либо иным образом ссылаться на DOM), потому что это излишне привязывает вашу модель представления к вашему представлению. Зависимость должна быть только наоборот.

Другими словами, $('#allTrackers').show(); не должно быть в модели представления. Используйте visible привязку.

Комментарии:

1. вау. Понятно. Проблема в том, что я работаю на стороне сервера php , и я в некотором роде новичок в этом. Я отредактировал свой вопрос и поместил php туда код. Не могли бы вы взглянуть? 🙂

2. Ваш PHP-код действительно легко исправить. Просто посмотрите на мой пример JSON «как это должно выглядеть» и подумайте пару минут. Вы разберетесь сами, я абсолютно уверен. (И это тоже принесет больше удовлетворения.)

3. @chility О, и еще одно: если вы на самом деле не обновляете данные на сервере (а это не похоже), используйте $.get() вместо $.post() .