Change CSS value by javascript for whole document - javascript

I want on ajax call change the values loaded from CSS file, it means not only for one element like:
document.getElementById("something").style.backgroundColor="<?php echo "red"; ?>";
but similar script which is change the css value generally, not only for element by ID, idealy like background color for CSS CLASS divforchangecolor:
CSS:
.divforchangecolor{
display: block;
margin: 20px 0px 0px 0px;
padding: 0px;
background-color: blue;
}
HTML:
<div class="divforchangecolor"><ul><li>something i want to style</li><ul></div>
<div class="divforchangecolor">not important</div>
<div class="divforchangecolor"><ul><li>something i want to style</li><ul></div>
<div class="divforchangecolor">not improtant</div>
Ideal solution for me:
onclick="--change CSS value divforchangecolor.backgroundColor=red--"
but i need to change CSS to reach .divforchangecolor ul li and .divforchangecolor ul li:hover

If you can't just apply the classname to these elements. You could add a new selector to your page. The following vanilla JS would be able to do that (jsFiddle).
function applyDynamicStyle(css) {
var styleTag = document.createElement('style');
var dynamicStyleCss = document.createTextNode(css);
styleTag.appendChild(dynamicStyleCss);
var header = document.getElementsByTagName('head')[0];
header.appendChild(styleTag);
};
applyDynamicStyle('.divforchangecolor { color: pink; }');
Just adapt the thought behind this and make it bullet proof.

var elements=document.getElementsByClassName("divforchangecolor");
for(var i=0;i<elements.length;i++){
elements[i].style.backgroundColor="red";
}

var e = document.getElementsByClassName('divforchangecolor');
for (var i = 0; i < e.length; i++) e[i].style.backgroundColor = 'red';
Use getElementByClassName() and iterate over the array returned to achieve this

You can select elements by class with document.getElementsByClassName or by css selector (includes class) with document.querySelectorAll().
Here are two approaches, for example: Live demo here (click).
Markup:
<div class="divforchangecolor"></div>
<div class="divforchangecolor"></div>
<div class="divforchangecolor"></div>
<div class="divforchangecolor"></div>
<div class="some-container">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
JavaScript:
var toChange = document.getElementsByClassName('divforchangecolor');
for (var i=0; i<toChange.length; ++i) {
toChange[i].style.backgroundColor = 'green';
}
var toChange2 = document.querySelectorAll('.some-container > div');
for (var i=0; i<toChange.length; ++i) {
toChange2[i].style.backgroundColor = 'red';
}
I recommend the second solution if it is possible in your case, as the markup is much cleaner. You don't need to specifically wrap the elements in a parent - elements already have a parent (the body, for example).
Another option is to have the background color you want to change to in a css class, then you can change the class on your elements (and therefore the style changes), rather than changing the css directly. That is also good practice, as it lets you keep your styles all in css files, while js is just manipulating which one is used.

On the whole document your approach can be a bit different:
ajax call
call a function when done
conditionally set a class on the body like <body class='mycondition'></body>
CSS will take care of the rest .mycondition .someclass: color: red;
This approach will be more performant than using JavaScript to change CSS on a bunch of elements.

You can leverage CSS selectors for that:
.forchangecolor {
display: block;
margin: 20px 0px 0px 0px;
padding: 0px;
background-color: blue;
}
.red-divs .forchangecolor {
background-color: red;
}
Then, with javascript, add the red-divs class to a parent element (could be the <body>, for example), when one of the divs is clicked:
document.addEventListener("click", function(event) {
var target = event.target;
var isDiv = target.className.indexOf("forchangecolor") >= 0;
if(isDiv) {
document.body.classList.add("red-divs");
}
});
Working example: http://jsbin.com/oMIjASI/1/edit

Related

How to display none if div tag doesn't exist?

If the "slick-initialized" div tag doesn't exist within a parent, then I want the parent ID (product recommender-recipe) to display none. Right now this is what I have set up:
HTML is set up like this:
<div id="product-recommender-recipe">
<div class="slick-initialized">
</div>
</div>
My JS so far. If length is 0, then have the parent ID display none. :
var productTemplate = document.getElementsByClassName("#product-recommender-recipe > .slick-initialized")
if (productTemplate.length === 0){
document.getElementById("product-recommender-recipe").style.display = "none";
}
Do I have this set up properly?
You can hide #product-recommender-recipe and check if .slick-initialized exists than show using just CSS.
it is working perfectly.
#product-recommender-recipe {
padding: 50px;
background-color: red;
display: none;
}
#product-recommender-recipe:has(.slick-initialized) {
display: block;
}
<!-- hidden if slick-initialized not exist -->
<div id="product-recommender-recipe">
<!-- <div class="slick-initialized"></div> -->
</div>
<br/>
<!-- visible if slick-initialized exist -->
<div id="product-recommender-recipe">
<div class="slick-initialized"></div>
</div>
You are pretty close. You have two mistakes in your implementation.
The first one is that you used getElementByClassName when in fact you are using an ID as your selector. Thus you should have used querySelector.
The second one is that you overused your selector. You have selected your parent div and placed it in a var so that you can reference it again.
Here is my implementation:
var productTemplate = document.querySelector("#product-recommender-recipe")
if (!productTemplate.querySelector('.slick-initialized')) {
productTemplate.style.display = none;
}
#product-recommender-recipe {
background: red;
width: 50px;
height: 50px;
}
<div id="product-recommender-recipe">
<div class="slick-initialized"></div>
</div>
getElementsByClassName expects a single class name – not a selector. If you want to use a selector, use querySelector or querySelectorAll. querySelector returns null if the element doesn't exists in the DOM.
const element = document.querySelector(".slick-initialized");
if(element === null) {
document.querySelector("#product-recommender-recipe").style.display = "none";
}

Place a button and its div with one command

Currently, I have a button class which lets me place a clickable button inside a sentence, and a div class which lets me add content to the button which I placed at the end of the paragraph containing the sentence.
This is an example of how I use them
Try to click <button class="col">THIS</button> and see what happens.
<div class="con">nice!</div>
Did you try?
When this text is displayed on the page, the two sentences are placed inside two different paragraphs, so the div object is placed between them.
Here is a snippet with the css classes and the javascript.
( function() {
coll = document.getElementsByClassName("col");
conn = document.getElementsByClassName("con");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].setAttribute('data-id', 'con' + i);
conn[i].setAttribute('id', 'con' + i);
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = document.getElementById(this.getAttribute('data-id'));
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
} )();
.col {
cursor: help;
border-radius: 0;
border: none;
outline: none;
background: none;
padding: 0;
font-size: 1em;
color: red;
}
.con {
padding: 0 1em;
max-height: 0;
overflow: hidden;
transition: .3s ease;
background-color: yellow;
}
Try to click <button class="col">THIS</button> and see what happens.
<div class="con">nice!</div>
Did you try?
I wonder if it is possible to implement a shortcut to place the two objects with one command, that is to obtain the previous example by using something like this
Try to click [[THIS|nice!]] and see what happens.
Did you try?
What I mean is that the command [[THIS|nice!]] should place the object <button class="col">THIS</button> in the same position and the object <div class="con">nice!</div> at the end of the paragraph containing the command.
Is it possible to implement such a command (or a similar one)?
EDIT
I forgot to say that the content of the button, ie what is written inside the div, should also be possible to be a wordpress shortcode, which is a shortcut/macro for a longer piece of code or text.
Using jQuery, closest() find the nearest <p> element and add <div class="con">nice!</div> after <p> element. To toggle you can use class active and add or remove .con element.
$('.col').click(function(){
let traget = $(this).closest('p');
if(traget.hasClass('active')) {
traget.removeClass('active');
traget.next('.con').remove();
} else {
traget.addClass('active');
traget.after(`<div class="con">${$(this).data('message')}</div>`);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Try to click <button class="col" data-message="Hello">THIS</button> and see what happens.</p>
<p>Did you try?</p>
You usually dont use div to type text. you use it to define areas or group items. you could obtain what youre asking for in a 1 sentence like this:
html
<h1> some random text <a class="btnID">button</> some more text<h1>
css
.btnID {
color: red;
}

give an onclick function to be executed to every element with a certain class

How would i go about making something like this - i have multiple elements with a certain class and i would like this to happen:
element1 - onclick fires someFunction(13);
element2 - onclick fires someFunction(27);
element3 - onclick fires someFunction(81);
i am loading these elements in dynamically so i can't put it manually into my js file. I also can't give them an onclick as i load them with php.
I am looking for a purely js answer so please no jQuery.
function setMyHandler(){
var elements = document.getElementsByClassName('someClass');
for(var i = 0; i < elements.length; i++){
elements[i].onclick = function(){};
}
}
But I would be better advised to use you event delegate. Set Handler on root element. And checking event.target. http://javascript.info/tutorial/event-delegation
Approach #1
In your PHP code, create your elements with onclick tags, with intended input into the function.
<div class="someclass" onclick="someFunction(1)"></div>
Approach #2
When the page loads, iterate through all elements with your given classname and attach listeners to them. For this approach to work, the divs must have the numbers which will be entered in SomeFunction included in arbitrary tags.
<div data="13" > =) </div>
window.onload = function() {
for (var i =0; i < document.getElementsByClassName("classname").; i++){
var Div = document.getElementsByClassName("classname")[i];
Div.addEventListener("click", function(){
someFunction(Div.data);
});
}
}
You can delegate events by attaching event listener to parent element. To get the target element you can use event.target
Here's the sample code how you can achieve it:
var parentElement = document.querySelector("#parent");
parentElement.addEventListener("click", function () {
var currentTarget = event.target;
if (currentTarget.tagName === "LI") { // If you want LI to be clickable
currentTarget.style.backgroundColor = "#eee";
currentTarget.style.color = "#606060";
}
});
Here's the jsfiddle for the same: https://jsfiddle.net/dx8Lye29/
The simplest way of doing this is giving the elements a data-attribute with the parameter for the function you want to run:
<div class="someclass" data-parameter="12">
<div class="someclass" data-parameter="13">
<div class="someclass" data-parameter="14">
and then run this:
function setMyHandler(){
var elements = document.getElementsByClassName('someclass');
for(var i = 0; i < elements.length; i++){
elements[i].onclick = function(){ myFunction(this.data.parameter); };
}
}
Here is a link for data attributes: data attributes
And here is a snipplet to see the simple version of it in action:
function setMyHandler(){
var elements = document.getElementsByClassName('someclass');
for(var i = 0; i < elements.length; i++){
elements[i].onclick = function(){window.alert(this.dataset.somevalue);};
}
}
setMyHandler();
body {
display: flex;
justify-content: center;
}
div.someclass {
margin: 2%;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
background: #80bfff;
box-shadow: 0px 2px 6px 0px rgba(0,0,0,0.7);
transition: background 0.3s ease;
}
div.someclass:hover {
background: #3399ff;
}
<div class="someclass" data-somevalue="13"> </div>
<div class="someclass" data-somevalue="14"> </div>
<div class="someclass" data-somevalue="15"> </div>

Dynamic mouseenter

I appended a few divs with inside img tags. Every tag has own unique id = "theImg"+i where "i" is number. I want to mouseover on specific img and show the content of span (which also have specific id with number). Here is my code so far but not working.
var j;
document.onmouseover = function(r) {
console.log(r.target.id);
j = r.target.id;
}
$(document).on({
mouseover: function(e){
$("span").show();
},
mouseleave: function(e){
$("span").hide();
}
}, "img#"+j);
If you have a span after every img, maybe it's a good idea to not use JavaScript at all? ;-)
You could use :hover pseudoclass in CSS, making your thing always work reliably.
Consider the following example:
img + span {
display: none;
}
img:hover + span {
display: block;
}
/*/ Optional styles /*/
div {
position: relative;
float: left;
}
div img + span {
position: absolute;
color: #fff;
background: #27ae60;
border: solid 1px #2ecc71;
border-radius: 50px;
z-index: 1;
bottom: 1em;
width: 80%;
left: 50%;
margin-left: -43%;
padding: 2% 3%;
text-align: center;
}
<div>
<img src="https://placehold.it/400x200">
<span>This is an image of a gray rectangle!</span>
</div>
<div>
<img src="https://placehold.it/200x200">
<span>This is an image of a gray square!</span>
</div>
<div>
<img src="https://placekitten.com/g/400/200">
<span>This is an image of a cute kitten inside a rectangle!</span>
</div>
<div>
<img src="https://placekitten.com/g/200/200">
<span>This is an image of even cuter kitten inside a square!</span>
</div>
So the issue is that you are trying to set your handler on a dynamic selector ("img#"+j) but this will not work. For one thing, that equation will be evaluated only once, on page load, when j is undefined.
So you want to do this instead:
target only img tags for your mouse over... Better yet, give your special images all the same css class so you can attach the event handlers only to those. That will be more efficient.
When an image is moused over or out of, grab it's id attribute, extract the number from it, then use that to build a selector for the appropriate span to show.
var get_span_from_image = function(image) {
var image_id = image.attr("id");
var matches = image_id.match(/theImg(\d+)/);
if(matches) return $("theSpan" + matches[1]);
return $(); // nothing found, return an empty jQuery selection
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Note: There are better ways to "link" two nodes together, but this is just to answer your question with the current structure you have.
UPDATE: Some ideas to link two nodes together
So instead of trying to extract a number from an id attribute, a better way would be to tell either one of the image or span about it's sibling. You could output your html like this, for instance:
<img id="theImg1" data-target="theSpan1" class="hoverable" src="..."/>
....
<span id="theSpan1">...</span>
Of course now your ideas could be anything - you don't have to use numbered values or anything.
Then your hover code becomes quite simply:
var get_span_from_image = function(image) {
var span_id = image.data("target");
return $("#" + span_id);
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Hope this helps!

How do I tell CSS to recalculate :first-of-type after DOM dynamically changes?

I have the following CSS rules:
.block:first-of-type{
border-top: 1px solid black;
}
.block:last-of-type{
border-bottom: 1px solid black;
}
This .block div is generated via AJAX and can be added multiple times to the page. The problem is that every time I add one of them, all divs are read as both first and last of the document. I assume it is because the CSS doesn't recognize the changes that happen in the DOM. How do I fix this?
all divs are read as both first and last of the document
You misunderstand what :first-of-type and :last-of-type mean.
See the spec
Same as :nth-of-type(1). The :first-of-type pseudo-class represents an element that is the first sibling of its type in the list of children of its parent element.
The important bit is children of its parent element not document.
You can see it does that quite correctly here:
function middle() {
var d = document.createElement("div");
d.appendChild(document.createTextNode("inserted in middle"));
var p = document.querySelector("div + div + div");
p.parentNode.insertBefore(d, p);
}
function first() {
var d = document.createElement("div");
d.appendChild(document.createTextNode("inserted at top"));
var p = document.querySelector("div");
p.parentNode.insertBefore(d, p);
}
setTimeout(middle, 2000);
setTimeout(first, 4000);
div:first-of-type {
border-top: 1px solid black;
}
div:last-of-type {
border-bottom: 1px solid black;
}
<div>Original First</div>
<div>Original Second</div>
<div>Original Third</div>
<div>Original Fourth</div>
<div>Original Fifth</div>
You are, presumably creating a structure such as:
<div>
<div class="block"></div>
</div>
<div>
<div class="block"></div>
</div>
<div>
<div class="block"></div>
</div>
… in which every div of that class is the first div in its parent element.
Given that layout then you would need something more akin to :first-of-type > .block as your selector.
The precise nature of the selector you need would depend on the DOM you are creating, but you haven't shared that with us.

Categories