I found that there are many frameworks that will check the duplicate class name before adding the new class name on the element which I think will slow down the performance.
Are there any problems when the element has a duplicate class name?
It will also apply the CSS class without conflict while the duplicate class name is in use.
<div class="aa bb cc aa"></div>
Is it OK to add a class name simply just like elem.className += ' ' + 'aa ee', even if the element has a duplicate class name?
There is nothing "wrong" with having a duplicate class name, it's just redundant. There's probably a small performance impact, but that'll only really make much difference if you have a lot of duplication.
Also, preventing duplicates just helps to keep things tidy.
Semantic UI heavily uses attribute selectors
like here
.ui.grid [class*="left floated"].column {
margin-right: auto;
}
.ui.grid [class*="right floated"].column {
margin-left: auto;
}
If you want margin-left and margin-right to have the auto value, you must have a duplicate of the classname segment floated (ex. <div class="left floated right floated">Lorem</div>)
The DOM-API provides a convenient way for adding and removing and testing class-names of DOM-elements: classList.add(name) and classList.remove(name) and classList.contains(name).
In the ES6 context the question could perhaps be rephrased as:
"If I use .classList.add() to add the same className more than once, and then want to remove that class with classList.remove(), do I need to call classList.remove() multiple times?
Luckily the answer seems to be a single call to .classList.remove() is enough to remove a given class no matter how many times you have added it.
I couldn't find an easy answer to this by Google so I wrote the following test to tell me that is how it behaves. Calling the below function with DOM-element as argument does NOT throw an error:
function testClassListRemove (dem)
{
dem.classList.add ("hello");
dem.classList.add ("hello");
dem.classList.add ("hello");
ok (dem.classList.contains ("hello") );
dem.classList.remove ("hello");
ok (! dem.classList.contains ("hello") );
function ok (b)
{ if (! b)
{ throw new Error ('not ok ');
}
}
}
Related
Im trying to make a simple quiz with a dynamic questions using Jinja (so a bit of python as well) + some SQL + JS.
Since im quite new to this, I was trying to do a simple "click here -> change color to green if your answer is the right one"
Here's the thing: to not complicate things, i want every answer to change the color to red (if wrong) or green (if right). Right know, thanks to this thread Javascript getElementById based on a partial string i manage to create a function that turns the right answer to green wih the code, no matter where the user clicks (as long its inside the question box answers):
document.querySelector('[ id$="{{ question.correct_answer }}"]').style.backgroundColor="rgb(0, 221, 135)";
I thought i could do something like "id$!=" and that would solve my problem, but that didnt work. So i tried to search for other stuff like the :not or not() selectors, but that showed me a lot of jquery stuff, which im not studying/learning right now. So, is there any way to write:
"if the id$ does not match the value {{ question.correct_answer }}, turn red" in plain JS?
Some important stuff about the code:
All answers have id="answer_a", "answer_b" etc.
That matches the way i save que "correct_answer" in the database, which comes exactly like the ID (so if the correct_answer is answer_d, i can call "{{ question.correct_answer }}" and that will always turn D into GREEN;
my HTML looks like <div class=question_answer id="answer_d" onclick="selecResposta()"> {{ question.answer_d }} </div> <br>. These are inside a DIV called "question_options" which i can also put the "onclick" function and everything works the same.
I can provide more information if necessary.
Thanks a lot for the help and sorry if this is something easy to solve. Any guidance (if you dont wanna say the answer) is quite welcome as well.
UPDATE:
Thanks to #connexo and #Vijay Hardaha, i manage to mix both answers and create a code that helped me. It might not be pretty, but its doing what i want so its perfect. Here's the solution:
html part:
<div class=question_answer data-answer="answer_a"> {{ question.answer_a }} </div> <br>
etc.etc
js:
function selecRightAnswer() {
document.querySelector("[data-answer={{ question.correct_answer }}]").style.backgroundColor="rgb(0, 221, 135)";
}
function selectWrongAnswer() {
const elements = document.querySelectorAll("div.question_answer:not([data-answer={{ question.correct_answer }}])");
elements.forEach(function (element) {
element.style.backgroundColor = "red";
});
}
Selects div with class question_answer when div has id=answer_a with an exact match.
document.querySelector("div.question_answer[id=answer_a]");
Selects div with class question_answer when div doesn't have id=answer_a with an exact match.
document.querySelector("div.question_answer:not([id=answer_a])");
document.querySelector will only selector first matched div. so if you have to work with all
unmatched with answer_a then you need to use document.querySelectorAll
and then you'll have to loop reach element and work with each element inside the loop.
Example
const elements = document.querySelectorAll(".box");
elements.forEach(function (element) {
element.style.color = "green";
});
I have been looking with no success to see if I can dynamically apply a css style to JSF component or div using javascript. Is this possible.
This is pseudo code
<div style="myJSStyleFunction("#{myBean.value}")"> stuff </div>
And the function would return something like "position:relative;left:25px;"
I've had no luck and maybe it can't be done but would like a second opinion.
Edit:
I'm trying to see if I can keep a separation / reduce the coupling between the presentation/view and the model/controller. This is for indenting commenting or product reviews (to nest replies to comments or reviews). The most I really want to track is an integer on how deep a reply is. First level = 0 second level = 1, and so on. So a comment or product review would be 0 deep, a reply to the comment or review would be 1 and so on.
Then in the EL I wanted to call a javascript function and do something like
<script>
myJSStyleFunction(depth){
if(depth<=5){
var nest=20*depth;
var style="position:relative;left:" + nest + "px;";
return style;
}
}
</script>
And then then say for a third level comment (a reply to a reply) it would look like this:
<div style="position:relative;left:40px;"> stuff </div>
where
#{myBean.value}
evaluates to 2
I suspect like Daniel says I'll have to tightly couple the view but I'd rather not have to. I'd think there has to be a way. But maybe not.
I don't know where there are cleaner solutions for this. However this is one suggestion.
Assume your page looks like below and myBean.getValue() method returns an integer.
<h:form id="frm">
<div style="#{myBean.value}"> div1 </div>
<div style="#{myBean.value}"> div2 </div>
</h:form>
So you can do something like this at 'window.onload'.
<head>
<script>
window.onload = function() {
var childList = document.forms['frm'].childNodes;
for(var i = 0; i < childList.length; i++) {
if(childList[i].nodeName == 'DIV') {
var _div = childList[i];
var depth = _div.getAttribute('style');
_div.setAttribute('style', 'position:relative;left:' +(depth *20)+ 'px;');
}
}
}
</script>
</head>
Note: 1. In above sample code I assume all the DIVs inside the form should be indented.
2. For IE you may need to use _div.style.setAttribute('cssText','position:relative;left:' +(depth *20)+ 'px;')
3. Another solution for your question is using <script> tags immediately after your divs and putting the js part inside them. In this way you don't have to use fake styling style="#{myBean.value}" or window.onload event because you can directly call #{myBean.value} in your script.
I decided to skip the javascript approach and settled on a simpler and I think cleaner method to create the dynamic css classes for my situation. I already capture/calculate the depth value for each comment when it is entered. So I am just returning that value in EL and concatenating it to a 'base name' for the css class like so:
<div class="indent_#{(comment.commentDepth le 5) ? comment.commentDepth : 5}" >
comment comment blah blah blah
</div>
"indent_" is the base name for the css class. So for a 0 level comment it will have a class="indent_0". A reply to that comment will have class="indent_1".
I use the ternary so that if there are lot of replies under a given comment it doesn't indent right off the right hand side of the page. Even though you can keep going deeper, it will only indent up to 5 levels.
For my case at the moment, this is a simpler and cleaner method of adding some dynamically generated css class names. Right now I have to define 6 classes for this in the css file, but perhaps I'll figure out how to nest the boxes but it isn't a priority this works just fine for me for now.
Is it in any way possible, to change a css class model using JavaScript?
Pseudo code:
function updateClass(className, newData) {
cssInterface.alterClass(className, newData);
}
className being the name of the class, which is supposed to be changed (like ".footer") and newData being the new class content (like border: "1px solid pink;").
The target is, actually, just to save space: I am working with CSS3-animations, so changing one attribute of an element, which is affected by it's class, will terminate the animation of of it - The (in my case) font size won't change anymore. Using different classes will require an entire new set of classes for all affected elements, I'd like to avoid this.
I am not searching for a change via
element.className = "foo";
or
element.style.fontSize = "15pt";
Thanks for your help, guys :)
Here's my function to do this...
function changeCSS(typeAndClass, newRule, newValue) // modify the site CSS (if requred during scaling for smaller screen sizes)
{
var thisCSS=document.styleSheets[0] // get the CSS for the site as an array
var ruleSearch=thisCSS.cssRules? thisCSS.cssRules: thisCSS.rules // work out if the browser uses cssRules or not
for (i=0; i<ruleSearch.length; i++) // for every element in the CSS array
{
if(ruleSearch[i].selectorText==typeAndClass) // find the element that matches the type and class we are looking for
{
var target=ruleSearch[i] // create a variable to hold the specific CSS element
var typeExists = 1;
break; // and stop the loop
}
}
if (typeExists)
{
target.style[newRule] = newValue; // modify the desired class (typeAndClass) element (newRule) with its new value (newValue).
}
else
{
alert(typeAndClass + " does not exist.");
}
}
Called with (example)
changeCSS("div.headerfixed","-moz-transform-origin", "100% 0%");
hope this helps.
See my answer here. To answer your question: Yes, it's possible.
#CSS3: I tried exactly the same in one of my html5 experiments. I created an extra <style> element, and changed its contentText to the CSS class definitions I needed. Of course changing the cssRule object would be much cleaner :-)
As far as I can tell the CSS object model cannot easily tell you whether you already have an existing style rule for a particular class, but you can easily append a new rule for that class and it will override any previous declaration of that style.
I found an example of creating dynamic stylesheets.
You should take a look at dojo, it has some nice features where you can do just that..
require(["dojo/dom-class"], function(domClass){
// Add a class to some node:
domClass.add("someNode", "anewClass");
});
http://dojotoolkit.org/reference-guide/1.7/dojo/addClass.html
Having trouble getting the following code to work:
$('#changeMode').button().click(function(){
$('#playfield').toggle(function() {
$(this).switchClass("gridView","plainView");
}, function() {
$(this).switchClass("plainView","gridView");
});
});
I cannot get it to switch the following div's class.
<div id="playfield" class="gridView"></div>
Any ideas?
EDIT: I tried this:
$('#changeMode').button().click(function(){
if ($('#playfield').attr('class') == "gridView"){
$('#playfield').removeClass("gridView");
$('#playfield').addClass("plainView");
} else {
$('#playfield').removeClass("plainView");
$('#playfield').addClass("gridView");
}
});
And it seems to work fine, what the heck?
I wasn't aware of a switchClass, perhaps you were thinking of toggleClass? Anyways - I had some old code that used this (I was having some strange issues with toggleClass):
$(this).removeClass("gridView").addClass("plainView");
or
$(this).toggleClass("gridView plainView");
and vice versa.
Example:
$('#changeMode').button().click(function(){
$('#playfield').toggle(function() {
$(this).toggleClass("gridView plainView");
//$(this).removeClass("gridView").addClass("plainView");
}, function() {
$(this).toggleClass("plainView gridView");
//$(this).removeClass("plainView").addClass("gridView");
});
});
But as others have suggested toggleClass should work for your needs.
The correct syntax is to use "One or more class names (separated by spaces).." ( from .toggleClass()) within the first parameter, rather than quoting classnames in the first and second parameter.
e.g.
$(this).toggleClass("gridView plainView");
just use the toggleClass twice will do the magic . toggoleClass refference to Jquery
This method takes one or more class names as its parameter. In the first version, if an element in the matched set of elements already has the class, then it is removed; if an element does not have the class, then it is added.
as for ur problem .
$('#changeMode').button().click(function(){
$(this).toggleClass('gridView').toggleClass('plainView');
});
help this will solve ur problem .
#Guy toggleClass('gridView plainView') this will actually be alternates bettween
<div class="gridView plainView"> and <div class=" ">. and not toggle bettween the two classe . no offence . hope this will do some help .
jQuery also has a toggleClass API:
http://api.jquery.com/toggleClass/
This works just like what Rionmonster suggested, adding classes when they aren't set on the class and removing them when they are already set.
Hey guys, the question pretty much asks itself... however, for more clarity:
I have an element called "chuckPalahniuk" and it has classes named "choke", "fightclub" and "haunted".
How could I get it so when I click on the "chuckPalahniuk" element, it removes "haunted" first, then "fightclub" on the second click and "choke" on the third?
also: be aware that the class names are dynamically added.
Cheers. peeeps!
psy.example:
$('#chuckPalahniuk').click(function() {
$(this).removeLastClassAdded(); //except this function doesn't exist...
});
just save in an array variable c every class you add c.push('yourclass'), then $(this).removeClass(c.pop());
http://www.devguru.com/technologies/ecmascript/quickref/pop.html
This will do it and will deal with leading and trailing whitespace, which a split()-based solution will not:
$('#chuckPalahniuk').click(function() {
this.className = this.className.replace(/(^|\s+)[^\s]+(\s+)?$/, "");
});
Something like:
$('#chuckPalahniuk').click(function() {
$(this).removeClass($(this).attr('class').split(/\s+/).pop());
});