So how exactly would i write
$('div').addClass('border1');
in Vanilla javascript, like what would my add class method look like. So far what I have is,
function addClass(x,y) {
x.className += " " + y;
}
but i know this is wrong, as the parameters are off. Im really lost.
Let's take a closer look at what jQuery does here.
What is the meaning of $('div')?
In jQuery terms it means "select all 'div' elements in the document".
$('div') is a jQuery object which represents all div elements in the document. But nowhere in this code you specifically target a single DOM element by yourself.
Let's write our own simplified selection object "MySelect":
/**
* `MySelect` object constructor.
*/
function MySelect(selector){
this.elementList = document.querySelectorAll(selector);
}
Now let's use it:
var divs = new MySelect('div');
divs.elementList; // all `div` elements in the document.
(Note that querySelectorAll is a native javascript DOM method)
Now that we have an elements selection object, let's add an addClass method to it:
/**
* Add the specified class to all elements selected by this object.
*/
MySelect.prototype.addClass = function(cls){
var i, e;
for (i = 0; i < this.elementList.length ; i++){
e = this.elementList[i];
e.className += " " + cls;
// can also use e.classList.add
}
}
And voila:
divs.addClass('xyz');
This, in a very simplified fashion, is how jQuery works.
For the $ syntax you can do:
function $(selector){
return new MySelect(selector);
}
And use it as usual:
$('div').addClass('xyz');
element.classList is vanillaJS's way of doing it
var x = document.getElementById('x');
var y = document.getElementById('y');
var z = document.getElementById('z');
y.addEventListener('click',function(){
x.classList.add('blue');
});
z.addEventListener('click',function(){
x.classList.toggle('blue');
});
#x {
width: 50px;
height: 50px;
border: 1px dotted gray;
}
.blue {
background-color: blue;
}
<div id="x"></div>
<button id="y">add the class</button>
<button id="z">toggle the class</button>
If you're targetting IE10+, you can use
var el = document.getElementById("someId");
el.classList.add(className);
For all browsers :
if (el.classList)
el.classList.add(className);
else
el.className += ' ' + className;
Source:
http://youmightnotneedjquery.com/#add_class
function addClass(selector, class) {
els = document.querySelectorAll(selector);
for (var i = 0; i < els.length; i++) {
els[i].className += class;
}
}
Then you can do:
addClass('div', 'border1');
addClass('#someID', 'someclass');
addClass('.someClass', 'someotherclass');
I write this not so much as a recommendation, but because you seem to want to create a method, rather than a function; presumably under the impression that one might be better. They're much the same, however, except extending the prototype to add a method can potentially cause trouble. However, if you must:
NodeList.prototype.addClass = function (cName) {
// creates an Array from the NodeList, and iterates through:
return [].forEach.call(this, function (elem) {
// adds the passed-in class-name:
elem.classList.add(cName);
});
};
The above can be called with:
document.querySelectorAll('div').addClass('newClassName');
Or:
document.getElementsByTagName('div').addClass('newClassName');
Note that this uses features found in relatively modern browsers, though they could be replaced with a for loop (forEach) and string-concatenation with className property (classList.add()) if desired.
Related
I'm trying to create a chrome extension. I had a problem with the affectation of event for the new element that i append to the dom of site with content. Js
If I add an event to an element' 'for example class' exist already in the page, it works correctly. Just for my new appended element((in the code iadded a button ,the event is just an alert to test))
function tst() {
myclass = $("._3hg-._42ft");
myclass = myclass.not(".supp");
myclass.addClass("supp");
var patt = /https:\/\/(.)*\.facebook\.com\/(.)*\/(posts|photos|videos)\/(\w|\.|\d)*/g;
for (i = 0; i < myclass.length; i++) {
result = patt.exec(myclass[i]);
myclass.append('<button class="fact" id=' + result[0] + ' style="position: absolute;">fact</button>');
};
/* this is a simple event*/
/***********************/
$(".fact").on('click', function() {
alert("no event work ");
});
Making somewhat broad assumption here in my answer that it is JavaScript/jQuery related and is NOT an extension...or is so still in that context.
You need to attach the event to the container here perhaps for the dynamically created elements. Lots of global stuff, suggested to not do that, updated there.
Appends a lot of buttons perhaps? might need to only hit DOM once but left as-is in this isolated function.
function tst() {
let myclass = $("._3hg-._42ft")
.not(".supp");
myclass.addClass("supp");
//let result = {};
var patt = /https:\/\/(.)*\.facebook\.com\/(.)*\/(posts|photos|videos)\/(\w|\.|\d)*/g;
var i = 0; //avoid global
for (i; i < myclass.length; i++) {
// broad assumption of the returned value from patt.exec() here
// not even sure why it needs an id, have a class, use for css
let result = patt.exec(myclass[i]);
myclass.append('<button class="fact" id="' + result[0] + '">fact</button>');
}
/* attache event to pre-existing element */
/***********************/
myclass.on('click', ".fact", function() {
alert("event works");
});
}
button.fact {
position: absolute;
}
The following code basically shows/hides paragraph tags, I'm having to re-declare the paras variable. Is this because I'm dynamically injecting the button into the DOM, or is it to do with scope? How could I better construct this markup?
// vars
var revealContainer = document.querySelector('.reveal-more');
var paras = revealContainer.querySelectorAll('p');
var status = true;
// return
if (paras && paras.length <= 3) return;
// generate show more link
revealContainer.innerHTML += '<button class="button--text reveal-more__btn">Read more</button>';
var revealBtn = revealContainer.querySelector('.reveal-more__btn');
// click event
revealBtn.addEventListener('click', function () {
var paras = revealContainer.querySelectorAll('p');
// toggle show/hide class
for (var i = 0; i < paras.length; i++) {
var p = paras[i];
p.classList.toggle('is-shown');
}
// check status
if (status) {
this.textContent = 'Read less';
status = false;
} else {
this.textContent = 'Read more';
status = true;
}
});
You can use the live HTMLCollection returned by .getElementsByTagName() instead of the static NodeList returned by .querySelectorAll()
The getElementsByTagName method of Document interface returns an HTMLCollection of elements with the given tag name. The complete document is searched, including the root node. The returned HTMLCollection is live, meaning that it updates itself automatically to stay in sync with the DOM tree without having to call document.getElementsByTagName() again.
var paragraphs = document.getElementById("container").getElementsByTagName("p");
console.log(paragraphs.length);
setInterval(function() {
document.getElementById("container").insertAdjacentHTML("beforeend", "<p>p</p>");
}, 1000);
setInterval(function() {
console.log(paragraphs.length);
}, 2000);
<div id="container"></div>
Below is a really simple Snippet that demonstrates delegated events in pure Javascript, instead of using jQuery.
Here you can see I've attached the eventListener to the div with id elements, this will then listen for click events under this, a simple matches is used just in case you have other elements your not interested in..
document.querySelector("#elements").addEventListener("click", (e) => {
if (!e.target.matches('.element')) return
console.log(`Clicked ${e.target.innerText}`);
});
.element {
border: 1px solid black;
margin: 5px;
}
<div id="elements">
<div class="element">1</div>
<div class="element">2</div>
<div class="element">3</div>
<div>Clicking this does nothing.</div>
</div>
I'm very new to learning JavaScript, and I've tried to read, and look for similar answers, but everything is pointing at jQuery, which I want to avoid using for this problem. I can't quite work out what is jQuery and what still works in JS...
I have set up a function that can grab the innerHTML but I can't seem to assign it to the same classes, else it'll only work on the first instance, and I tried creating multiple classes but essentially they're all the same button with different values...
document.querySelector(".b1").addEventListener("click", writeDisp);
document.querySelector(".b2").addEventListener("click", writeDisp);
document.querySelector(".b3").addEventListener("click", writeDisp);
document.querySelector(".b4").addEventListener("click", writeDisp);
function writeDisp() {
if(dispNum.length < 9){
if(dispNum === "0") {
dispNum = this.innerHTML
} else {
dispNum = dispNum + this.innerHTML};
document.querySelector(".display").textContent = dispNum;
}
}
}
How can I make this more simple. As there are way more .b* classes to add, and I'd rather not have a massive list if possible.
Thanks,
var class_elem = document.querySelectorAll("button[class^='b']");
function writeDisp(){
if(dispNum.length < 9){
if(dispNum === "0"){dispNum = this.innerHTML}else{dispNum = dispNum + this.innerHTML};
document.querySelector(".display").textContent = dispNum;
}
}
for (var i = 0; i < class_elem.length; i++) {
class_elem[i].addEventListener('click', writeDisp, false);
}
//Here your code in javascript only.
If you don't want to use jquery, you can use native document.querySelectorAll API like this
function writeDisp(){
if(dispNum.length < 9){
if(dispNum === "0"){
dispNum = this.innerHTML
} else {
dispNum = dispNum + this.innerHTML
}
document.querySelector(".display").textContent = dispNum;
}
}
// this line will select all html tags that contains a class
// name starting with 'b'
var doms = document.querySelectorAll("[class^=b]");
doms.forEach(function(dom) {
dom.addEventListener('click', writeDisp);
})
Note
querySelectorAll will fetch only those DOM instance in which b* is defined as first class, so in case of multiple class defintion, it will not fetch those DOMs which don't have the desired classname at first. That means if you have a DOM defintion like <div class="a box"></div>, this will be ignored, as here, classname starting with b sits after a class.
I try to change color in all elements in class, but I have an error:
Cannot convert undefined or null to object
I have code:
<div class="kolorek" onclick="changeColor('34495e');" style="background-color:#34495e;"></div>
function changeColor(color) {
var block = document.getElementsByClassName('kafelek');
with (block.style) {
backgroundColor = "#" + color;
}
};
As getElementsByClassName will return HTMLCollection, you have to loop through them to set the color as below.
function changeColor(color) {
var block = document.getElementsByClassName('kafelek');
for (var i = 0; i < block.length; i++) {
block[i].style.backgroundColor = "#" + color;
}
};
<div class="kolorek" onclick="changeColor('34495e');" style="background-color:#34495e;">Clickable Div</div>
<div class="kafelek">Another Div</div>
Note: Instead of inline onclick event, you can use addEventListener instead
Firstly you are searching for the wrong element and you can access style by using element.style and to change backgroundColor it should be element.style.backgroundColor=color
check this snippet
function changeColor(color) {
var block = document.querySelector('.kolorek');
console.log(block.style);
block.style.backgroundColor = "#"+color;
};
<div class="kolorek" onclick="changeColor('999999');" style="background-color:#34495e;">sdfdsfds</div>
Hope this helps
First of all, using with is not recommended and even forbidden since es5 in strict mode (See the link I posted in the comment above). Secondly you are targeting elements with kafelek as their class, but the class you are showing in your html is kolorek. The third error is that you are trying to set a property on a HTMLCollection, but that doesn't exist. It exists on a single element. You need to refactor your code to the following:
function changeColor(color) {
var block = document.getElementsByClassName('kolorek');
Array.prototype.forEach.call(block, function(el) {
el.style.backgroundColor = '#' + color;
}
};
I have an HTML page having css class for a control with following definition:
.ms-crm-Inline-Edit select.ms-crm-SelectBox {
border: 1px solid #CCCCCC;
font-size: 12px;
margin: 1px 0 0 1px;
width: 100%;
}
I need to add a new attribute to this class as follows:
height: "120px !important";
This has to be done through Javascript. I can't modify origional class definition that's why I have to add Javascript function which does this job. For that purpose I have written Jscript method but its not working.
function CustomizePicklistHeight ()
{
document.getElementsByClassName('ms-crm-Inline-Edit select.ms-crm-SelectBox').style.height = '120px !important';
}
I guess, first we have to add height attribute to this class but I dont know how to do that in JScript. Please suggest.
document.getElementsByClassName returns an array of all items with that class.
Try this:
function CustomizePicklistHeight()
{
// Store elements for each class differently. Just in case :)
var elements1 = document.getElementsByClassName('ms-crm-Inline-Edit');
var elements2 = document.getElementsByClassName('ms-crm-SelectBox');
// Since you cant affect the array directly, you use a loop to do the operation on each individual element
for (var i = 0; i < elements1.length; i++)
{
element1[i].style.height = '120px !important';
};
for (var j = 0; j < elements2.length; j++)
{
element1[j].style.height = '120px !important';
};
}
Hope this helps.. :)
var matches = document.querySelectorAll(".ms-crm-Inline-Edit, select.ms-crm-SelectBox");
for(i=0; i<matches.length; i++)
{
matches[i].style.height = '120px !important';
}
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Document.querySelectorAll
ClassName means "class name" (ms-crm-SelectBox) not "Entire selector". (querySelector and querySelectorAll let you use complete selectors though.
Elements means "elements" (plural) not "Element". It returns a NodeList, which you can loop over like an array.
If, on the other hand, you want to the modify the CSS rule-set instead of the styles applied directly to the HTML elements, then you need to look at document.styleSheets instead.
you will have to make a loop by setting each item, and if you have not "! important" earlier you do not need it.