appending to the DOM - vanilla javascript - javascript

I wanted to practice my vanilla javascript skills since I've been so library-heavy lately. My goal was to filter an array of JSON data (by events after 10/01/2015), and then append them as list items to the DOM, with the class being "events", and give the ability to delete events. Why isn't this working?
https://jsfiddle.net/youngfreezy/7jLswj9b/
function convertToJSData(arr) {
for (var i = 0; i < arr.length; i++) {
// var from = "10-11-2011";
var from = arr[i].date;
var numbers = from.match(/\d+/g);
var date = new Date(numbers[2], numbers[0] - 1, numbers[1]);
arr[i].date = date;
}
console.log(arr[0].date);
return arr;
}
function getByDate(data) {
convertToJSData(data);
var filterDate = new Date(2015, 09, 01);
return data.filter(function (el) {
return el.date >= filterDate;
});
}
var filteredDates = getByDate(events);
filteredDates.sort(function (a, b) {
return a.date - b.date;
});
console.log(filteredDates.length); //returns 6
var appendHTML = function (el) {
var list = document.getElementById("events");
for (var i = 0; i < filteredDates.length; i++) {
var listItem = filteredDates[i].name;
listItem.className = "event-list";
list.appendChild(listItem);
}
};
appendHTML(document.body);
var deleteEvent = function () {
var listItem = this.parentNode;
var ul = listItem.parentNode;
//Remove the parent list item from the ul
ul.removeChild(listItem);
}

when you do:
var listItem = filteredDates[i].name;
listItem.className = "event-list";
list.appendChild(listItem);
listItem is a string. You cannot append it as a child, you need to create a DOM element and append that:
var newEl = document.createElement('div');
newEl.className = "event-list";
newEl.innerHTML = filteredDates[i].name;
list.appendChild(newEl);

On a separate note, to just focus on the vanilla JS part of the question, maybe something like the following should illustrate the idea more generally:
let newElement = document.createElement("div");
newElement.innerHTML += `<ul><li>Item 1</li><li>Item 2</li></ul>`;
newElement.className = "item-list";
document.getElementById("root").append(newElement);

Related

$ dot each not working for recursion (JS)

I have a loop in which I am calling rec_append() recursively, apparently the first pass alone works, then the loop stops.
I have an array of 4 elements going into that $.each loop but I see only the first element going into the function recursively. Help!
I switched it for a element.forEach but that gives me only the second element and I am stuck, is there a better solution to process a tree of elements? My array is a part of a tree.
var data = JSON.parse(JSON.stringify(result))
var graph = $(".entry-point");
function rec_append(requestData, parentDiv) {
var temp_parent_details;
$.each(requestData, function (index, jsonElement) {
if (typeof jsonElement === 'string') {
//Element construction
//Name and other details in the form of a : delimited string
var splitString = jsonElement.split(':');
var details = document.createElement("details");
var summary = document.createElement("summary");
summary.innerText = splitString[0];
details.append(summary);
temp_parent_details = details;
parentDiv.append(details);
var kbd = document.createElement("kbd");
kbd.innerText = splitString[1];
summary.append(' ');
summary.append(kbd);
var div = document.createElement("div");
div.className = "col";
details.append(div);
var dl = document.createElement("dl");
div.append(dl);
var dt = document.createElement("dt");
dt.className = "col-sm-1";
dt.innerText = "Path";
div.append(dt);
var dd = document.createElement("dd");
dd.className = "col-sm-11";
dd.innerText = splitString[2];
div.append(dd);
var dt2 = document.createElement("dt");
dt2.className = "col-sm-1";
dt2.innerText = "Type";
div.append(dt2);
var dd2 = document.createElement("dd");
dd2.className = "col-sm-11";
dd2.innerText = splitString[1];
div.append(dd2);
} else {
$.each(jsonElement, function (jsonElementArrIndx, jsonChildElement) {
rec_append(jsonChildElement, temp_parent_details); //Only 1 pass works, rest skip
});
}
});
}
rec_append(data, graph);
Sample data:enter image description here

Javascript a TD click and get row cell data

I have this in Jquery all works:
$(document).ready(function() {
$("#checktable td:nth-child(1)").click(function(event){ // This line I need converted
event.preventDefault();
var $td = $(this).closest('tr').children('td'); //This line I need converted
var tid = $td.eq(0).text();
var tdate = $td.eq(1).text();
var tdescribe = $td.eq(2).text();
var wd = $td.eq(3).text();
var dep = $td.eq(4).text();
// ... more code
I need a similar thing in javascript, above only first td is clicked.
My javascript code so far:
function addRowHandlers() {
var table = document.getElementById("checktable2");
var rows = table.getElementsByTagName('tr');
var tid = '';
var tdate = '';
var tdescribe = '';
var wd = '';
var dep = '';
var tisclr = '';
for (var i = 1; i < rows.length; i++) {
rows[i].i = i;
rows[i].onclick = function() {
tid = table.rows[this.i].cells[0].innerText;
tdate = table.rows[this.i].cells[1].innerHTML;
tdescribe = table.rows[this.i].cells[2].innerHTML;
wd = table.rows[this.i].cells[3].innerHTML;
dep = table.rows[this.i].cells[4].innerHTML;
// ... etc more code
The javascript works but any td can be clicked, I am after only:
The first td clicked
Then get parent row
Then all child td's
I have been over dozens of StackOverflow posts and other sites as well... Thanks
And how do I add the event.preventDefault() to regular JS in such a case.
You'd bind the handler to the first .cell.
rows[i].cells[0].onclick = function () {
And then in the handler, access the .parentNode of this to get the row.
And since you're not closing over any variables except those in the function itself (and outside that function, of course), I'd just use a single handler instead of recreating it in the loop.
function addRowHandlers() {
var table = document.getElementById("checktable2");
var rows = table.getElementsByTagName('tr');
var tid = '';
var tdate = '';
var tdescribe = '';
var wd = '';
var dep = '';
var tisclr = '';
for (var i = 1; i < rows.length; i++) {
rows[i].i = i;
rows[i].cells[0].onclick = handler;
}
function handler() {
var row = this.parentNode;
tid = this.innerText;
tdate = row.cells[1].innerHTML;
tdescribe = row.cells[2].innerHTML;
wd = row.cells[3].innerHTML;
dep = row.cells[4].innerHTML;
// etc more code
}
}
I'd probably use a loop to get the desired content too. Maybe like this:
function handler() {
var row = this.parentNode;
var props = ["tid", "tdate", "tdescribe", "wd", "dep"];
var content = props.reduce(function(obj, key, i) {
obj[key] = row.cells[i][i ? "innerHTML" : "innerText"];
return obj;
}, {});
// etc more code
}
Now instead of variables, you have properties of the content object.

Is there a way so that elements which are getting added inside javascript function on the click of array of elements should be added only once?

Pre-Requisite: allPanelElems1[j] has elements such as t1, t2, t3 etc. which are div elements.
I am calling the javascript function handlePanelClick1 on array of elements. Inside the function I am adding up some other element i.e apiinfo. Now this function is called for each of element inside array allPanelElems1[j]. When a user clicks on any element of allPanelElems1[j] (let's say t1), then inside function element apiinfo is added successfully but when user clicks on the same element (t1) again then the element apiinfo is added again.
Is there a way, so that when user click on any element for the first time the apiinfo element should be added. But if the user calls the element again then apiinfo should not be added. Similarly for other elements t2, t3 etc ?
var allPanelElems1 = accordionElem.querySelectorAll(".panel1");
for (var j = 0, len1 = allPanelElems1.length; j < len1; j++) {
allPanelElems1[j].addEventListener("click", handlePanelClick1);
}
function handlePanelClick1(event) {
if (event.currentTarget.getAttribute('class').indexOf('active') >= 0) {
event.currentTarget.classList.remove("active");
} else {
prod1 = {
"Testcase": [{
"apiName": " demoAPIname1",
"request": "req",
"response": " res"
},
{
"apiName": " demoAPI name2",
"request": " req",
"response": "res"
}
]
};
var projectBody1 = document.createElement("div");
for (var propt1 in prod1) {
var projectBody2 = document.createElement("div");
var project1 = prod1[propt1];
for (var i in project1) {
var temp = document.createElement("div");
var apiname = project1[i].apiName;
var request1 = project1[i].request;
var response1 = project1[i].response;
var t1 = document.createElement("div");
var r1 = document.createElement("div");
var t2 = document.createElement("div");
var r2 = document.createElement("div");
r1.innerHTML = request1;
r2.innerHTML = response1;
t1.appendChild(createPanel("request", r1, "apidata"));
t2.appendChild(createPanel("response", r2, "apidata"));
temp.appendChild(t1);
temp.appendChild(t2);
projectBody2.appendChild(createPanel(apiname, temp, "apipanel"));
}
}
projectBody1.appendChild(createPanel("apiinfo", projectBody2, "apititle"));
var accordion4 = event.currentTarget; //THIS LINE I AM ASSIGNING MY current element
accordion4.appendChild(projectBody1);
var allPanelElems4 = accordion4.querySelectorAll(".panel");
for (var i = 0, len = allPanelElems4.length; i < len; i++) {
allPanelElems4[i].addEventListener("click", handlePanelClick);
}
event.currentTarget.classList.add("active");
}
event.stopPropagation();
}
I mean this sounds pretty stupid but couldn't you just clear the element's child/s before adding the new one? So It would only ever exist once?
element.innerHTML = "";
...
...
element.appendChild(child);
In case speed matters: Children removal ... sounds bad xD
Or you could check if the child count is more than 1
if(div.childNodes.length > 1) return
Check a specific ID
let children = Array.from(div.childNodes);
for(let i = 0; i < children.length; i++) {
if(children[i].id == "onlyOnce") return;
}
// Append child then as following:
let childElement = document.createElement("div");
childElement.id = "onlyOnce";
div.appendChild(childElement);
EDIT:
Greeting Elias :D

Splice out data, unknown position

I have a ToDo list, using localStorage... I need to be able to remove the item from the ToDo list... I try to use "dataArray.splice();" But the problem is I don't know how i can remove the object when the position is unknown...
function getTodoItems() {
for (var i = 0; i < dataArray.length; i++) {
if (!dataArray[i].listItem.length) return;
var itemList = document.getElementById("my-todo-list");
var list = document.createElement("li");
itemList.appendChild(list);
list.innerHTML = dataArray[i].listItem;
var spanItem = document.createElement('span');
spanItem.style.float = 'right';
var myCloseSymbol = document.createTextNode('\u00D7');
spanItem.classList.add("closeBtn");
spanItem.appendChild(myCloseSymbol);
listItems[i].appendChild(spanItem);
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
console.log(dataArray);
}
var list = document.getElementsByTagName('li');
list[i].onclick = function() {
this.classList.toggle("checked");
}
}
}
Then probably get its position:
const position = dataArray.indexOf(/*whatever*/);
dataArray.splice(position, 1);
You can get the position of the element using 'indexOf'
let pos = dataArray.indexOf(element);
dataArray.splice(pos,1)
IndexOf() wont work if you are trying to find the index of an entire object or array inside the array.
If you need to find the index of an entire object inside your array, you test each one's value to find out if it is the correct one. I would use findIndex();
Try this in your console:
var array = [];
for (var i = 0; i < 10; i++ ){ array.push({item: i}) }
console.log('Current Array: ', array);
var indexOfResult = array.indexOf({item: 3});
console.log('indexOf result: ',indexOfResult);
var findIndexResult = array.findIndex(object => object.item === 3);
console.log('findIndex result: ',findIndexResult)

Creating elements and event listeners with a for loop

I have an array of objects and I have defined a function to reference this objects using the this keyword.
var catArray = [toodles, whiskers, cornelius, poko, flufflepuss];
function catClicker() {
currentCat.textContent = this.name;
photo.src = this.src;
console.log("clicked on " + this.name);
catNow = this;
clicker.textContent = this.clicks;
}
I am trying to add list items to a html ul using a for loop and add event listeners for my function at the same time. Why is it not working?
for (var i = 0; i < catArray.length; i++) {
var item = document.createElement('li');
item.appendChild(document.createTextNode(catArray[i].name));
item.addEventListener("click", catClicker);
}
You need to use Function.prototype.bind to set the correct this scope.
item.addEventListener('click', catClicker.bind(catArray[i]));
I have this working maybe you can work out what was wrong with your code from this. It is hard for me to tell what your problem is because vital bits of the code is missing from what you have posted.
function whenReady(){
for (var i = 0; i < catArray.length; i++) {
var item = document.createElement('li');
var d
item.appendChild(document.createTextNode(catArray[i].name));
item.attributes.setNamedItem(
(d=document.createAttribute('data-catArray-idx'),d.value=i,d)
)
document.body.appendChild(item)
item.addEventListener("click", catClicker);
catClicks.set(catArray[i],{clicks:0})
}
catView=CatView().setCat(catArray[0]).appendToElement(document.body)
}
var catView
var catClicks=new WeakMap()
var catArray = [
{name: "toodles",url:"images/toodles.jpg",height:100,width:150},
{name: "whiskers",url:"images/whiskers.jpg",height:100,width:150},
{name: "cornelius",url:"images/cornelius.jpg",height:100,width:150},
{name: "poko", url:"images/poko.jpg",height:100,width:150},
{name: "flufflepuss",url:"images/flufflepuss.jpg",height:100,width:150}
]
var clicks=0
function catClicker() {
catView.setCat(catArray[this.attributes['data-catarray-idx'].value])
console.log("clicked on " + catView.selectedCat.name);
catClicks.get(catView.selectedCat).clicks++
}
var catViewId=0
var p=CatView.prototype
p.setCat=function(cat){
this.selectedCat=cat
this.update()
return this
}
p.appendToElement = function(element){
element.appendChild(this.catView)
return this
}
p.template= (name,photoURL) =>
`<img src="${photoURL}" height=100 width=100><span>${name}</span>`
p.update=function(){
this.catView.innerHTML =
this.template(
this.selectedCat.name, this.selectedCat.url
)
return this
}
p.toString=function(){this.selectedCat.name + 'view'}
function CatView(){
var me,cv,id
id = 'catView'+catViewId++
me = Object.create(CatView.prototype)
cv = me.catView = document.createElement('div')
cv.id = id;
return me
}
whenReady()

Categories