Проблемы с createElement и appendChild

У меня есть достаточно простая идея, которую я хотел бы реализовать.

У меня есть массив объектов с двумя свойствами: «id» и «name». Я хотел бы перечислить их в серии тегов «p», которые будут внутри «div».

Итак, вот HTML:

<body>
    <div id="listView"></div>
</body>

А вот и JavaScript в теге:

sessionStorage.eventid = 2;
var playerList = [];
playerList[0].id = 0;
playerList[0].name = "Add New Player";
playerList.push({
    id: 5,
    name: "Asako"
});
playerList.push({
    id: 6,
    name: "James"
});
playerList.push({
    id: 7,
    name: "Brian"
});
playerList.push({
    id: 8,
    name: "Helmut Spargle"
});

function listAll() {
    var element = document.getElementById("listView");
    var div;
    var node;
    for (var i = 0; i < playerList.length; i++) {
        div = document.createElement("div");
        div.setAttribute("onClick", "javascript: formOver(" + playerList[i].id + ")");
        node = "<p>" + playerList[i].name + "<br />\n" +
        "<small>&nbsp</small>\n" +
        "</p>\n";
        div.appendChild(node);
        element.appendChild(div);
    }
}
window.onLoad = function(){
    listAll();
}

Это ничем не наполняется. Я также разместил это на JSFiddle.

Я неправильно понял, как работает Array.push? Или что-то делать с appendChile и createElement?

Заранее спасибо за помощь.


person SimpleProgrammer    schedule 26.06.2014    source источник
comment
У вас есть две проблемы (посмотрите на консоль javascript в своей скрипке). Во-первых, вы можете установить свойство для playerList[0], когда playerList[0] не определено. Итак, playerList[0].id недействителен. Просто добавьте элементы с push, как и все остальные. Во-вторых, вы не можете использовать appendChild и передать ему строку. Вам нужно передать ему элемент. Например, элемент, созданный с помощью createElement.   -  person Matt Burland    schedule 26.06.2014
comment
Как я вижу консоль? Я никогда раньше не использовал JSFiddle. Я не мог найти кнопку для этого. Спасибо за все остальные советы, @MattBurland. Это сработало. За исключением того, что я использовал document.creatTextNode("string");, и он выводит все теги в виде строк вместо того, чтобы анализировать их как HTML. Означает ли это, что мне придется сделать кучу элементов и узлов отдельными друг от друга? Или я должен просто использовать innerHTML?   -  person SimpleProgrammer    schedule 26.06.2014
comment
Вы можете использовать innerHTML, если хотите. Для консоли зависит от вашего браузера, но F12 — хороший выбор. В противном случае загляните в меню вашего браузера, возможно, в разделы «Инструменты» и «Веб-разработчик» или что-то подобное. Или просто погуглите, как увидеть консоль javascript в браузере x. Консоль — это первый шаг в отладке, именно здесь будут появляться ваши сообщения об ошибках.   -  person Matt Burland    schedule 26.06.2014
comment
Я думал, вы имели в виду консоль внутри самого JSFiddle. Но теперь, когда вы сказали, что это кажется слишком очевидным. Ваше здоровье!   -  person SimpleProgrammer    schedule 26.06.2014


Ответы (2)


Две проблемы - впереди, попытка установить id и name на playerList[0] (которого еще не существует) не сработает.

Во-вторых, попытка добавить целый «узел», полный html, в стиле jQuery, не работает в мире простого JS. Вам нужно наращивать отдельные элементы.

sessionStorage.eventid = 2;
var playerList = [];

playerList.push({
    id: 0,
    name: "Add New Player"
});
playerList.push({
    id: 5,
    name: "Asako"
});
playerList.push({
    id: 6,
    name: "James"
});
playerList.push({
    id: 7,
    name: "Brian"
});
playerList.push({
    id: 8,
    name: "Helmut Spargle"
});

function listAll() {

    var element = document.getElementById("listView");
    var div = document.createElement("div");
    var node = "some string";
    for (var i = 0; i < playerList.length; i++) {
        div = document.createElement("div");
        div.setAttribute("onClick", "formOver(" + playerList[i].id + ")");

        var p = document.createElement('p');
        p.innerHTML = playerList[i].name;

        var br = document.createElement('br');
        p.appendChild(br);

        var small = document.createElement('small');
        small.innerHTML = '&nbsp;';
        p.appendChild(small);

        div.appendChild(p);

        element.appendChild(div);
    }
}
listAll();

Пример: http://jsfiddle.net/NF45y/

person Paul Roub    schedule 26.06.2014
comment
Вместо этого я выбрал div.innerHTML = "<p>" + playerList[i].name + "<br />\n <small>&nbsp</small>\n </p>\n";, но ваш ответ дал мне гораздо более глубокое понимание. Спасибо. - person SimpleProgrammer; 26.06.2014
comment
Обратите внимание, что div.setAttribute("onClick", "formOver(" + playerList[i].id + ")") фактически приводит к formOver(undefined). - person RobG; 26.06.2014
comment
Я определенно не вижу в этом проблемы (с Chrome, Firefox или Opera). Я получаю <div onclick="javascript: formOver(5)">, и при нажатии он делает то, что должен. Просто прочитайте ваш комментарий ниже, возможно, я просто проигнорировал это в Fiddle, чтобы уменьшить количество ненужного кода для отладки. - person SimpleProgrammer; 26.06.2014

Изначально:

var playerList = [];
playerList[0].id = 0;

Здесь вы должны получить сообщение об ошибке при попытке установить свойство id для undefined. Ты можешь сделать:

var playerList = [{}];
playerList[0].id = 0;
playerList[0].name = "Add New Player";

или добавьте объект так же, как и другие. Внутри функции;

function listAll() {
    var element = document.getElementById("listView");
    var div;
    var node;
    for (var i = 0; i < playerList.length; i++) {
        div = document.createElement("div");
        div.setAttribute("onClick", "javascript: formOver(" + playerList[i].id + ")");

Не используйте setAttribute для добавления слушателей таким образом, он не предназначен для использования и не работает везде, для простоты используйте свойства DOM:

        div.onclick = function(){...};

Поскольку вы устанавливаете значения внутри цикла, вам нужно разорвать замыкание с помощью переменных. Немедленно вызываемое функциональное выражение (IIFE) может помочь:

        div.onclick = (function(id) {
                         return function(){formOver(id);}
                      }(playerList[i].id));

Не используйте синтаксис XML в документе HTML, и нет особого смысла в '\n', если только вы не собираетесь читать разметку:

        node = "<p>" + playerList[i].name + "<br><small>&nbsp</small></p>";
        div.appendChild(node);

appendChild ожидает элемент DOM, а не разметку. Поскольку это единственное содержимое элемента div, вы можете использовать разметку для установки его свойства innerHTML (возможно, вы захотите изменить имя node на markup ):

        div.innerHTML = node;

        element.appendChild(div);
    }
}
person RobG    schedule 26.06.2014
comment
Не используйте свойства dom для событий. Используйте 1_ - person PitaJ; 26.06.2014
comment
Потому что это против обычного соглашения. Это также позволяет добавлять более одного обработчика на элемент. stackoverflow.com/questions/6348494/addeventlistener-vs-onclick - person PitaJ; 26.06.2014
comment
OP добавляет только одного слушателя, он не препятствует добавлению других слушателей для того же события, он поддерживается в каждом используемом браузере (попробуйте addEventListener в IE8), это меньше кода и быстрее. Кстати, в вашей скрипке обработчик вызывает formOver со значением undefined. И ответ, на который вы ссылаетесь (очевидно, в поддержку «не делайте этого»), не поддерживает этого. ;-) - person RobG; 26.06.2014