lets say i have a parent-div. And in this div-container, i want to display 5 elements which have all the same structure. For example:
<div class="element">
<p class="name">
</p>
<div class="logo">
</div>
</div>
Is there a way to make an object or prototype out of it, so i dont have to generate every single HTML Element with their classes and src values with the appendChild-function and Dot-Notations in a for-loop?
Im thinking of something like:
for(let i = 0; i<=5;i++){
var element = new element(class,src1,src2 ...);
}
And the "element" is defined in a external class file or something familiar.
Im a beginner, so please show mercy :)
You'll need to clone the node from the template's content. For example:
const templateElement = document.querySelector("#someTemplate")
.content
.querySelector(".element");
// create an Array of nodes (so in memory)
const fiveNodes = [];
for (let i = 0; i < 5; i += 1) {
const nwNode = templateElement.cloneNode(true);
// ^ clone the whole tree
nwNode.querySelector("p.name").textContent += ` #${i + 1}`;
fiveNodes.push(nwNode);
}
// append the nodes to document.body
// this is faster than appending every element in the loop
fiveNodes.forEach(el => document.body.append(el));
<template id="someTemplate">
<div class="element">
<p class="name">I am node</p>
<div class="logo"></div>
</div>
</template>
Related
I am a beginner in JavaScript and I can't figure out the following problem: I am trying to create a simple JavaScript Movie List. I have 10 lists on the Movie List. I tried to show all of the lists with for loop, but it doesn't work.
Here's the code:
function renderModal() {
for (let i = 0; i < listMovies.length; i++) {
let movieData = listMovies[i];
document.getElementById("poster").src = movieData.img;
document.getElementById("title").innerHTML = movieData.name;
document.getElementById("genre").innerHTML = movieData.genre;
document.getElementById("rating-num").innerHTML = "Rating: "+ movieData.rating + "/10";
document.getElementById("movie-desc").innerHTML = movieData.desc;
document.getElementById("imdb-page").href = movieData.link;
return movieData;
}
}
What do I have to do?
Help me to fix it!.
You can use template tag for list and render it into target element.I am showing an example.
Movie list
<div id="movieList"></div>
template for list
<template id="movieListTemplate">
<div class="movie">
<img src="" class="poster" alt="">
<div class="title"></div>
<div class="genre"></div>
<div class="rating-num"></div>
<div class="movie-desc"></div>
<div class="imdb-page"></div>
</div>
</template>
Javascript code:
if (listMovies.length > 0) {
const movileListTemplate = document.getElementById('movieListTemplate')
const movieRenederElement = document.getElementById('movieList')
for(const movie of listMovies) {
const movieEl = document.importNode(movileListTemplate.content, true)
movieEl.querySelector('.poster').src = movie.img
movieEl.querySelector('.title').textContent = movie.name
//use all queryselector like above
}
}
Your return movieData; will stop the loop dead. Not that running it more than once will change anything since you change the same elements over and over. IDs must be unique.
Here is a useful way to render an array
document.getElementById("container").innerHTML = listMovies.map(movieData => `<img src="${movieData.img}" />
<h3>${movieData.name}</h3>
<p>${movieData.genre}</p>
<p>Rating: ${movieData.rating}/10</p>
<p>${movieData.desc}
IMDB
</p>`).join("<hr/>");
With return movieData, the for loop will ends in advance.You should put it outside the for loop.
Consider the following hierarchy in DOM
<div class="bodyCells">
<div style="foo">
<div style="foo">
<div style="foo1"> 'contains the list of text elements I want to scrape' </div>
<div style="foo2"> 'contains the list of text elements I want to scrape' </div>
</div>
<div style="foo">
<div style="foo3"> 'contains the list of text elements I want to scrape' </div>
<div style="foo4"> 'contains the list of text elements I want to scrape' </div>
</div>
By using class name bodyCells, I need to scrape out the data from each of the divs one at a time (i.e) Initially from 1st div, then from the next div and so on and store it in separate arrays. How can I possibly achieve this? (using puppeteer)
NOTE: I have tried using class name directly to achieve this but, it gives all the texts in a single array. I need to get data from each tag separately in different arrays.
Expected output:
array1=["text present within style="foo1" div tag"]
array2=["text present within style="foo2" div tag"]
array3=["text present within style="foo3" div tag"]
array4=["text present within style="foo4" div tag"]
As you noted, you can fetch each of the texts in a single array using the class name. Next, if you iterate over each of those, you can create a separate array for each subsection.
I created a fiddle here - https://jsfiddle.net/32bnoey6/ - with this example code:
const cells = document.getElementsByClassName('bodyCells');
const scrapedElements = [];
for (var i = 0; i < cells.length; i++) {
const item = cells[i];
for (var j = 0; j < item.children.length; j++) {
const outerDiv = item.children[j];
const innerDivs = outerDiv.children;
for (var k = 0; k < innerDivs.length; k++) {
const targetDiv = innerDivs[k];
scrapedElements.push([targetDiv.innerHTML]);
}
}
}
console.log(scrapedElements);
I have a function which accepts two parameters, each of type HTML element. It is supposed to return which element appears first in the document order. Is there any simple way to determine this?
Template -
<body>
<div id="div1">
<div id="div2">
</div>
</div>
<div id="div3">
<div id="div4">
</div>
</div>
</body>
JS -
const elem1 = document.getElementById('div2');
const elem2 = document.getElementById('div4');
const firstAppearingElement = checkOrder(elem1, elem2); // it should return elem1
function checkOrder(element1, element2) {
// check which one appears first in dom tree
}
You can try with Node.compareDocumentPosition()
The Node.compareDocumentPosition() method compares the position of the
given node against another node in any document.
The syntax is object.compareDocumentPosition (nodeToCompare);
let first = document.getElementById('a');
let second=document.getElementById('b');
// Because the result returned by compareDocumentPosition() is a bitmask, the bitwise AND operator has to be used for meaningful results.See link above for more
if (first.compareDocumentPosition(second) & Node.DOCUMENT_POSITION_FOLLOWING) {
console.log('element with id a is before element with id b'); //
} else {
console.log('element with id a is after element with id b');
}
<div id="a"></div>
<div id="b"></div>
<body>
<div class = "order-1-a">
<div class = "order 2-a">
<div class = "order 3-a"></div>
</div>
<div class = "order 2-b"></div>
<div class = "order 2-c"></div>
<div class = "order 2-d"></div>
</div>
<div class = "order-1-b"></div>
</body>
If I want a div to wrap only class "order-2-a" + being the first child of "class-1-a", how should I script the div with JavaScript?
Probably your best bet is to:
Create a new Element with .createElement().
Append 2-a to the new Element with .appendChild().
Insert the new element before 2b with .insertBefore().
var one_a = document.getElementsByClassName("order-1-a")[0];
var two_a = document.getElementsByClassName("order-2-a")[0];
var two_b = document.getElementsByClassName("order-2-b")[0];
var new_node = document.createElement("div");
new_node.appendChild(two_a);
one_a.insertBefore(new_node, two_b);
console.log(one_a.innerHTML);
<body>
<div class="order-1-a">
<div class="order-2-a">
<div class="order-3-a"></div>
</div>
<div class="order-2-b"></div>
<div class="order-2-c"></div>
<div class="order-2-d"></div>
</div>
<div class="order-1-b"></div>
</body>
This provides the structure you're looking for (albeit not displayed well with console.log()).
Also, please be aware that class names cannot start with numbers, and may yield unexpected results. I've updated most of your classes to start with order in my example, as is with your order-1-a class.
Hope this helps!
You can create a general wrapping function based on a selector. It should get the subject node, then its parent and either it's next sibling or null if there isn't one.
Then create an element of the required type, append the subject node and insert it before the next sibling or as the last node if there wasn't one.
PS.
I've modified the class names to be valid, they can't start with a digit.
// Wrap element with selector in element with tagName
function wrapEl(selector, tagName) {
var node = document.querySelector(selector);
// If there is no subject node, return
if (!node) return;
// Get parent and sibling (or null if there isn't one)
var parent = node.parentNode;
var sibling = node.nextSibling;
// Append stuff
var wrapper = document.createElement('tagName');
wrapper.textContent = 'inserted wrapper'; // Just to show it's there
wrapper.appendChild(node);
parent.insertBefore(wrapper, sibling);
}
window.onload = function() {
wrapEl('.order-2-a', 'div');
}
<body>
<div class = "order-1-a">
<div class = "order-2-a">
<div class = "order-3-a"></div>
</div>
<div class = "order-2-b"></div>
<div class = "order 2-c"></div>
<div class = "order 2-d"></div>
</div>
<div class = "order-1-b"></div>
</body>
With the following code, I'm getting the values of "id"(almost 35), and then add 1 to each "id", so 1 will be 2 and so on. Where I'm stock, it is on how to replace that id number in the html.
This is the code that use to get the values of each id, then I push them into an array, then I run another "for loop" to add 1 to each value, but I don't how to return them to the html.
var x = document.getElementsByClassName('p-divs');
var portfolio = new Array;
for (var i = 0; i < x.length; i++)
{
var y = document.getElementsByClassName('p-divs')[i].getAttribute('id');
portfolio.push(y);
}
console.log(portfolio);
var portfolio2 = new Array;
for (var i = 0; i<portfolio.length; i++)
{
var newId;
newId = parseInt(portfolio[i]) + 1;
portfolio2.push(newId);
}
console.log(portfolio2);
<div class="col-lg-3 col-md-3 col-sm-6 col-xs-12 p-divs" id="1">
<div class="portfolio">
<center>
<img src="images/pace.png" width="230" height="190" alt="" class="img-responsive">
</center>
</div>
</div>
Since you're using jQuery library the code could be simple than what you've so far using .each() method :
$('.p-divs').each(function(){
$(this).attr('id', Number(this.id) + 1);
});
Or shorter using using .attr() method callback like :
$('.p-divs').attr('id', function(){
return Number(this.id) + 1;
});
The more clear version could be :
$('.p-divs').each(function(){
var current_id = Number(this.id); //Get current id
var new_id = current_id + 1; //Increment to define the new one
$(this).attr('id', new_id); //Set the new_id to the current element 'id'
});
Hope this helps.
$(function(){
$('.p-divs').attr('id', function(){
return Number(this.id) + 1;
});
//Just for Debug
console.log( $('body').html() );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="p-divs" id="1">
<div class="portfolio">
<center>Image 1</center>
</div>
</div>
<div class="p-divs" id="2">
<div class="portfolio">
<center>Image 2</center>
</div>
</div>
<div class="p-divs" id="3">
<div class="portfolio">
<center>Image 3</center>
</div>
</div>
<div class="p-divs" id="4">
<div class="portfolio">
<center>Image 4</center>
</div>
</div>
Using native javascript, just use getattribute's opposite: setAttribute
for (var i = 0; i < x.length; i++)
{
var y = document.getElementsByClassName('p-divs')[i].getAttribute('id');
y++;
document.getElementsByClassName('p-divs')[i].setAttribute("id",y);
}
var j = document.getElementsByClassName('p-divs');
for (var i = 0; i < x.length; i++) {
j[i].id = portfolio2[i];
}
Add this to the end of your code. Vanilla JS.
j will be an array of your divs, i will keep count of which div we're on, and we are simply accessing the "id" of each element in the "j" array and updating it to the corresponding value in your pre-populated "portfolio2" array.
Hope this helps!
P.S.- I would also recommend that instead of using 'new Array' to instantiate your arrays, you use the array literal notation '[]'. This is more concise and also avoids needing to put (); after Array.
I'd suggest, assuming I'm not missing something, and that you're able to us ES6 methods:
// converting the NodeList returned from document.querySelectorAll()
// into an Array, and iterating over that Array using
// Array.prototype.forEach():
Array.from( document.querySelectorAll('.p-divs') ).forEach(
// using an Arrow function to work with the current element
// (divElement) of the Array of elements,
// here we use parseInt() to convert the id of the current
// element into a number (with no sanity checking), adding 1
// and assigning that result to be the new id:
divElement => divElement.id = parseInt( divElement.id, 10 ) + 1
);
Note that updating, changing or otherwise modifying an id shouldn't be necessary in most circumstances, and having a purely numeric id may present problems for CSS selecting those elements (it's valid, but only in HTML 5, but will still be problematic).
for(i=0;i<$('.p-divs').length;i++){
newId= parseInt($($('.p-divs')[i]).attr('id'))+1;
$($('.p-divs')[i]).attr('id',newId)
}
Using Jquery attr