How to use delegate in javascript - javascript

I try to make todo list app with javascript, I have function to create new each item (li elements) like that
todoView: function (todo) {
var controller = todoController.todoList;
console.log('controller', controller);
var item = document.createElement('li');
item.setAttribute('class', 'todoItem');
var inpCheckbox = document.createElement('input');
this.setAttributes(inpCheckbox, { 'type': 'checkbox', 'class' : 'itemList'} );
var lbContent = document.createElement('label');
lbContent.innerHTML = todo.getContent();
var btnRemove = document.createElement('button');
console.log('id', this.id)
this.setAttributes(btnRemove, { 'class': 'remove', 'id' : this.id} );
// btnRemove.setAttribute('id', this.id);
//item append each element
item.appendChild(inpCheckbox);
item.appendChild(lbContent);
item.appendChild(btnRemove);
console.log('item', item);
//ul append each item
document.querySelector('#todoListView').appendChild(item);
},
but in the end file I set the handle event for all li item have class .remove
var deleteItem = document.getElementsByClassName('remove')
for(var i = 0; i < deleteItem.length; i++) {
deleteItem[i].addEventListener("click", function() {
todoController.removeTodo(i);
});
}
But now I have issue that I can't call .remove class, because it just create into todoView function. It to be contain difference block. In jquery I can use delegate to resolve it, but I don't know how to fix it in js pair. Pls help me

Instead of
var deleteItem = document.getElementsByClassName('remove')
for(var i = 0; i < deleteItem.length; i++) {
deleteItem[i].addEventListener("click", function() {
todoController.removeTodo(i);
});
}
you'll want
todoListView.addEventListener('click', function(e) {
if(e.target.classList.contains('remove')){
todoController.removeTodo(e.target);
}
});
However, I think your removeTodo function is flawed

Related

Get click array item

trying to call an array from model.data in catListView.render(), it's showing perfectly but how to make the array item clickable, (i.e cat0 is clicked or cat2 is click).
$(function () {
var model = {
data: ["cat0", "cat1", "cat2", "cat3"],
}
var oct = {
init: function () {
catList.init();
},
getCat: function () {
return model.data;
},
};
var catListView = {
init: function () {
this.$catList = $("#cat-list");
catList.render();
},
render: function () {
var catList = this.$catList.html('');
var cats = oct.getCat();
for (var i = 0; i < cats.length; i++) {
var cat = cats[i];
var li = "<li>" + cat + "</li>";
addEventListener(li, "click", function(){
console.log(this.li.text());
});
catList.append(li);
}
}
};
oct.init();
}());
You should bind an eventListener to the EventTarget using EventTarget.addEventListener() when using pure DOM (see https://developer.mozilla.org/de/docs/Web/API/EventTarget/addEventListener for reference).
So in your code it would be:
var li = document.createElement('li'); // create an element instead if string
li.innerText = cat;
li.addEventListener("click", function(){
console.log(li.innerText);
});
Note that you also need to create a DOM element to bind events to.
The codes you typed cannot run... I try to guess what you want-
$li.bind("click", function() {
console.log("way 2", $(this).index());
});
https://codepen.io/linjiyeah/pen/QvzVQN

Dynamically creating collapsible lists without Jquery

I am trying to create an HTML list of items dynamically but I cannot understand how to make the lists collapsible. Right now I only have a way to dynamically create list items. Also if anyone has suggestions for code optimization they are always welcome. I am limited to just Javascript and HTML though. Sample of what the list will look like. The data is very long so I would like to be able to minimize scriptlog's list item on click.
var self = this;
var nameItem = document.createElement("li");
var dateItem = document.createElement("li");
nameNode = document.createTextNode("Name: " + session.name);
dateNode = document.createTextNode("Date: " + session.date);
nameItem.appendChild(nameNode);
dateItem.appendChild(dateNode);
var element = document.getElementById("sessionData");
element.appendChild(nameItem);
element.appendChild(dateItem);
session.actions.forEach(function(action, index) {
console.log(action);
var listItem = document.createElement("li");
var node = document.createTextNode(action.name);
var nestedUl = document.createElement("ul");
var dataUl = document.createElement("ul");
var scriptUl = document.createElement("ul");
var versionUl = document.createElement("ul");
var scriptLi = nestedUl.appendChild(document.createElement("li"));
var dataLi = nestedUl.appendChild(document.createElement("li"));
var versionLi = nestedUl.appendChild(document.createElement("li"));
var scriptInfo = scriptUl.appendChild(document.createElement("li"));
var dataInfo = dataUl.appendChild(document.createElement("li"));
var versionInfo = versionUl.appendChild(document.createElement("li"));
scriptLi.appendChild(document.createTextNode(action.script));
dataLi.appendChild(document.createTextNode(action.data));
versionLi.appendChild(document.createTextNode(action.version));
scriptInfo.appendChild(document.createTextNode(action.scriptTxt));
dataInfo.appendChild(document.createTextNode(action.dataTxt));
versionInfo.appendChild(document.createTextNode(action.versionTxt));
scriptLi.appendChild(scriptUl);
dataLi.appendChild(dataUl);
versionLi.appendChild(versionUl);
listItem.appendChild(node);
listItem.appendChild(nestedUl);
var element = document.getElementById("actionData");
element.appendChild(listItem);
});
A simple solution would be to add a click event listener to your <li> tags and set the display to 'none' for the child <ul> tags.
listItem.addEventListener("click", function() {
var ul = document.getElementById('ul-' + action.name);
ul.style.display = ul.style.display === '' ? 'none' : '';
});
See plnkr
You can update the style.display attribute of an element to show or hide it. As CDelaney noted, this can be done inside a click event listener.
If you already have the target li and ul elements in variables within a JavaScript closure, you can reference them directly from within the inline addEventListener function without needing to do any lookups to IDs or HTML properties.
Check out the example snippet below to see it in action.
var source = {
text: "1",
items: [
{text: "1A"},
{text: "1B", items: [
{text: "1B-i"},
{text: "1B-ii"},
{text: "1B-iii"},
{text: "1B-iv", items: [
{text:"1B-iv-a"},
{text:"1B-iv-b"},
{text:"1B-iv-c"}
]}
]},
{text: "1C", items:[
{text:"1C-i"},
{text:"1C-ii"},
{text:"1C-ii"}
]},
{ text: "1D"}]
};
var rootNode = document.getElementById("actionData");
createListFromObject(source, rootNode);
function createListFromObject(obj, element) {
if (obj.text) { // add text node
var li = document.createElement("li");
li.appendChild(document.createTextNode(obj.text));
element.appendChild(li);
}
if (obj.items) { // add child list
var ul = document.createElement("ul");
element.appendChild(ul);
if (li) {
li.style.cursor = "pointer";
li.style.color = "blue";
li.style.textDecoration = "underline";
// make clicking the text node toggle the child list's visibility:
li.addEventListener("click", function() {
ul.style.display = ul.style.display === "none" ? "inherit" : "none";
});
}
for (var i = 0, len = obj.items.length; i < len; i++) {
createListFromObject(obj.items[i], ul);
}
}
}
<ul id="actionData"></ul>

addEventListener to class after for loop; Vanilla JS

I'm trying to get eventlistener to work for a class created inside a loop. I can't get it to work, any suggestions?
window.onload = function(){
var div = document.createElement('div'),
container = document.getElementById('container'),
classname = document.getElementsByClassName("hello");
div.className = 'hello';
var tasks = [
'One',
'Two',
'Three',
'Four'
];
for (var i = 0; i < tasks.length; ++i) {
container.innerHTML += '<div class="hello"><p>' + tasks[i] + '</p></div>';
}
classname.addEventListener('click', function(){
this.className = 'done';
});
console.log(classname);
};
classname is a NodeList, addEventListener is a method for individual nodes. You need to loop over the elements:
for (i = 0; i < classname.length; i++) {
classname[i].addEventListener('click', function() {
this.className = 'done';
});
}
getElementsByClassName returns a NodeList, so you can not add an event listener on that. You must wanted to add event listener to the elements on this list.
So that gives:
//NodeList has not forEach method, but we can take it from an array
[].forEach.call( classnameElements, function( classnameElement ){
classnameElement.addEventListener('click', function(){
this.className = 'done';
});
}):

create a group of checkboxes with a click event associated Javascript

I'm creating a javascript function that builds a table with checkboxes.
I want associate a click event to them.
The event must be the same for all.
This is a part of my code:
var i = 0;
for (i = 0; i < data.Items.length; i++) {
var tr = $(document.createElement('tr'));
tr.addClass("MyBookings_table_content");
$("#MyBookings_table").append(tr);
//Create a CheckBox Element
var chkbox = document.createElement('input');
chkbox.type = "checkbox";
chkbox.id = "chk"+i.toString();
chkbox.name = "chk" + i.toString();
//Event here
}
Can anybody help me?
Since you are using jQuery, you can simply add this event listener :
$("#MyBookings_table").on("click", "input[type=checkbox]", clickCB);
function clickCB() {
var $cbx = $(this);
// some code on my checkbox
}
This code is to be appended after the loop, see this fiddle : http://jsfiddle.net/6f79pd5y/
create a function and link it with an addEventListener
function outerFunction(){
}
checkbox.addEventListener('click', outerFunction);
addEventListener("click",myFunction);
where you have the comments
How about:
var i = 0;
for (i = 0; i < data.Items.length; i++) {
var tr = $(document.createElement('tr'));
tr.addClass("MyBookings_table_content");
$("#MyBookings_table").append(tr);
//Create a CheckBox Element
var chkbox = document.createElement('input');
chkbox.type = "checkbox";
chkbox.id = "chk"+i.toString();
chkbox.name = "chk" + i.toString();
//Event here
$(chkbox).click(function()
{
alert("Click!");
});
tr.append(chkbox);
}
A working example:http://jsfiddle.net/mpup12z5/
If you reorganise your element-creation to use jQuery also, you can bind the click-handler at the point of creation:
var i = 0;
for (i = 0; i < data.Items.length; i++) {
var tr = $(document.createElement('tr'));
tr.addClass("MyBookings_table_content");
$("#MyBookings_table").append(tr);
$('<input />', {
'type' : 'checkbox',
'id' : chk + i, // i will be converted to a string automatically
'name' : chk + i,
'click' : functionToCall // note: no parentheses, you want to
}); // call the function, not use its return value
}
Or:
var i = 0;
for (i = 0; i < data.Items.length; i++) {
var tr = $(document.createElement('tr'));
tr.addClass("MyBookings_table_content");
$("#MyBookings_table").append(tr);
$('<input />', {
'type' : 'checkbox',
'id' : chk + i, // i will be converted to a string automatically
'name' : chk + i,
'on' : {
'click' : functionToCall
}
});
}
But, it really is preferable to delegate the event-handling to the closest ancestor element, presumably the <table>, unless a specific property of the created <input /> should call a different function, or do something somewhat different.

mapping Json data and adding data attr

I have a difficulty with mapping my my Json data. I would like to add data attr to each div with .name class. So as the result is like that:
<div class="name" data-key="sth"> sty</div>
Key can be got like that: ['streme'].key
here is my buggy JS:
function getExistingLinks() {
$.post( "http://0.0.0.0:9292/api/links", function( data ) {
var names = data.map(function (i) {
return i['link'].name
});
var keys = data.map(function (i) {
return i['link'].key
});
var container = document.querySelector(".link-names");
names.forEach(function(name) {
var div = document.createElement('div');
div.innerHTML = name;
$('div').addClass("name");
// $('div').each( function(index) {
$('div')[index].data("key") = keys[index];
}
container.appendChild(div);
});
});
return false;
}
names.forEach(function(name,index) {
var div = document.createElement('div');
div.innerHTML = name;
$(div).addClass("name");
$(div).data("key") = keys[index];
});
You need to remove the quotes in the $() selector!
As per your comment, may be try doing like:
var i = 0;
names.forEach(function(name) {
var div = document.createElement('div');
div.innerHTML = name;
$('div').addClass("name");
$('div').data("key", keys[i]);
container.appendChild(div);
i++;
});
the preferred method is to only add to the DOM once, as adding to the DOM will cause a redraw on each.
psuedo code as not sure what name represents in your innerHTML:
var divs = [];
for (var i, len = names.length; i < len; i++) {
divs.push($(''+name+'').data("key", keys[i]));
}
$container.append(divs);
http://codepen.io/jsdev/pen/2866265243563efd79cf05a5b12202b3
try something like this
$('.name').data('key') //will give you sth

Categories

Resources