Adding new element to nested classes - javascript

I need to use JS to create a new element within specific nested classes in HTML. So in this example, I need to create a new span with the class of "paw-print" only where the "collies" class is nested within "dogs".
Here's what I have so far: https://jsfiddle.net/p50e228w/6/
The problem is that my current JS works on the first instance, but not on the other. I currently have document.getElementsByClassName set to "collies" but I need to target that class only when it's inside the parent "dogs" class.
What am I missing here?
var span = document.createElement("span");
span.className = "paw-print";
var wrap = document.getElementsByClassName("collies");
for(var i = 0; i < wrap.length; i++) {
wrap[i].appendChild(span);
}
I can use jQuery, but I've been using vanilla JS just because I'm such a noob and want to understand what my code is doing.

There are 2 issues with your code.
Positioning : The images are being given a absolute position, and they rest in the same position based on the page layout. So set relative positioning for the parent container.
CSS
.relative {
position: relative;
}
You need to append that to parent element which is collie here.
You can use querySelectorAll to find the nested relation ship that you are looking for.
var collies = document.querySelectorAll('.dogs .collies');
for (var i = 0; i < collies.length; i++) {
var span = document.createElement("span");
span.className = "paw-print";
collies[i].appendChild(span);
}
Fiddle

If you want to append to parent ( element with class 'dog')
$('.dogs .collies').each(function() // finds elements in the dom with parent element 'dog' and it's child element 'collies'
{
$(this) // 'this' would represent 'collies' element
.closest('.dogs') // .closest('.dogs') would get it's nearest occurence in the heirarchy ( basically it's parent )
.append($('<span/>', { class: 'paw-print'})); // create a dynamic span element and append to 'this'
});
If you want to append to child( element with class 'collies')
$('.dogs .collies').each(function()
{
$(this).append($('<span/>', { class: 'paw-print'}));
});
In addition to this, you also need to set position: relative as pointed out by Rob.
Example : https://jsfiddle.net/DinoMyte/1zxn8193/1/

Related

How to select an element with specific css value in javascript

I want to select an element if it has a css as display block then do this function. If the element has the css as display block then remove ('hide') class from the header class.. This is what I want to do.. Any help?
Well, there are two solutions depending on what you want:
Solution 1
Looping through all elements and removing hide class from the current element if it has display block value in its style.
var elements = document.getElementsByTagName("*");
for(let i = 0; i < elements.length; i++) {
if(elements[i].style.display == "block") {
elements[i].classList.remove("hide");
}
}
Solution 2
Getting the reference of the element via HTML id.
var element = document.getElementById("YourElementID");
if(element.style.display == "block") {
element.classList.remove("hide");
}
You can define an id like this in your HTML file:
<div id="YourElementID">Div</div>
I am assuming that you want to determine if the element has the "hide" class by checking its display style. you don't need to do that, you can easily check its class list by using the following code:
element.classList.contains("hide");
There are several ways of collecting all the elements with display: block and i am not sure, which one performs best - or whether it performs good at all.
If you want all the Element instances of the page, which have a computed style of display: block you can do something like:
var $els = Array.from(document.body.querySelectorAll('*')).filter(function($el) {
return getComputedStyle($el).display === 'block';
});
Or ES6:
const $els = Array.from(document.body.querySelectorAll('*')).filter($el => getComputedStyle($el).display === 'block');
If you want the Element instances which have display: block literally set in the style-attribute, you have to do something like this:
var $els = Array.from(document.body.querySelectorAll('*')).filter(function($el) {
return $el.style.display === 'block';
});
I think it would perform better, if the selector in querySelectorAll() would be a little more specific.
Another option would be to use the TreeWalker API, but then you have to do a mutation, because you have to iterate over all the elements and push them to an array:
var $els = [];
walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);
while (walker.nextNode()) {
if (getComputedStyle(walker.currentNode).display === 'block') {
$els.push(walker.currentNode);
}
}
Once you have all your elements, you can do something with them.
A little bit more information would be helpful, especially what exactly you want to achieve, once you have the elements, because then i could also provide more help. Maybe provide a code example?

Insert Parents for all links in menu list

I am trying to insert h2 tags and make them parents for all links inside of a vertical navigation menu.
I can do this for a single element but now I want to do it for all elements within a menu.
JavaScript:
var menu_item = document.querySelector("div.righ-nav-style1 ul li a");
// `menu_item` is the element you want to wrap
var parent = menu_item.parentNode;
var wrapper = document.createElement('h2');
wrapper.className = 'category_links';
// set the wrapper as child (instead of the 'menu_item')
parent.replaceChild(wrapper, menu_item);
// set 'menu_item' as child of wrapper
wrapper.appendChild(menu_item);
I want to use the replaceChild() and appendChild() methods within a forloop for all menu items.
Any help would be greatly appreciated!
EDIT: I actually just found a solution to my problem.
Edited JavaScript:
// Replaced 'querySelector()' with 'querySelectorAll()' to get all elements
var menu_item = document.querySelectorAll("div.righ-nav-style1 ul li a");
// Created 'for' loop to use 'replaceChild()' and 'appendChild()' methods for all elements
for (var i = 0; i < menu_item.length; i++){
var parent = menu_item[i].parentNode;
var wrapper = document.createElement('h2');
wrapper.className = 'category_links';
// set the wrapper as child (instead of the 'menu_item')
parent.replaceChild(wrapper, menu_item[i]);
// set 'menu_item' as child of wrapper
wrapper.appendChild(menu_item[i]);
}

javascript issue getElementById to modify CSS

I have an issue about getElementById.
Here is the part of the javascript code that causes a problem:
var elmt = document.getElementById("cardSlotsJoueur");
elmt.style.backgroundImage = "url('images/backcard.png')";
I wanted to modify this (Css) :
#cardSlotsJoueur div {
But it actually modifies #cardSlotsJoueur {
Could you help me to find a way to modify the first one with getElementById ?
Thanks !
If you only want to modify the first div within the element with id=cardSlotsJoueur, you can use this:
var elmt = document.getElementById("cardSlotsJoueur").getElementsByTagName("div")[0];
To target #cardSlotsJoueur div it's better to use querySelector method which would retrieve children div element of the #cardSlotsJoueur container:
var elmt = document.querySelector("#cardSlotsJoueur div");
If you expect multiple div elements under the #cardSlotsJoueur then you need to get them all first
var elmt = document.querySelectorAll("#cardSlotsJoueur div");
and then set backgroundImage to each in the for loop.
You need to find div elements within #cardSlotsJoueur:
var elmt = document.getElementById("cardSlotsJoueur");
var divs = elmt.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].style.backgroundImage = "url('images/backcard.png')";
}
Probably the best way to do what you want is to use a class with the required styling and add it to the element. But as an alternative, you can add a rule to the last style sheet, e.g.
function addBackground() {
var sheets = document.styleSheets;
// If there are no style sheets, add one
if (!sheets.length) {
document.head.appendChild(document.createElement('style'));
}
// The sheets collection is live, if a new sheet was needed, it's automatically a member
sheets[sheets.length - 1].insertRule('#cardSlotsJoueur div{background-image:url("images/backcard.png")');
}
You can make it generic:
function addRule(ruleText) {
var sheets = document.styleSheets;
if (!sheets.length) {
document.head.appendChild(document.createElement('style'));
}
sheets[sheets.length - 1].insertRule(ruleText);
}
and call it like:
addRule('#cardSlotsJoueur div{background-image:url("images/backcard.png")');

How do I repeat div classes using JavaScript only?

Okay, I'm unsure how to word the question, but basically I want to repeat my div containers that have a class of "blocks" using only javascript, no HTML (other than the HTML needed to start a page). IF I were doing this using HTML the result should look exactly like this.
http://jsfiddle.net/nqZjB/1/
<div class = "blocks"> <!-- Repeats three times -->
However as I stated in the description I do not want to use any HTML, so here is my fiddle with javascript only.
How do I make div class blocks repeat three times as in my HTML example using only javascript? Of course in real life I would use HTML for this as javascript is unnecessary, but I want to do this in pure javascript so I can learn. Also as a sidenote if you have a better way as to how I should have worded the question, let me know.
Thanks (:
http://jsfiddle.net/TbCYH/1/
It's good you see the use of making a function of a re-occurring pattern.
Before posting it in StackOverflow, have you tried doing it yourself?
jsfiddle: http://jsfiddle.net/kychan/W7Jxu/
// we will use a container to place our blocks.
// fetch the element by id and store it in a variable.
var container = document.getElementById('container');
function block(mClass, html) {
//extra html you want to store.
return '<div class="' + mClass + '">' + html + '</div>';
}
// code that loops and makes the blocks.
// first part: creates var i
// second: condition, if 'i' is still smaller than three, then loop.
// third part: increment i by 1;
for (var i = 0; i < 3; i++) {
// append the result of function 'block()' to the innerHTML
// of the container.
container.innerHTML += block('block', 'data');
}
Edit: JS has changed a lot since the original post. If you do not require compatibility, use const, template literals, class and querySelector to make the code a bit cleaner. The following code has a Builder class and assumes there is a div with ID 'container':
// create class builder.
class Builder {
// create constructor, accept an element selector, i.e #container.
constructor(targetContainerSelector) {
// search element by given selector and store it as a property.
this.targetContainer = document.querySelector(targetContainerSelector);
}
// method to append to innerHtml of target container.
appendUsingInnerHtml(divAsHtml) {
this.targetContainer.innerHTML += divAsHtml;
}
// method to append to target container using DOM elements.
appendUsingDom(divAsDom) {
this.targetContainer.appendChild(divAsDom);
}
}
// constant to hold element selector.
const myTargetContainer = '#container';
// constant to set the class if required.
const myDivClass = 'my-class';
// constant to hold the instantiated Builder object.
const builder = new Builder(myTargetContainer);
// loop 3 times.
for (let i=0; i<3; i++) {
// call method to append to target container using innerHtml.
builder.appendUsingInnerHtml(`<div class="${myDivClass}}">innerhtml div text</div>`);
// OR.. build using DOM objects.
// create the div element.
const div = document.createElement('div');
// create text element, add some text to it and append it to created div.
div.appendChild(document.createTextNode('dom div text'));
// call method to append div DOM object to target container.
builder.appendUsingDom(div);
}
Please note: Every time something is added to the DOM, it forces the browser to reflow the DOM (computation of element's position and geometry).
Adding everything at once, improve speed, efficiency and performance of a code.
(ref: document.createDocumentFragment)
window.onload = Create();
function Create() {
// create the container
var mainContainer = document.createElement('div');
mainContainer.id = 'mainContainer';
// add all style in one go
mainContainer.setAttribute('style', 'witdht: 400px; height: 200px; border: 2px solid green; margin-left: 20px;');
var divBlocks1 = document.createElement('div');
divBlocks1.className = 'blocks';
divBlocks1.setAttribute('style', 'width: 100px; heigth: 100px; border: 1px solid black; margin-left: 20px; margin-top: 10px; floar: left;');
var divBlocks2 = divBlocks1.cloneNode(false); // copy/clone above div
var divBlocks3 = divBlocks1.cloneNode(false); // copy/clone above div
// everything is still in memory
mainContainer.appendChild(divBlocks1);
mainContainer.appendChild(divBlocks2);
mainContainer.appendChild(divBlocks3);
// now we append everything to the document
document.body.appendChild(mainContainer);
}
Good luck
:)
for(var d=0;d<10;d++){
var aDiv = document.createElement('div');
aDiv.className = "block";
document.getElementsByTagName('body')[0].appendChild(aDiv);
}
Rather than creating the elements before hand and then appending them to the main container, consider dynamically creating and appending them in a loop.
http://jsfiddle.net/TbCYH/6/
for(var i = 0; i < 3; i++) {
var divBlock = document.createElement("div");
divBlock.className = "blocks";
mainContainer.appendChild(divBlock);
}
In the above code snippet a div is being created and appended for each iteration of the loop (which is set to cease at 3).
Also if possible, always use CSS classes rather than modifying the styles for each div directly.

How to append an element, all its children, and all classes of the parent and children with jQuery

I have a function that is successful in removing an element and appending it elsewhere on the page as successful. The problem is that as soon as the document is ready jQuery adds classes and attributes to the children that upon moving are lost. I need these classes and attributes to remain after removing and appending. I have thought about calling the original function that adds the classes, but the problem is they are key based and rely on their position prior to the move, calling it after changes the key and thus will add brand new and different classes.
The classes adding jQuery is pretty standard:
$(function(){
$("div").each(function(key){
if ($(this).hasClass("container")){
$(this).find("ul").addClass("parent" + key);
$(this).find(".container-item").attr("parentClass", ".parent" + key);
};
});
});
The remove/append function:
function copy_item(draggable, target){
var account = clone_items(draggable);
//$('#'+name.uid).remove();
$('#'+name.uid).hide();
target.append(make_div(name, true, true));
//$(draggable).children().attr("class", ($(draggable).children().attr("class")));
}
function make_div(name, drag, drop){
var newdiv = document.createElement('div');
newdiv.setAttribute('id', name.uid);
newdiv.appendChild(make_h3(name.username));
ul = document.createElement('ul');
ul.setAttribute("class", "domain_list");
newdiv.appendChild(ul);
for (j = 0; j < name.domains.length; ++j) {
ul.appendChild(make_li(name.domains[j], drag));
}
return newdiv;
}
The end result in the HTMl is basically:
<div class="container">
<ul class="parent0">
<li parentClass="parent0">
<li parentClass="parent0">
When recreating this structure, I need to have the class "parent0" and the parentClass attribute intact. Above you can see I've tried hiding the element, ensuring that it still stays a valid element with the correct classes/attributes, but in the end that still didn't work out. Ideally, I could remove the element entirely and recreate it with the correct classes.
If I am correct in my understanding of what you are trying to do, you do not need to .remove() and recreate the element in order to move it. You can just do this:
function copy_item(draggable, target) {
// not sure what this variable is for
// as you don't seem to be using it?
var account = clone_items(draggable);
// ...however, appending an existing
// element to another will 'move' it
// and preserve all of it's properties
target.append($('#' + name.uid));
}

Categories

Resources