Selecting dynamically added classes in Javascript - javascript

I'll try to keep the question short and clear as mush as possible. I will really appreciate every help I can get but really important, is a solution in vanilla Javascript. So here come;
I created some elements (div and p) and added classes to these dynamically created elements using javascript. So that when the HTML is opened in the browser, these elements are added based on some actions.
Here is the HTML below:
<div class="work-container-outer"></div>
That is all the HTML there is.
Here is the Javascript code used to add the elements and the classes;
for (const items of areaOfWork) {
//create elements---------------------------------------------------------------
let workContainer, workAreaDiv, workTitle, pTitle;
workContainer = document.createElement('div');
workAreaDiv = document.createElement('div');
workTitle = document.createElement('div');
pTitle = document.createElement('p');
//add classes--------------------------------------------------------------------
workContainer.classList.add('work-container');
workAreaDiv.classList.add('work-area-div');
workTitle.classList.add('work-title');
//append as necessary------------------------------------------------------------
workTitle.append(pTitle);
workAreaDiv.append(workTitle);
//append workAreaDiv
workContainer.append(workAreaDiv);
//append the above to the main from the selector
workContainerOuter.append(workContainer);
//fill in with content from the database------------------------------------------
pTitle.innerHTML = items.title;
}
So all these elements created were appended together and finally added to the div container in the HTML file.
Here is what the HTML file looks like in the console after these stuffs has been added:
<div class="work-container-outer">
<div class="work-container">
<div class="work-area-div">
<div class="work-title">
<p>Promoting energy efficiency</p>
</div>
</div>
</div>
</div>
The issue now is, when I try to queryselect these dynamically created elements with their added classes, I get null. Therefore, I can't do anything with them. For example, when I try to select work-area-div, it returns null even though now i
Thank you for reading up to this point and I will really appreciate every assistance here. Thank you all :)

You can simplify your script considerably if you set it up with a template. In HTML5 and modern browsers you can use the new <template> element for this. As this element does not yet work reliably in all browsers, I have used the <script> here in exactly the same way:
const block=document.getElementById('tmpl').innerHTML,
parr=["Promoting energy efficiency",
"Make products repairable/sustainable",
"Do other useful stuff"
];
document.querySelector(".work-container-outer")
.innerHTML=parr.map(p=>block.replace("#",p)).join("<hr>");
// scan the new structure for all `p` elements:
console.log( [...document.querySelectorAll('p')].map(p=>p.textContent).join("\n"));
div {background-color:#8882; padding:10px}
<div class="work-container-outer"></div>
<script type="text" id="tmpl"
><div class="work-container">
<div class="work-area-div">
<div class="work-title">
<p>#</p>
</div>
</div>
</div>
</script>
The generated elements can be found just like any other elements in the DOM, as you can see from the console output.

Related

Add complexe Javascript array elements to HTML [duplicate]

I have a template:
function useIt() {
var content = document.querySelector('template').content;
// Update something in the template DOM.
var span = content.querySelector('span');
span.textContent = parseInt(span.textContent) + 1;
document.querySelector('#container').appendChild(
document.importNode(content, true));
}
<button onclick="useIt()">Use me</button>
<div id="container"></div>
<template>
<div>Template used: <span>0</span></div>
<script>alert('Thanks!')</script>
</template>
You can try the code here.
This code basically copies the template(html5 templates does not render on your screen) into another div. This allows you to reuse the DOM.
Problem: The line "span.textContent = parseInt(span.textContent) + 1;" changes the template code directly. I need to manipulate the content DOM and clone it into the container, without changing the template. This is very important since if I want to reuse the code, I need it to stay the same.
I have tried multiple ways to use jQuery to mimic the above javascript code, but I can't manage to figure it out. It would be better if there is a jQuery way.
If you NEED to use the new <template> tag, then you are mildly stuck . . . your cleanest alternative is to use importNode to bring in the content and then modify it after it's been appended.
Assuming that the templated code is realtively small, this should happen fast enough that you would never notice the difference in approach, though, in this specific example, the alert(), would delay the change of the content, so you would see "0", until you clicked "Okay", and then it would update to "1".
The code change for that would be:
function useIt() {
var content = document.querySelector('template').content;
var targetContainer = document.querySelector('#container');
targetContainer.appendChild(document.importNode(content, true));
var $span = $(targetContainer).find("div:last-of-type").find("span");
$span.text(parseInt($span.text() + 1));
}
If you are not married to the idea of <templates>, you could use jQuery's clone() method to do what you want to do, very easily . . . but, clone does not "see" the content of a <template>, due to the special nature of that particular element, so you would have to store the templated code some other way (JS variable, hidden div, etc.).
HOWEVER, this method will not work if you need to clone a script, the way that a <template> will. It will not trigger any script code in the "template container" element when the cloned version is created or appended. Additionally, if you store it in a hidden <div>, any script code in the "template container" element will trigger immediately on page load.
A simple version of the code for the clone() approach would look something like this:
function useIt() {
var $content = $("#template").clone();
var $span = $content.find("span");
$span.text(parseInt($span.text()) + 1);
$content.children().each(function() {
$("#container").append($(this));
});
}
Assuming that your template was:
<div id="template" style="display: none;">
<div>Template used: <span>0</span></div>
<script>alert('Thanks!')</script>
</div>
You could also move the <script>alert('Thanks!')</script> out of the template and into the script section (after you completed the "append loop"), to achive the desired alert functionality, if you wanted to.
It's an old question, but, did you try cloneNode(true)? It works on templates, as this:
var span = content.querySelector('span').cloneNode(true)
regards.

Changing inner HTML of a button with dynamic id

On a project I'm working on, a HTML file is defining a Javascript template used on selection buttons. All buttons have a "Change..." label that I want to localize (set dynamically). In other cases I'm searching for the element ID and setting the InnerHTML accordingly. But in this case, the ID of the buttons are defined dynamically. Is it possible to have a text element inside the button element, search for this element, and set its InnerHTML value?
<script id="optionSelectionTemplate" type="text/x-handlebars-template">
<div class="sub-section option-selection">
{{#if name}}<h4>{{name}}</h4>{{/if}}
<div class="current"></div><button class="button" id="{{id}}" data-action-id="{{id}}">Change...</button>
</div>
</script>
I've been searching this for a while now. But given that my forte is not web development, I'm not really sure what to search for...
You may be able to get the button element(s) by its class instead; for example:
var x = document.getElementsByClassName("button");
As you suggested, you can improve your selection's precision by first getting the 'optionSelectionTemplate' element(s) like so:
var x = document.getElementById("optionSelectionTemplate").getElementsByClassName("button");
Or if you prefer:
var x = document.getElementById("optionSelectionTemplate").getElementsByTagName("button");
Here are some links for more on these method:
https://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp
https://www.w3schools.com/jsref/met_document_getelementsbytagname.asp
Depending on how dynamic your localization should become, you could also specify the text inside a (locale-dependent) CSS as in https://jsfiddle.net/1gws5kat/ :
[HTML]
<button class="button btn_change" id="{{id}}" data-action-id="{{id}}"></button>
[CSS]
.btn_change:before { content: "Change..."; }
In particular when dealing with a large number of identically-named elements (i.e. many "Change" buttons), this might be pretty handy.
You find those btns by this command:
var btnlist= $(':button')
This Camano get you all button in your html file, then loop ton in and apply your changing.
Before call this command, jquery must be install.

Remove any specific html code using javascript

In the past I used Google Developer Console to delete some specific divs on a page. I could do it manually of course but in some cases where the divs where many I had to use the console. I had a single line code that did the job (I found it while searching the internet) but I lost my note.
So how can I delete using javascript any html code (by copy pasting the code).
Something like:
elements = $('<div ... </div>');
elements.remove();
OR
$('<div ... </div>').remove();
Any ideas? I am not an expert in javascript (obviously) and I've been searching stackoverflow for hours without finding anything that works.
UPDATE: I think some people might get confused with my question. Google developer console accepts javascript command lines. So even though I ask for javascript I will use the code on the google developer console.
UPDATE 2 :
Here is an example of a div I need to delete. Keep in mind I want to copy paste the entire code in the javascript code. Not just identify the div.
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
It's the data-entry-status="declined" that makes that div unique so I can't just identify the div using an id selector or a class selector. I need to put the entrire thing there and remove it.
I tried:
$('<div class="entry-status-overlay" data-entry-status="declined"><div class="entry-status-overlay__inner"><span class="entry-status-overlay__title">Declined</span></div></div>').remove();
It didn't remove the div.
Try to search the dom by its outerHTML.
function deleteDomByHtml(html){
html=html.replace(/\s/g,'');
$("*").each(function(){
if(this.outerHTML.replace(/\s/g,'')===html){
$(this).remove();
}
});
}
And try this line on this page:
deleteDomByHtml(`<span class="-img _glyph">Stack Overflow</span>`);
You cannot do by simply pasting the code. That will remove all the div element.
You may need a specific selector like id,class or child to specific parent to remove the element from the dom.
Consider this case the divs have common class but the data-entry-status is different. So you can get the dom using a selector and then check the dataset property.
For demo I have put it inside setTimeout to show the difference. In application you can avoid it
setTimeout(function() {
document.querySelectorAll('.entry-status-overlay').forEach(function(item) {
let getStatus = item.dataset.entryStatus;
if (getStatus === 'declined') {
item.remove()
}
})
}, 2000)
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
<div class="entry-status-overlay" data-entry-status="accepted">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">accepted</span>
</div>
</div>
Just add any attribute with [] and it will remove the element.
$('[class="entry-status-overlay"]').remove();
/*OR*/
$('[data-entry-status="declined"]').remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
function del(){
var h = document.body.outerHTML;
h = h.match('<div>...</div>');
h.length--;
return h;
}
I guess this will work just give it a try... i tried on browser console and it worked, this way you can match the exact you want.
I might as well add my take on this. Try running this in your console and see the question vanish.
// convert the whole page into string
let thePage = document.body.innerHTML,
string = [].map.call( thePage, function(node){
return node.textContent || node.innerText || "";
}).join("");
// I get some string. in this scenario the Question or you can set one yourself
let replacableCode = document.getElementsByClassName('post-layout')[0].innerHTML,
string2 = [].map.call( replacableCode, function(node){
return node.textContent || node.innerText || "";
}).join("");
// replace whole page with the removed innerHTML string with blank
document.body.innerHTML = thePage.replace(replacableCode,'');
If you want to identify divs with that particular data attribute, you can use a data-attribute selector. In the example below, I've used a button and click event to make the demo more visual, but in the console the only line you'd need would be:
$('div[data-entry-status="declined"]').remove();
$(function() {
$("#testbutton").click(function() {
$('div[data-entry-status="declined"]').remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
<div id="x">Some other div</div>
<button type="button" id="testbutton">Click me to test removing the div</button>
See https://api.jquery.com/category/selectors/attribute-selectors/ for documentation of attribute selectors.
P.S. Your idea to paste some raw HTML into the jQuery constructor and then execute "remove" on it cannot work - you're telling jQuery to create an object based on a HTML string, which is, as far as it's concerned, a new set of HTML. It does not try to match that to something existing on the page, even if that exact HTML is in the DOM somewhere, it pays it no attention. It treats what you just gave it as being totally independent. So then when you run .remove() on that new HTML...that HTML was never added to the page, so it cannot be removed. Therefore .remove() has no effect in that situation.

Find the tag JavaScript is running in

Generating HTML source on backend, I am using separate independent widgets.
I am simply including pieces of markup like this to the resulting HTML output.
<div>
I want to work with this DOM element
<script>
new Obj(/*but I can't get this <div> as a parameter! */);
</script>
</div>
I'm looking for a way to find the DOM element in which the obj is created (Without any unique IDs). This would add flexibility to my app and speed up the development. But is that technicaly possible in JavaScript?
You could seed an element in there and then get it's parent, and then remove the element.
<div>
I want to work with this DOM element
<script>
document.write("<div id='UniqueGUID_3477zZ7786_' style='display:none;'></div>");
var thatDivYouWanted;
(function(){
var target = document.getElementById("UniqueGUID_3477zZ7786_");
thatDivYouWanted = target.parentNode;
target.parentNode.removeChild(target);
})();
new Obj(/*but I can't get this <div> as a parameter! */);
</script>
</div>
The following code works:
<script>
function Obj(color) {
var scriptTags = document.getElementsByTagName("script");
var scriptTag = scriptTags[scriptTags.length - 1];
// find parent or do whatsoever
var divTag = scriptTag.parentNode;
divTag.style.backgroundColor = color;
}
</script>
<div>
I want to work with this DOM element
<script>new Obj("green");</script>
</div>
<div>
I want to work with this DOM element
<script>new Obj("yellow");</script>
</div>
<div>
I want to work with this DOM element
<script>new Obj("lime");</script>
</div>
This method has very simple code and has almost zero impact on performance.
Note: I am pretty sure this won't work IE6 (as far as I remember it does not support manipulating open tags).
I believe your approach is not ideal. If you're trying to obtain the <div>, it should be done programmatically in a conventional way using JavaScript and the API's that empower you to query the target <div>
Instead of executing inline, you can execute in a separate scope in a controlled way (DOM Ready then Query then Your Method). You can target your div by using an ID, CSS class name, or any other CSS selector in JavaScript.
This allows you to pretty much do the follow anywhere you want, not inline.
// on dom ready...
var div = document.getElementById('myDiv'), // replace with any other selector method
myObject = new Object(div);
Need to find your div? https://developer.mozilla.org/en-US/docs/DOM/Document.querySelectorAll
If you know beforehand how the page will be structured, you could use for example:
document.getElementsByTagName("div")[4]
to access the 5th div.

jquery add not-in-dom element in a ordered stack (in-dom elements)

I have an unexpected problem.
HTML
<div id="div1" class="myDiv"></div>
<div id="div2" class="myDiv"></div>
<div id="div3" class="myDiv"></div>
<div id="div5" class="myDiv"></div>
<div id="div6" class="myDiv"></div>
JS
$(function() {
var $divs = $('.myDiv');
// create new div not in tree
var $div = $('<div/>').attr("id","div4").addClass('myDiv');
// insert #div4 in right position. Only in stack, not in dom tree.
$divs = $divs.slice(0,3).add($div).add($divs.slice(3));
console.log($divs);
});
output
[div#div1.myDiv, div#div2.myDiv, div#div3.myDiv, div#div5.myDiv, div#div6.myDiv, div#div4.myDiv]
Warning: I DON'T want to insert it in dom tree (like $div.appendBefore($divs[3])), I just want append it in my stack $divs.
I thought that this stack was an ordered list. So, my goal was to create on fly a #div4 and insert it inĀ $divs stack without insert it in DOM tree. The insert works but it seems that jquery ignore the order given.
I've other solutions for this problem (i.e. append in dom with a display none), ok.. but:
My question is: why? It's a bug for some cache optimization, or it's a documented feature?
I've also tried:
var $newDivs = $();
$divs.each(function(i,e) {
if(i==3)
$newDivs = $newDivs.add($div);
$newDivs = $newDivs.add(e);
});
console.log($newDivs);
but the output is the same.
EDIT: Just for completeness: this was just a fast hack for a complex code. I know that the purpose is not clean
That's not the purpose of a jQuery object. KEep your data-structures straight; I'm not sure how the concept of a 'stack' came into this at all. Use the regular built in JS arrays (which keep items ordered):
$(function() {
// make an array of existing divs
var divs = $('.myDiv').toArray();
// create new div
var newDiv = $('<div/>').attr("id","div4").addClass('myDiv').get(0);
// insert newDiv at index 4 in array
divs.splice(4, 0, newDiv);
// Rejoice.
console.log(divs);
});
One more variant of nbrooks answer
// get regular array of matched DOM nodes
var divs = $('.myDiv').toArray();
// require you to find out on which position you need to put your new div
divs.splice(2, 0, $('<div/>').attr("id","div4").addClass('myDiv').get(0))
// again wrap in jQuery to get what you need
divs = $(divs);
As of jQuery 1.4 the results from .add() will always be returned in document order (rather than a simple concatenation).
It's documented behaviour, it's not a normal array.
http://api.jquery.com/add/
Really seems not a jquery behaviour but more a javascript browser's native code implementation as
i get these results, depending of which browser is used (windows7):
Firefox and IE9: 1,2,3,5,6,4
Safari : 1,2,3,4,5,6
Chrome: 4,1,2,3,5,6

Categories