Javascript MVC, addEventListener не может быть присоединен к элементу DOM - PullRequest
0 голосов
/ 04 февраля 2019

У меня есть эти файлы JavaScript.Это действительно небольшой тестовый проект, чтобы понять, как MVC работает с JavaScript.Когда я пытаюсь нажать кнопку «Удалить Bloak», ничего не происходит, кроме как с последней кнопкой с идентификатором 100. К другим кнопкам не прикреплено никакого события щелчка.Почему?

Controller.js

    var BloakController = function BloakController(model, view) {
    this.model = model;
    this.view = view;
}

BloakController.prototype.init = function init() {
    this.view.onAddBloak = this.addBloak.bind(this);

    this.view.onDeleteBloak = this.deleteBloak.bind(this);

    this.view.onGetAllBloaks = this.getAllBloaks.bind(this);
}

BloakController.prototype.addBloak = function addBloak() {

}

BloakController.prototype.getAllBloaks = function getAllBloaks() {
    this.model.getAllBloaks(this.getAllBloaksList.bind(this));
}

BloakController.prototype.getAllBloaksList = function getAllBloaksList(allBloaksList) {
    for (var i = 0; i < allBloaksList.length; i++) {
        var bloak = allBloaksList[i];
        var bloakDataObjectModel = {
            title: bloak.title,
            body: bloak.body,
            userId: bloak.userId,
            id: bloak.id
        };

        this.view.render(bloakDataObjectModel);
    }
}

BloakController.prototype.deleteBloak = function deleteBloak(id) {
    this.model.deleteBloak(id, this.getAllBloaksList.bind(this));
}

Model.js

var BloakModel = function BloakModel(XMLHttpRequest) {
    this.XMLHttpRequest = XMLHttpRequest;
}

BloakController.prototype.addBloak = function addBloak() {

}

BloakModel.prototype.getAllBloaks = function getAllBloaks(callback) {
    var request = new this.XMLHttpRequest;

    request.onload = function onLoad(e) {
        var ajaxResponse = JSON.parse(e.currentTarget.responseText);
        callback(ajaxResponse);
    }

    request.open('GET', 'https://jsonplaceholder.typicode.com/posts', true);
    request.send();
}

BloakModel.prototype.deleteBloak = function deleteBloak(id, callback) {
    console.log(id);
    var request = new this.XMLHttpRequest;

    request.onload = function onLoad(e) {
        var ajaxResponse = JSON.parse(e.currentTarget.responseText);
        callback(ajaxResponse);
    }

    request.open('DELETE', 'https://jsonplaceholder.typicode.com/posts/' + id, true);
    request.send();
}

View.js

var BloakView = function BloakView(domElement) {
    this.domElement = domElement;

    this.onAddBloak = null;
    this.onDeleteBloak = null;
    this.onGetAllBloaks = null;
}

BloakView.prototype.render = function render(bloakDataObjectModel) {
    this.domElement.innerHTML += '<div class="bloakContainer"><h3>' + bloakDataObjectModel.title + '</h3><p class="bloakContent">' + bloakDataObjectModel.body + '</p><label class="bloakAuthor">' + bloakDataObjectModel.userId + '</label><br /><label class="bloakDate">' + bloakDataObjectModel.id + '</label><br /><input id=' + bloakDataObjectModel.id + ' type="button" value="Delete Bloak" /></div>';

    var addBloakButton = document.getElementById('addBloakButton');

    var deleteBloakButton = document.getElementById(bloakDataObjectModel.id);

    addBloakButton.addEventListener('click', this.onAddBloak);

    deleteBloakButton.addEventListener('click', this.onDeleteBloak);
}

App.js

var bloakModel = new BloakModel(XMLHttpRequest);

var targetElement = document.getElementById('bloaksContainer');
var bloakView = new BloakView(targetElement);

var bloakController = new BloakController(bloakModel, bloakView);

bloakController.init();

bloakController.getAllBloaks();

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

Код this.domElement.innerHTML += ...; неверен. Вы используете оператор + =, который добавляет что-то к себе, а затем присваивает новое значение.

Новое значение является результатом существующего innerHTML и нового HTML.Таким образом, новое значение [HTML] не будет иметь ранее добавленных обработчиков событий, оно будет просто копировать HTML.

Вы можете использовать метод appendChild для добавления новых элементов.

Кроме того, вам следует избегать использования for-loop с innerHTML, поскольку он будет продолжать обновлять DOM, и вы можете увидеть мерцания на экране.Если вы должны использовать innerHTML, вы должны

  1. создать весь HTML-код [innerHTML] вместе и ввести сразу,
  2. Затем использовать делегирование событий для добавления обработчиков событий.

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

Подробнее о DOM здесь .

0 голосов
/ 04 февраля 2019

Обновление

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

My Brain Fart

Я должен был понять, что изначально был неправ, если я был прав, то у вас возникла бы ошибка, в которой говорилось, что вы не можете прикрепить прослушиватель событий к null или undefined, моя плохая, глупая ошибка с моей стороны!


Идея

Очень кратко 1018 * просмотрел ваш код, я думаю, можно с уверенностью сказать, что ваша функция рендеринга несколько неисправна из-за использования innerHTML, он не разбирает обновленный HTML достаточно быстро, чтобы слушатели событий могли работать ...

Я сам проверил его и только что сделал следующее:

setTimeout(() => {
    var addBloakButton = document.getElementById('addBloakButton');
    var deleteBloakButton = document.getElementById(bloakDataObjectModel.id);
    addBloakButton.addEventListener('click', this.onAddBloak);
    deleteBloakButton.addEventListener('click', this.onDeleteBloak);
}, 10);

Это сработало.Итак, если вы не хотите слишком сильно изменять , вы можете сделать то, что я делал выше, или, в качестве альтернативы, вы можете сделать что-то вроде этого:

  var div = document.createElement("div");
  div.innerHTML = '<div class="bloakContainer"><h3>' + bloakDataObjectModel.title + '</h3><p class="bloakContent">' + bloakDataObjectModel.body + '</p><label class="bloakAuthor">' + bloakDataObjectModel.userId + '</label><br /><label class="bloakDate">' + bloakDataObjectModel.id + '</label><br /><input id=' + bloakDataObjectModel.id + ' type="button" value="Delete Bloak" /></div>';
  this.domElement.append(div);

  var addBloakButton = document.getElementById('addBloakButton');
  var deleteBloakButton = div.querySelector('input[id*="' + bloakDataObjectModel.id + '"]');
  addBloakButton.addEventListener('click', this.onAddBloak);
  deleteBloakButton.addEventListener('click', this.onDeleteBloak);
* 1029Более того, я бы сделал более надежный и надежный подход для реализации функции onRender в представлении, в сущности заявив, что один раз и только один раз все *Было отображено 1036 * соответствующего HTML, затем запускают метод onRender. или может быть что-то вроде view.dispatchEvents и т. Д. В частности, в этом примере я бы запустил такую ​​функцию в контроллере, поэтому, как только getAllBloaksList отобразит все соответствующие данные, вы можете затем срабатывает функция dispatchEvents, например: // Within the controller part... BloakController.prototype.getAllBloaksList = function getAllBloaksList(allBloaksList) { for (var i = 0; i < allBloaksList.length; i++) { var bloak = allBloaksList[i]; var bloakDataObjectModel = { title: bloak.title, body: bloak.body, userId: bloak.userId, id: bloak.id }; this.view.render(bloakDataObjectModel); } this.view.dispatchEvents(); }; // .. Within the View part... BloakView.prototype.dispatchEvents = function () { var list = this.domElement.querySelectorAll(".bloakContainer"); var todo = this.onDeleteBloak; list.forEach(function (div) { var deleteButton = div.querySelector("input[type=button]"); deleteButton.onclick = function () { todo(this.id); }; }); }; Демо // Controller. var BloakController = function BloakController(model, view) { this.model = model; this.view = view; }; BloakController.prototype.init = function init() { this.view.onAddBloak = this.addBloak.bind(this); this.view.onDeleteBloak = this.deleteBloak.bind(this); this.view.onGetAllBloaks = this.getAllBloaks.bind(this); }; BloakController.prototype.addBloak = function addBloak() { // todo }; BloakController.prototype.getAllBloaks = function getAllBloaks() { this.model.getAllBloaks(this.getAllBloaksList.bind(this)); }; BloakController.prototype.getAllBloaksList = function getAllBloaksList(allBloaksList) { for (var i = 0; i < allBloaksList.length; i++) { var bloak = allBloaksList[i]; var bloakDataObjectModel = { title: bloak.title, body: bloak.body, userId: bloak.userId, id: bloak.id }; this.view.render(bloakDataObjectModel); } this.view.dispatchEvents(); }; BloakController.prototype.deleteBloak = function deleteBloak(id) { this.model.deleteBloak(id, this.getAllBloaksList.bind(this)); }; // Model. var BloakModel = function BloakModel(XMLHttpRequest) { this.XMLHttpRequest = XMLHttpRequest; }; BloakController.prototype.addBloak = function addBloak() { // todo }; BloakModel.prototype.getAllBloaks = function getAllBloaks(callback) { var request = new this.XMLHttpRequest; request.onload = function onLoad(e) { var ajaxResponse = JSON.parse(e.currentTarget.responseText); callback(ajaxResponse); } request.open('GET', 'https://jsonplaceholder.typicode.com/posts', true); request.send(); }; BloakModel.prototype.deleteBloak = function deleteBloak(id, callback) { console.log(id); var request = new this.XMLHttpRequest; request.onload = function onLoad(e) { var ajaxResponse = JSON.parse(e.currentTarget.responseText); callback(ajaxResponse); } request.open('DELETE', 'https://jsonplaceholder.typicode.com/posts/' + id, true); request.send(); }; // View. var BloakView = function BloakView(domElement) { this.domElement = domElement; this.onAddBloak = null; this.onDeleteBloak = null; this.onGetAllBloaks = null; }; BloakView.prototype.render = function render(bloakDataObjectModel) { this.domElement.innerHTML += '<div class="bloakContainer"><h3>' + bloakDataObjectModel.title + '</h3><p class="bloakContent">' + bloakDataObjectModel.body + '</p><label class="bloakAuthor">' + bloakDataObjectModel.userId + '</label><br /><label class="bloakDate">' + bloakDataObjectModel.id + '</label><br /><input id=' + bloakDataObjectModel.id + ' type="button" value="Delete Bloak" /></div>'; } BloakView.prototype.dispatchEvents = function() { var list = this.domElement.querySelectorAll(".bloakContainer"); var todo = this.onDeleteBloak; var addBloakButton = document.getElementById('addBloakButton'); addBloakButton.addEventListener('click', this.onAddBloak); list.forEach(function(div) { var deleteButton = div.querySelector("input[type=button]"); deleteButton.onclick = function() { todo(this.id); }; }); }; // App. var bloakModel = new BloakModel(XMLHttpRequest); var targetElement = document.getElementById('bloaksContainer'); var bloakView = new BloakView(targetElement); var bloakController = new BloakController(bloakModel, bloakView); bloakController.init(); bloakController.getAllBloaks(); <button id="addBloakButton">Add</button> <div id="bloaksContainer"> <!-- DHTML --> </div>
...