Javascript Class References in Html - javascript

Assuming I have a class class FooBar() {} with a method doSomething(){}, can I create and append a html element from within the class itself that calls doSomething() when clicked?. Here is a code snippet:
class FooBar{
constructor(options){this.options = options}
doSomething(){ /* onclick functionality */}
creator(){
let reference = `<div onclick="this.doSomething()"></div>`;
document.getElementByTagName('body')[0].innerHtml = reference;
}
}
I would now like to know the correct way of writing the let reference . . . line.

First, to attach the event listener you can't use innerHTML because onclick="this.doSomething()" in your string won't point to your class. You have to construct the element using document.createElement and append that using appendChild.
Second, when you attach the event listener, make sure the proper this is used (more on that in this other SO question). We'll just use a simple arrow function. We'll also use addEventListener instead of onclick which is more standard:
class FooBar{
constructor(options) { this.options = options; }
doSomething() { /* onclick functionality */}
creator() {
let div = document.createElement("div");
div.addEventListener("click", ev => this.doSomething( /* pass 'ev' here if you want */ ));
// it's ok to use div.innerHTML here to fill out the div instead of createElement/appendChild
document.body.appendChild(div);
}
}

Maybe try using addEventListener instead of using onclick on the tag
let newElement = document.createElement('div')
newElement.addEventListenser('click', () => console.log('clicked'))

Related

How can i add same multiple html element with js?

I want to build a note taker app with html css and js but when i want add second note there is a problem.
let myNote = "";
let myTitle = "";
let noteInput = document.getElementById("note-input");
let titleInput = document.getElementById("title-input");
let title = document.getElementById("title");
let note = document.getElementById("first-note-p");
let addButton = document.getElementById("addButton");
let removeButton = document.getElementById("remove-button");
let newDiv = document.createElement("div");
let newP = document.createElement("p");
let newH3 = document.createElement("h3");
let newButton = document.createElement("button");
let notePlace = document.getElementById("note-place");
let button = document.getElementsByTagName("button");
let div = document.getElementsByTagName("div");
let paragrapgh = document.getElementsByTagName("p");
let head3 = document.getElementsByTagName("h3");
let tally = 0;
const addNote = () => {
myNote = noteInput.value;
myTitle = titleInput.value;
notePlace.appendChild(newDiv);
div[tally].appendChild(newH3);
div[tally].appendChild(newP);
div[tally].appendChild(newButton);
notePlace = document.getElementById("note-place");
head3[tally].innerText = myTitle;
paragrapgh[tally].innerText = myNote;
button[tally + 1].innerText = "remove";
tally += 1;
};
const removeNote = () => {
title.innerHTML = "";
note.innerHTML = "";
};
addButton.onclick = addNote;
<h1>Take your notes</h1>
<input id="title-input" onfocus="this.value=''" type="text" value="title" />
<input id="note-input" onfocus="this.value=''" type="text" value="note" />
<button id="addButton">add</button>
<div id="note-place"></div>
I use addNote function to add a new note but for second note I encounter to the following error.
Cannot set properties of undefined (setting 'innerText')
at HTMLButtonElement.addNote (notetaker.js:37:26)
Sorry for my bad English.
The main problem with your attempt is that you're selecting the elements before actually creating and appending them to the DOM and that will lead to problems because those elements that were initially selected are no longer there when a new note is added.
The fix is fairly easy, select the elements at the time you create a new note. Actually, I won't just stop here and I will happily invite you to follow along with my answer as we approach your task (of making notes and showing them in the screen) in a better approach that, i think, will be more helpful than just giving a fix.
So, here's what we're going to do, we're firstly go by tackling the task and see what are the main sub-tasks to do in order to have a working demo (with add and remove notes features):
To have a better performance, we'll select and cache the elements that we will use extensively in our task. Mainly, the element div#note-place should be cached because we're going to use many times when we add and remove notes.
The inputs, for the note title and text, the button that adds a note, those elements should be cached as well.
The main thing we will be doing is creating some elements and appending them to div#note-place so we can assign that sub-task to a separate function (that we will create). This function will create an element, add the wanted attributes (text, class etc...) then it returns that created element.
At this stage, our solution has started to take shape. Now, to create a note we will listen for the click event on the add note button and then we will have a listener that will handle the creation of the new note based on the values found on the inputs and then append that to the DOM. We will use addEventListener to attach a click event listener on the add note button (modern JS, no more onclicks!).
Now, for the remove note feature. The initial thinking that comes to mind is that we will listen for click events on the remover buttons and then do the work. This can work, but here's a better solution, Event Delegation, which basically allow us to have 1 listener set on div#note-place element that will call the remove note logic only when a remove button was clicked (see the code below for more info).
So, let's not take more time, the live demo below should allow you to easily understand what's being said:
/** cache the elemnts that we know we will use later on */
const notesContainer = document.getElementById('note-place'),
titleInp = document.getElementById('title-input'),
noteInp = document.getElementById('note-input'),
addNoteBtn = document.getElementById('add-note-btn'),
/** this class will be added to all remove note buttons This will allow us to catch clicks on those buttons using event delegation */
noteRemoverBtnClass = 'note-remover-btn',
/**
* a simple function that create an element, add the requested attribute and return the newly created element.
* tag: the tag name of the element to create (like div, h3 etc...).
* text: the text to show on the element (using textContent attribute).
* attributes: an object that holds "key: value" pairs where the keys are the attributes (like id, type etc...) and the values are the values for each attribute set on that parameter (see usage below).
*/
createElement = (tag, text, attributes) => {
const el = document.createElement(tag);
attributes = attributes || {};
!!text && (el.textContent = text);
for (let attr in attributes)
attributes.hasOwnProperty(attr) && el.setAttribute(attr, attributes[attr]);
return el;
};
/** listen for click events on the add note button */
addNoteBtn.addEventListener('click', () => {
/** create a div that will wrap the new note */
const noteEl = createElement('div');
/**
* create an "h3" for the note title, a "p" for the note text and a "button" that acts as the remove note button
* then loop through them and add them to the note wrapper that we just created
*/
[
createElement('h3', titleInp.value),
createElement('p', noteInp.value),
createElement('button', 'Remove', {
type: 'button',
class: noteRemoverBtnClass
})
].forEach(el => noteEl.appendChild(el));
/** append the entire note element (including the "h3", "p"p and "button" to "div#note-place" */
notesContainer.appendChild(noteEl);
});
/** implement event delegation by listening to click events on "div#note-place" and execute a set of logic (to remove a note) only when the clicked element is actually a remove button (thanks to "noteRemoverBtnClass" that we add to each created remove button) */
notesContainer.addEventListener('click', e => e.target.classList.contains(noteRemoverBtnClass) && e.target.parentNode.remove());
<h1>Take your notes</h1>
<input id="title-input" onfocus="this.value=''" type="text" value="title" />
<input id="note-input" onfocus="this.value=''" type="text" value="note" />
<button id="add-note-btn">add</button>
<div id="note-place"></div>
The above code sample is definitely NOT the only way to get things done, it only aims to be simple while recommending the use of some modern JS technics and logics. There always be more ways to do the task and even some better ways to do it.

Why can't I remove this class with javascript?

I'm trying to make a skeleton loading screen by having a class 'skeleton' on the elements which styles them then removing it with javascript after a timeout. The issue is that i can't get the javascript to work.
Here's my javascript to remove the class, why isn't it working?
const timeout = setTimeout(loading, 3000);
function loading() {
const element = document.getElementById("skeleton");
element.classList.remove("skeleton");
}
What I think is happening is that you have too many "skeleton" elements with the same id, and ids have to be unique. So remove the ids, and target the classes instead, and use forEach to iterate over each of them to remove the class.
const timeout = setTimeout(loading, 3000);
function loading() {
const skeletons = document.querySelectorAll('.skeleton');
skeletons.forEach(skeleton => {
skeleton.classList.remove('skeleton');
});
}
.skeleton { color: red; }
<div class="skeleton">One</div>
<div class="skeleton">Two</div>
<div class="skeleton">Three</div>
<div class="skeleton">Four</div>
You are calling getElmentById on Class. Can You Share The HTML Elment whose id or class is skeleton
try this
function loading() {
const element = document.getElementsByClassName("skeleton")[0];
element.classList.remove("skeleton");
}
I think the reason behind its not working is that your trying to remove the skeleton class from the skeleton itself. Try targeting the parent Element of the skeleton and then remove the skeleton from the parent Element. Did you try using :
const parentNode=document.querySelector(".parentElem");
parentNode.removeChild(document.querySelector(".skeleton"));
Did you notice you are trying to get an element by using getElementById whereas you stated skeleton is a class.

Get element data-attributes and insert them into the button

I want to ensure that when I click on the divs (A, B, C), the link of the button changes and gets the values of the data attributes in the appropriate places. I wrote a small script, but it does not work, and there is still not enough knowledge to understand exactly where I went wrong. Any help would be welcome.
document.getElementById("product").onclick = function() {
document.getElementById("purchase").href =
"/?add-to-cart=" + this.data-product +
"&variation_id=" + this.data-id + "/";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="product__items" id="product">
<div data-id="338" data-product="A" id="uI-1" class="items-uniqueItem">A</div>
<div data-id="339" data-product="B" id="uI-2" class="items-uniqueItem">B</div>
<div data-id="340" data-product="C" id="uI-3" class="items-uniqueItem">C</div>
<div class="product__items---btn">
Button
</div><!-- btn -->
</div>
You have several problems here.
First, I suggest you consult the documentation for HTMLElement.dataset or jQuery's .data().
Also, if you intend on using event delegation, you can't use this to refer to the event source element in a vanilla event listener as it will refer to the delegate.
Since you do have jQuery involved, you might as well use it since it makes this a lot easier (see also vanilla JS version below)
const button = $("#purchase")
$("#product").on("click", ".items-uniqueItem[data-id][data-product]", function() {
// Due to the selector above, `this` is now the clicked `<div>`
// Extract data properties
const { product, id } = $(this).data()
// Construct URL parameters
const params = new URLSearchParams({
"add-to-cart": product,
"variation_id": id
})
// Set the `href`
button.prop("href", `/?${params}/`)
})
/* this is just for visibility */
.items-uniqueItem{cursor:pointer;}#purchase{display:block;text-decoration:none;margin: 1rem;}#purchase:after{content:attr(href);display:block;color:#ccc;margin:.5rem;}
<!-- your HTML, just minified -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><div class="product__items" id="product"><div data-id="338" data-product="A" id="uI-1" class="items-uniqueItem">A</div><div data-id="339" data-product="B" id="uI-2" class="items-uniqueItem">B</div><div data-id="340" data-product="C" id="uI-3" class="items-uniqueItem">C</div><div class="product__items---btn">Button</div></div>
A vanilla JS version would look something more like this. You can use Element.closest() to locate the delegated event source
const button = document.getElementById("purchase")
document.getElementById("product").addEventListener("click", e => {
// find the required event source element
const el = e.target.closest(".items-uniqueItem[data-id][data-product]")
if (el) {
// Extract data properties
const { product, id } = el.dataset
// Construct URL parameters
const params = new URLSearchParams({
"add-to-cart": product,
"variation_id": id
})
// Set the `href`
button.href = `/?${params}/`
}
})
.items-uniqueItem{cursor:pointer;}#purchase{display:block;text-decoration:none;margin: 1rem;}#purchase:after{content:attr(href);display:block;color:#ccc;margin:.5rem;}
<!-- your HTML, just minified -->
<div class="product__items" id="product"><div data-id="338" data-product="A" id="uI-1" class="items-uniqueItem">A</div><div data-id="339" data-product="B" id="uI-2" class="items-uniqueItem">B</div><div data-id="340" data-product="C" id="uI-3" class="items-uniqueItem">C</div><div class="product__items---btn">Button</div></div>
As you can see, it's not very different to the jQuery version so maybe you might not need jQuery
I've never personally used the element.onlick = function() {...} notation, so I'll be usingelement.addEventListener('click', (e) => ...), but it should work the same way.
What you are doing is selecting the object that has the id "product". But "product" is the parent os the elements you want to select.
If you want to select several elements and do something with them, you can't use the id attribute, since id is unique for html page. So you'll want to use classes for that.
Create a class and add that class to each child (the ones with the data-product).
Select all children with .querySelectorAll(). Here is the doc. This returns a NodeList, but it's similar to an Array.
Iterate thought the List with a .forEach(item => ...) where item represents each element of the list.
Add an Event Listener (or .click, I guess) on each item.
*theList*.forEach( (item) => {
item.addEventListener('click', (event) => {
event.target.href = "/?add-to-cart=" + event.target.dataset.product + "&" + "variation_id=" + event.target.dataset.id + "/";
})
));
To access a dataset in JS you use the .dataset property.
First, grab all the divs that have a given class so that we can use their data.
const items = document.querySelectorAll('.items-uniqueItem');
items.forEach(item => item.addEventListener('click', (e) => console.log(e.target)))
Then inside you click handler you can get the button reference and assign the properties you want to get from it.

alert the class name of an element using javascript

i have an element and i want to alert the class attribute of this element i use this code;
<li id="SSS" class="settings" onclick="alertClassName(this)">1111</li>
and in the alertClassName function ;
function changeClass(elem)
{
var x = $(elem.id);
alert(x.class) ;
}
it alerts undefind.
Try with className instead of class.
onclick="alertClassName(this)"
...
function alertClassName(elem) {
alert(elem.className);
}
Reference.
First off, you have to decide on a function name (alertClassName or changeClass). I'll use alertClassName as that matches the question title:
Here:
<li id="SSS" class="settings" onclick="alertClassName(this)">1111</li>
...you're passing a reference to the actual element into your function. The this within the code in an onxyz DOM0 handler attribute refers to the element the onxyz attribute is on.
This means you can just use it directly:
function alertClassName(elem)
{
alert(elem.className);
}
And if you wanted to change it:
<li id="SSS" class="settings" onclick="changeClass(this, 'foo')">1111</li>
and
function changeClass(elem, newClass)
{
elem.className = newClass;
}
...would remove all classes from the element when it was clicked and add the foo class.
You can access class name directly via className property (no need for jQuery, in this case):
function alertClassName(elem)
{
alert(elem.className);
}
You trying to activate different function then what you posted) alertClassName instead of changeClass )
Here's an example of how to alert and then change the class of your element. (here's the fiddle).
And the code:
<li id="SSS" class="settings" onclick="changeClass(this)">1111</li>
<script>
function changeClass(e)
{
alert("Current Class:" + e.className);
e.className = "Settings2";
alert("Updated Class:" + e.className);
}
</script>
try:
alert($(this).attr('class'))

How can I add a class to a DOM element in JavaScript?

How do I add a class for the div?
var new_row = document.createElement('div');
This answer was written/accepted a long time ago. Since then better, more comprehensive answers with examples have been submitted. You can find them by scrolling down. Below is the original accepted answer preserved for posterity.
new_row.className = "aClassName";
Here's more information on MDN: className
Use the .classList.add() method:
const element = document.querySelector('div.foo');
element.classList.add('bar');
console.log(element.className);
<div class="foo"></div>
This method is better than overwriting the className property, because it doesn't remove other classes and doesn't add the class if the element already has it.
You can also toggle or remove classes using element.classList (see the MDN documentation).
Here is working source code using a function approach.
<html>
<head>
<style>
.news{padding:10px; margin-top:2px;background-color:red;color:#fff;}
</style>
</head>
<body>
<div id="dd"></div>
<script>
(function(){
var countup = this;
var newNode = document.createElement('div');
newNode.className = 'textNode news content';
newNode.innerHTML = 'this created div contains a class while created!!!';
document.getElementById('dd').appendChild(newNode);
})();
</script>
</body>
</html>
3 ways to add a class to a DOM element in JavaScript
There are multiple ways of doing this. I will show you three ways to add classes and clarify some benefits of each way.
You can use any given method to add a class to your element, another way to check for, change or remove them.
The className way - Simple way to add a single or multiple classes and remove or change all classes.
The classList way - The way to manipulate classes; add, change or remove a single or multiple classes at the same time. They can easily be changed at any time in your code.
The DOM way - When writing code according to the DOM model, this gives a cleaner code and functions similar to the className way.
The className way
This is the simple way, storing all classes in a string. The string can easily be changed or appended.
// Create a div and add a class
var new_row = document.createElement("div");
new_row.className = "aClassName";
// Add another class. A space ' ' separates class names
new_row.className = "aClassName anotherClass";
// Another way of appending classes
new_row.className = new_row.className + " yetAClass";
If an element has a single class, checking for it is simple:
// Checking an element with a single class
new_row.className == "aClassName" ;
if ( new_row.className == "aClassName" )
// true
Removing all classes or changing them is very easy
// Changing all classes
new_row.className = "newClass";
// Removing all classes
new_row.className = "";
Searching for or removing a single class when multiple classes are used is difficult. You need to split the className string into an array, search them through one by one, remove the one you need and add all others back to your element. The classList way addresses this problem and can be used even if the class was set the className way.
The classList way
It is easy to manipulate classes when you need to. You can add, remove or check for them as you wish! It can be used with single or multiple classes.
// Create a div and add a class
var new_row = document.createElement("div");
new_row.classList.add( "aClassName" );
// Add another class
new_row.classList.add( "anotherClass" );
// Add multiple classes
new_row.classList.add( "yetAClass", "moreClasses", "anyClass" );
// Check for a class
if ( new_row.classList.contains( "anotherClass" ) )
// true
// Remove a class or multiple classes
new_row.classList.remove( "anyClass" );
new_row.classList.remove( "yetAClass", "moreClasses" );
// Replace a class
new_row.classList.replace( "anotherClass", "newClass" );
// Toggle a class - add it if it does not exist or remove it if it exists
new_row.classList.toggle( "visible" );
Removing all classes or changing to a single class is easier done the className way.
The DOM way
If you write code the DOM way, this looks cleaner and stores classes in a string by setting the class attribute.
// Create a div, add it to the documet and set class
var new_row = document.createElement( "div" );
document.body.appendChild( new_row );
new_row.setAttribute( "class", "aClassName anotherClass" );
// Add some text
new_row.appendChild( document.createTextNode( "Some text" ) );
// Remove all classes
new_row.removeAttribute( "class" );
Checking for a class is simple, when a single class is being used
// Checking when a single class is used
if ( new_row.hasAttribute( "class" )
&& new_row.getAttribute( "class" ) == "anotherClass" )
// true
Checking for or removing a single class when multiple classes are used uses the same approach as the className way. But the classList way is easier to accomplish this and can be used, even if you set it the DOM way.
If doing a lot of element creations, you can create your own basic createElementWithClass function.
function createElementWithClass(type, className) {
const element = document.createElement(type);
element.className = className
return element;
}
Very basic I know, but being able to call the following is less cluttering.
const myDiv = createElementWithClass('div', 'some-class')
as opposed to a lot of
const element1 = document.createElement('div');
element.className = 'a-class-name'
over and over.
If you want to create multiple elements all with in one method.
function createElement(el, options, listen = [], appendTo){
let element = document.createElement(el);
Object.keys(options).forEach(function (k){
element[k] = options[k];
});
if(listen.length > 0){
listen.forEach(function(l){
element.addEventListener(l.event, l.f);
});
}
appendTo.append(element);
}
let main = document.getElementById('addHere');
createElement('button', {id: 'myBtn', className: 'btn btn-primary', textContent: 'Add Alert'}, [{
event: 'click',
f: function(){
createElement('div', {className: 'alert alert-success mt-2', textContent: 'Working' }, [], main);
}
}], main);
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<div id="addHere" class="text-center mt-2"></div>
var newItem = document.createElement('div');
newItem.style = ('background-color:red');
newItem.className = ('new_class');
newItem.innerHTML = ('<img src="./profitly_files/TimCover1_bigger.jpg" width=50 height=50> some long text with ticker $DDSSD');
var list = document.getElementById('x-auto-1');
list.insertBefore(newItem, list.childNodes[0]);
Cross-browser solution
Note: The classList property is not supported in Internet Explorer 9. The following code will work in all browsers:
function addClass(id,classname) {
var element, name, arr;
element = document.getElementById(id);
arr = element.className.split(" ");
if (arr.indexOf(classname) == -1) { // check if class is already added
element.className += " " + classname;
}
}
addClass('div1','show')
Source: how to js add class
var new_row = document.createElement('div');
new_row.setAttribute("class", "YOUR_CLASS");
This will work ;-)
source
It is also worth taking a look at:
var el = document.getElementById('hello');
if(el) {
el.className += el.className ? ' someClass' : 'someClass';
}
If you want to create a new input field with for example file type:
// Create a new Input with type file and id='file-input'
var newFileInput = document.createElement('input');
// The new input file will have type 'file'
newFileInput.type = "file";
// The new input file will have class="w-95 mb-1" (width - 95%, margin-bottom: .25rem)
newFileInput.className = "w-95 mb-1"
The output will be: <input type="file" class="w-95 mb-1">
If you want to create a nested tag using JavaScript, the simplest way is with innerHtml:
var tag = document.createElement("li");
tag.innerHTML = '<span class="toggle">Jan</span>';
The output will be:
<li>
<span class="toggle">Jan</span>
</li>
<script>
document.getElementById('add-Box').addEventListener('click', function (event) {
let itemParent = document.getElementById('box-Parent');
let newItem = document.createElement('li');
newItem.className = 'box';
itemParent.appendChild(newItem);
})
</script>

Categories