How do I repeat div classes using JavaScript only? - javascript

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.

Related

Wrap innerHTML in div

I have a JS function that updates descriptions of products when variables are changed. Here is where the element is updated.
Product.Config.prototype.updateProductShortDescription = function(productId) {
var shortDescription = this.config.shortDescription;
if (productId && this.config.childProducts[productId].shortDescription) {
shortDescription = this.config.childProducts[productId].shortDescription;
}
$$('#product_addtocart_form div.short-description').each(function(el) {
el.innerHTML = shortDescription;
});
};
Works great but would like to wrap the output in a div. Does anyone know a way or wrapping innerHTML in a tag before when updating it?
Thank you.
Don't use innerHTML if you're just setting text. It is incredibly insecure and will happily execute scripts and contact any server that the text you're using can instruct the browser to do by simply including some malicious HTML code.
Use the .textContent property instead.
But better yet, since it looks like you're using jQuery anyway, just use jQuery's built-in way to construct elements as needed:
let div = $(`<div></div>`).text(description);
$(`.my-element`).append(div);
And if you already have elements:
let update = $(`<div></div>`).text(description);
$(`#your.query-selector goes:here()`).empty().append(update);
(because jQuery lets you chain calls in a way that make them apply to every element in a selection, this will set that div-wrapped description as content for every element in the query result)
I don't know what your $$ function is from, but there is my proposal in vanilla JS:
const descriptionText = "my short description";
const descriptionElements = document.querySelectorAll('#product_addtocart_form div.short-description');
Array.from(descriptionElements).forEach(function(el) {
const newDiv = document.createElement('div');
newDiv.classList.add('customDiv');
newDiv.textContent = descriptionText;
el.appendChild(newDiv);
});
div {
border: 1px dotted silver;
padding: .5em;
margin: .25em;
}
<div id="product_addtocart_form">
<div class="short-description">1</div>
<div class="short-description">2</div>
<div class="short-description">3</div>
</div>
Edit:
After reading your first comment, in your code you just have to replace:
el.innerHTML = shortDescription;
by:
const descWrapper = document.createElement('div');
descWrapper.innerHTML = shortDescription;
el.appendChild(descWrapper);

Adding new element to nested classes

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/

Accessing items in Javascript Node List to alter image

I am trying to create the same effect of CSS Hover but with Javascript code (for the purpose of learning Javascript and for future use). So on mouseover, I would like the individual image to increase opacity.
The code I have written below does not work. Please see comments for explantion regarding what I am trying to do;
<script>
//gets all img tags (qu.20)
var images = document.getElementsByTagName("img")
// Create new element with id "newNode" for the individual node to go into
var node = document.body.createElement("newNode")
// Add the new element into the html document
document.body.appendChild(newNode)
// Attach var i to the individual nodes and set src of new element as that node
function overImage () {
for (var i=0; i<images.length; i++) {
document.getElementById("newNode")
document.body.newNode.src = images.item(i)
}
}
// function to create a new class with same attributes as original when mouse leaves image
function leaveImage () {
for (var i=0; i<images.length; i++) {
document.getElementById("newNode")
document.body.newNode.src = images.item(i)
document.body.newNode.className = " leave"
}
}
</script>
<html>
<img src="image1.gif" onmouseover="overImage()" onmouseout="leaveImage()" alt="image" />
<img src="image2.gif" onmouseover="overImage()" onmouseout="leaveImage()" alt="image" />
</html>
<style>
img { opacity:0.5; }
#newNode { opacity:1; }
#newNode.leave { opacity:0.5; }
As an alternative, this code works but only on all images (ie. they all change opacity together, not individually.
<script>
function overImage () {
var selectImage = document.getElementsByTagName("img")
for (var i=0; i<selectImage.length; i++) {
selectImage[i].className = " over"
}
}
function leaveImage () {
var selectImage = document.getElementsByTagName("img")
for (var i=0; i<selectImage.length; i++) {
selectImage[i].className = ""
}
}
</script>
<style>
img { opacity:0.5; }
.over { opacity:1; }
</style>
Answers in Javascript only please with explanations. No jquery
You can do this in a much simpler manner, check this example:
var f = function(e) {
// the event target, can be any element in the page at this point
var t = e.target;
// check if the event target is an img element
if(t.tagName.toLowerCase() == 'img') {
// then toggle its active class
t.classList.toggle('active');
}
}
// add listeners to the window (or on whatever image container you have)
addEventListener('mouseover', f /* call this function f on mouseover */, false);
addEventListener('mouseout', f, false);
img { opacity: .5; }
.active { opacity: 1; }
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
This code is going to work no matter how many images you add after this. It eliminates for you to add calls to your JS functions (whose names you may choose to change) to the HTML, the need for messing with the DOM from JS, the need for looping in the JS. And as far as the CSS is concerned, it's not using ids for styling, so it's avoiding specificity issues.
Your issue appears to be right at the top, document.body.createElement("newNode") will give you a TypeError: undefined is not a function. The createNode method is on the #document node, not a HTMLElement.
Next, you create nodes by tag name, there is no such tag <newNode>, maybe you meant to create an <img>
var node = document.createElement("img");
Now you need to assign the id attribute to it,
node.setAttribute('id', 'newNode');
Next, you have to append node to your document tree (you're currently trying to append an undefined variable newNode)
document.body.appendChild(node);
Finally, your two functions overImage and leaveImage have several problems of their own;
They are performing document.getElementById but not remembering the result, instead trying to go through the DOM tree in an unusual way and also you're trying to assign a node as a src, when you probably want to assign a String
// outside loop
var node = document.getElementById("newNode");
// inside loop
node.src = images.item(i).src;
They loop over all of images each time, meaning you will always finally end up with node's src pointing at the value from the last item in images
Try linking up these listeners using foo.addEventListner(type, event_handler) where foo is a reference to each node you want to attach the event_handler to. This will let you access the mouseover or mouseout event in more detail, especially if event_handler looks at it's first argument which will be the event itself, or this which will be the node which invoked the handler.
Always check your console as the first step in debugging, it'll usually let you quickly narrow down your issue to the exact line with the problem

replace specific tag name javascript

I want to know if we can change tag name in a tag rather than its content. i have this content
< wns id="93" onclick="wish(id)">...< /wns>
in wish function i want to change it to
< lmn id="93" onclick="wish(id)">...< /lmn>
i tried this way
document.getElementById("99").innerHTML =document.getElementById("99").replace(/wns/g,"lmn")
but it doesnot work.
plz note that i just want to alter that specific tag with specific id rather than every wns tag..
Thank you.
You can't change the tag name of an existing DOM element; instead, you have to create a replacement and then insert it where the element was.
The basics of this are to move the child nodes into the replacement and similarly to copy the attributes. So for instance:
var wns = document.getElementById("93");
var lmn = document.createElement("lmn");
var index;
// Copy the children
while (wns.firstChild) {
lmn.appendChild(wns.firstChild); // *Moves* the child
}
// Copy the attributes
for (index = wns.attributes.length - 1; index >= 0; --index) {
lmn.attributes.setNamedItem(wns.attributes[index].cloneNode());
}
// Replace it
wns.parentNode.replaceChild(lmn, wns);
Live Example: (I used div and p rather than wns and lmn, and styled them via a stylesheet with borders so you can see the change)
document.getElementById("theSpan").addEventListener("click", function() {
alert("Span clicked");
}, false);
document.getElementById("theButton").addEventListener("click", function() {
var wns = document.getElementById("target");
var lmn = document.createElement("p");
var index;
// Copy the children
while (wns.firstChild) {
lmn.appendChild(wns.firstChild); // *Moves* the child
}
// Copy the attributes
for (index = wns.attributes.length - 1; index >= 0; --index) {
lmn.attributes.setNamedItem(wns.attributes[index].cloneNode());
}
// Insert it
wns.parentNode.replaceChild(lmn, wns);
}, false);
div {
border: 1px solid green;
}
p {
border: 1px solid blue;
}
<div id="target" foo="bar" onclick="alert('hi there')">
Content before
<span id="theSpan">span in the middle</span>
Content after
</div>
<input type="button" id="theButton" value="Click Me">
See this gist for a reusable function.
Side note: I would avoid using id values that are all digits. Although they're valid in HTML (as of HTML5), they're invalid in CSS and thus you can't style those elements, or use libraries like jQuery that use CSS selectors to interact with them.
var element = document.getElementById("93");
element.outerHTML = element.outerHTML.replace(/wns/g,"lmn");
FIDDLE
There are several problems with your code:
HTML element IDs must start with an alphabetic character.
document.getElementById("99").replace(/wns/g,"lmn") is effectively running a replace command on an element. Replace is a string method so this causes an error.
You're trying to assign this result to document.getElementById("99").innerHTML, which is the HTML inside the element (the tags, attributes and all are part of the outerHTML).
You can't change an element's tagname dynamically, since it fundamentally changes it's nature. Imagine changing a textarea to a select… There are so many attributes that are exclusive to one, illegal in the other: the system cannot work!
What you can do though, is create a new element, and give it all the properties of the old element, then replace it:
<wns id="e93" onclick="wish(id)">
...
</wns>
Using the following script:
// Grab the original element
var original = document.getElementById('e93');
// Create a replacement tag of the desired type
var replacement = document.createElement('lmn');
// Grab all of the original's attributes, and pass them to the replacement
for(var i = 0, l = original.attributes.length; i < l; ++i){
var nodeName = original.attributes.item(i).nodeName;
var nodeValue = original.attributes.item(i).nodeValue;
replacement.setAttribute(nodeName, nodeValue);
}
// Persist contents
replacement.innerHTML = original.innerHTML;
// Switch!
original.parentNode.replaceChild(replacement, original);
Demo here: http://jsfiddle.net/barney/kDjuf/
You can replace the whole tag using jQuery
var element = $('#99');
element.replaceWith($(`<lmn id="${element.attr('id')}">${element.html()}</lmn>`));
[...document.querySelectorAll('.example')].forEach(div => {
div.outerHTML =
div.outerHTML
.replace(/<div/g, '<span')
.replace(/<\/div>/g, '</span>')
})
<div class="example">Hello,</div>
<div class="example">world!</div>
You can achieve this by using JavaScript or jQuery.
We can delete the DOM Element(tag in this case) and recreate using .html or .append menthods in jQuery.
$("#div-name").html("<mytag>Content here</mytag>");
OR
$("<mytag>Content here</mytag>").appendTo("#div-name");

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