I have the html page. In that HTML page, Iust want to clone all elements like head,body and other elements .
I can able to get like this
const getHeadEle = () => {
const newHead = document.head.cloneNode(true);
return newHead.innerHTML;
}
const getBody = () => {
const head = document.head.cloneNode(true);
const dom = document.createElement('div');
dom.innerHTML = document.body.innerHTML;
return dom.innerHTML;
}
const html = `<!doctype html><html lang="en"><head>${getHeadEle()}</head><body>${getBody()}</body></html>`;
For now, I get the head element and body element into separate method. Is possible to clone all documents in a line of code?
try it ...
const getdocument = () => {
const newDocument = document.cloneNode(true);
return newDocument ;
}
const html = getdocument() ;
Related
i know that the problem is that let todoList is an empty array, but i dont know how to solve it.
the id tags in my created html is so e can create a delete button later
heres my code:
const textArea = document.querySelector("textarea");
const button = document.querySelector("button");
const listContainer = document.querySelector(".list-container");
let id = 0;
let todoList = [];
button.onclick = function () {
const listItem = {
title: textArea.value,
};
todoList.push(listItem);
addToStorage(todoList);
const dataFromStorage = getFromStorage();
createHtml(dataFromStorage);
};
function addToStorage(items) {
const stringify = JSON.stringify(items);
localStorage.setItem("list", stringify);
}
function getFromStorage() {
const data = localStorage.getItem("list");
const unstrigified = JSON.parse(data);
return unstrigified;
}
const createHtml = (data) => {
id++;
listContainer.innerHTML = "";
data.forEach((item) => {
listContainer.innerHTML += `<div class="list-item" data-id=${id}><p>${item.title} </p><button class="remove" data-id=${id}>Delete</button></div>`;
});
};
The problem here is you just forgot to load the data from localStorage when the page loaded like this
window.onLoad = () => {
const dataFromStorage = getFromStorage();
if(dataFromStorage){
createHtml(dataFromStorage);
} else {
createHtml([]);
}
}
The problem in the code is as follows
Initially the todolist will be an empty array. so when you do the below
todoList.push(listItem);
// adding to local storage which will override the existing todos when page is refreshed
addToStorage(todoList);
// So when the below line is executed only the latest todo will be returned
const dataFromStorage = getFromStorage();
createHtml(dataFromStorage);
Fix:
Initialise the todos from localstorage instead of an empty array
let todoList = [];
// change it as below
let todoList = getFromStorage();
Now Modify the getFromStorage() as below
// If the data is present in the localStorage then return it, else return empty array
function getFromStorage() {
const data = localStorage.getItem("list");
if (!data) return [];
const unstrigified = JSON.parse(data);
return unstrigified;
}
Now when the page is loaded, we need to display the todos. Add the below lines of code
window.onload = function () {
createHtml(todoList);
};
That's it. This will fix the issue.
Few minor improvements can be made as well.
todoList.push(listItem);
addToStorage(todoList);
const dataFromStorage = getFromStorage(); // this line is not necessary, remove it
createHtml(dataFromStorage); // change this to createHtml(todoList)
Codepen
Thanks.
I have a function to render comments, in which each comment is stored as an object in an array. Comments can have reply comments, in which they have the exact same html and data to render, just their styling is different (via a CSS modifier class).
How can I make this function recursive? The renderReplies(comment.replies) calls a function that is the exact same as renderComments function, just without the mentioned function call renderReplies (as a reply to a reply is the exact same also in styling terms).
const renderComments = (comments) => {
commentsElement.innerHTML = '';
comments.forEach(comment => {
commentsElement.innerHTML += html;
// data-id attribute
const liElements = commentsElement.querySelectorAll('.comment');
const liElement = liElements.item(liElements.length - 1);
liElement.setAttribute('data-id', comment.id);
// author
liElement.querySelector('.comment__author').innerHTML = comment.user.username;
// avatar src & alt attributes
const avatar = liElement.querySelector('.comment__avatar');
avatar.setAttribute('src', comment.user.image.png);
avatar.setAttribute('alt', comment.user.username);
// time since posted
// content
const p = liElement.querySelector('.comment__text');
p.appendChild(document.createTextNode(comment.content));
// score
liElement.querySelector('.comment__score b').innerHTML = comment.score;
// replies
renderReplies(comment.replies);
});
};
Check whether there's a replies property. If it exists, call the function recursively. Since replies won't have replies of their own, you'll stop there.
const renderComments = (comments) => {
commentsElement.innerHTML = '';
comments.forEach(comment => {
commentsElement.innerHTML += html;
// data-id attribute
const liElements = commentsElement.querySelectorAll('.comment');
const liElement = liElements.item(liElements.length - 1);
liElement.setAttribute('data-id', comment.id);
// author
liElement.querySelector('.comment__author').innerHTML = comment.user.username;
// avatar src & alt attributes
const avatar = liElement.querySelector('.comment__avatar');
avatar.setAttribute('src', comment.user.image.png);
avatar.setAttribute('alt', comment.user.username);
// time since posted
// content
const p = liElement.querySelector('.comment__text');
p.appendChild(document.createTextNode(comment.content));
// score
liElement.querySelector('.comment__score b').innerHTML = comment.score;
// replies
if (comment.hasOwnProperty("replies")) {
renderComments(comment.replies);
}
});
};
So I have been a mess for days. I am scraping a website for particular information. The problem is that the website has two css classes but with an identical name. I want to use the link and text from the first css class. Attached is the image of what I have. I want to only use the href values from 1 and not the ones from the two "regions".
const cheerio = require('cheerio');
const axios = require("axios");
const siteUrl = "https://worldpostalcode.com/nigeria/abia/";
const fetchData = async () => {
const result = await axios.get(siteUrl);
return cheerio.load(result.data);
};
const getData = async (html) => {
const stateList = []
const $ = await fetchData();
const stateUrl = $('.regions',html);
//console.log(stateUrl.length)
console.log(stateUrl.length)
for (let index = 0; index < 1; index++) {
let firstRegion = $(stateUrl[index],'a')
stateList.push(firstRegion)
}
console.log(stateList)
}
getData()
Help please
I would use the previous h2 text:
$('h2:contains(Regions) + div.regions a')
When taking screenshots using puppeteer, dynamic elements with the .menu__link class are required to change innerHTML to a stub.
I use BackstopJs puppet/onReady.js
When I try this, only the first element on the page is replaced:
module.exports = async (page) => {
const myLocalValue = "Test";
const tweets = await page.$$('.menu__link');
for (const tweet of tweets) {
await page.$eval('.menu__link', (el, value) => el.innerHTML = value, myLocalValue)
}
};
And this code does not work at all:
module.exports = async (page) => {
const myLocalValue = "Test";
const tweets = await page.$$('.menu__link');
for (const tweet of tweets) {
await page.$eval(tweet, (el, value) => el.innerHTML = value, myLocalValue)
}
};
Please tell me how to replace innerHTML on the entire page for all .menu__link using puppeteer?
You can use $$eval
await page.$$eval('. menu__link', (links, value) => links.forEach(el => el.innerHTML = value), 'myLocalValue');
I'm trying to get my code to output an api object to the html file.
const container = document.createElement('div');
container.setAttribute('class', 'container');
obj = fetch('https://apis.is/concerts')
.then(function(response) {
return response.json();
})
.then(function(data) {
return obj = data;
})
.then(() => idk())
function idk() {
let count = 0;
for(key in obj.results) {
count++;
};
console.log(count);
for(let i = 0; i < count; i++) {
const card = document.createElement('div');
card.setAttribute('class', 'card');
const h1 = document.createElement('h1');
h1.textContent = obj.results[i].eventDateName;
const p = document.createElement('p');
p.textContent = obj.results[i].dateOfShow;
container.appendChild(card);
card.appendChild(h1);
card.appendChild(p);
};
};
I have been trying to use DOM to create elements for the html file but it's like some of the code is being ignored.
If you want to render all the DOM you are creating you have to somehow add it to the DOM tree that browser is displaying. The simples way would be to add it to body node. document.querySelector('body').appendChild(container); once you're done with data processing.
But I would suggest to refactor your code a bit. For instance in this step you are assigning results to the original object where you are saving the promise with the results. Also that is a global object so pretty quick you might end up with a race condition.
.then(function(data) {
return obj = data;
})
Also the idk() function is coupled to that very specific variable obj which would make it really hard to test.
obj = fetch('https://apis.is/concerts')
.then(function(response) {
return response.json(); //subscribe to response stream
})
.then((response) => {
const allEvents = eventsDomTree(response.results); // create the events DOM tree based on response
document.querySelector('body').appendChild(allEvents); //append the created list to document DOM tree
});
function eventsDomTree(events) {
const allEvents = document.createElement('div');
events.forEach((event) => {
const card = document.createElement('div');
card.setAttribute('class', 'card');
const eventName = document.createElement('h1');
eventName.textContent = event.eventDateName;
const dateOfShow = document.createElement('p');
dateOfShow.textContent = event.dateOfShow
card.appendChild(eventName);
card.appendChild(dateOfShow);
allEvents.appendChild(card);
});
return allEvents;
}