Removing specific classes from all div elements of certain format - javascript

I would like to remove all classes starting with nf-
Console image
JSfiddle
https://jsfiddle.net/zapjelly/fda3Lm84/11/
I have the following HTML/JS:
var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');
Array.prototype.map.call(nfClasses, function(elem) {
Array.prototype.map.call(elem.classList, function(classStr) {
if (classStr.match(/^nf\-/)) elem.classList.remove(classStr);
});
});
<p>Remember to inspect element on the input below</p>
<div class="custom-nf">
<div class="input nf-input-outer nf-validation">
<div class="nf-container">
<div class="nf-outer nf-outer-input nf-outer-validation">
<div class="nf-middle">
<div class="nf-inner">
<label for="dummy" class="nf-label"></label>
<input id="dummy" type="text" class="nf-input">
</div>
</div>
</div>
</div>
</div>
</div>

As stated by MDN, the .classList property returns a live DOMTokenList of the class attributes of the element. The key point is that the list is live, which means that as you remove classes, you are inadvertently skipping over some of the other classes while iterating over them.
Based on the code that you provided, you could simply create a copy of the class list so that it is no longer live. You can do this by calling the .slice() method:
Updated Example
var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');
Array.prototype.forEach.call(nfClasses, function(element) {
var classListCopy = Array.prototype.slice.call(element.classList);
classListCopy.forEach(function(className) {
if (className.match(/^nf\-/)) {
element.classList.remove(className);
}
});
});
Alternatively, you could also iterate over the classes backwards. In doing so, none of the classes will be skipped:
Updated Example
var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');
Array.prototype.forEach.call(nfClasses, function(element) {
for (var i = element.classList.length; i >= 0; i--) {
if (element.classList[i] && element.classList[i].match(/^nf\-/)) {
element.classList.remove(element.classList[i]);
}
}
});
A third option would be to just use a regular expression to replace the classes:
var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');
Array.prototype.forEach.call(nfClasses, function(element) {
element.className = element.className.replace(/\bnf-\S+\b/g, '').trim();
});

Updated inner loop to slice as suggested and working now
https://jsfiddle.net/zapjelly/fda3Lm84/12/
var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');
Array.prototype.map.call(nfClasses,
function(elem){
Array.prototype.slice.call(elem.classList).map(
function(classStr){
if(classStr.match(/^nf\-/)) elem.classList.remove(classStr);
})
});

Related

JavaScript possible to select all elements with classname that starts with (...)? [duplicate]

I'm trying to only show certain divs. The way I have decided to do this is to first hide all elements that start with "page" and then only show the correct divs. Here's my (simplified) code:
<form>
<input type="text" onfocus="showfields(1);">
<input type="text" onfocus="showfields(2);">
</form>
<div class="page1 row">Some content</div>
<div class="page1 row">Some content</div>
<div class="page2 row">Some content</div>
<div class="page2 row">Some content</div>
<script>
function showfields(page){
//hide all items that have a class starting with page*
var patt1 = /^page/;
var items = document.getElementsByClassName(patt1);
console.log(items);
for(var i = 0; i < items.length; i++){
items[i].style.display = "none";
}
//now show all items that have class 'page'+page
var item = document.getElementsByClassName('page' + page);
item.style.display = '';
}
</script>
When I console.log(items); I get a blank array. I'm pretty sure the regexp is right (get all items starting with 'page').
The code I'm using is old school JS, but I'm not adverse to using jQuery. Also if there is a solution that doesn't use regexp, that's fine too as I'm new to using regexp's.
getElementsByClassName only matches on classes, not bits of classes. You can't pass a regular expression to it (well, you can, but it will be type converted to a string, which is unhelpful).
The best approach is to use multiple classes…
<div class="page page1">
i.e. This div is a page, it is also a page1.
Then you can simply document.getElementsByClassName('page').
Failing that, you can look to querySelector and a substring matching attribute selector:
document.querySelectorAll("[class^=page]")
… but that will only work if pageSomething is the first listed class name in the class attribute.
document.querySelectorAll("[class*=page]")
… but that will match class attributes which mention "page" and not just those with classes which start with "page" (i.e. it will match class="not-page".
That said, you could use the last approach and then loop over .classList to confirm if the element should match.
var potentials = document.querySelectorAll("[class*=page]");
console.log(potentials.length);
elementLoop:
for (var i = 0; i < potentials.length; i++) {
var potential = potentials[i];
console.log(potential);
classLoop:
for (var j = 0; j < potential.classList.length; j++) {
if (potential.classList[j].match(/^page/)) {
console.log("yes");
potential.style.background = "green";
continue elementLoop;
}
}
console.log("no");
potential.style.background = "red";
}
<div class="page">Yes</div>
<div class="notpage">No</div>
<div class="some page">Yes</div>
<div class="pageXXX">Yes</div>
<div class="page1">Yes</div>
<div class="some">Unmatched entirely</div>
Previous answers contain parts of the correct one, but none really gives it.
To do this, you need to combine two selectors in a single query, using the comma , separator.
The first part would be [class^="page"], which will find all the elements whose class attribute begins with page, this selector is thus not viable for elements with multiple classes, but this can be fixed by [class*=" page"] which will find all the elements whose class attribute have somewhere the string " page" (note the space at the beginning).
By combining both selectors, we have our classStartsWith selector:
document.querySelectorAll('[class^="page"],[class*=" page"]')
.forEach(el => el.style.backgroundColor = "green");
<div class="page">Yes</div>
<div class="notpage">No</div>
<div class="some page">Yes</div>
<div class="pageXXX">Yes</div>
<div class="page1">Yes</div>
<div class="some">Unmatched entirely</div>
You can use jQuery solution..
var $divs = $('div[class^="page"]');
This will get all the divs which start with classname page
$(document).ready(function () {
$("[class^=page]").show();
$("[class^=page]").hide();
});
Use this to show hide div's with specific css class it will show/hide all div's with css class mention.

querySelectorAll for grouped data-attributes

Suppose I have the following markup...
<div data-namespace-title="foo"></div>
<div data-namespace-description="bar"></div>
<div data-namespace-button="foo"></div>
Is there anyway in which I can select of them with a querySelectorAll?
I've tried document.querySelectorAll([data-namespace-*]), but that doesn't work of course
There is no easy way to do it, simply because the browser does not implement wildcard selectors on the attribute name/key (only on its value). What you can do is to simply iterate through your element set (in this case, their common denominator is div), and then filter them out.
You can access the list of attributes of each DOM node by calling <Node>.attributes, and then convert that into an array, and check if one or more of each attribute's name matches the regex pattern /^data-namespace-.*/gi:
var els = document.querySelectorAll("div");
var filteredEls = Array.prototype.slice.call(els).filter(function(el) {
var attributes = Array.prototype.slice.call(el.attributes);
// Determine if attributes matches 'data-namespace-*'
// We can break the loop once we encounter the first attribute that matches
for (var i = 0; i < attributes.length; i++) {
var attribute = attributes[i];
// Return the element if it contains a match, and break the loop
if (attribute.name.match(/^data-namespace-.*/gi))
return el;
}
});
console.log(filteredEls);
<div data-namespace-title="foo">title</div>
<div data-namespace-description="bar">description</div>
<div data-namespace-button="foobar">button</div>
<div data-dummy>dummy</div>
Update: if you're familiar with ES6, it gets a lot cleaner, because:
We can use Array.from in place of the cumbersome Array.prototype.slice.call(...). Pro-tip: you can also use the spread operator, i.e. const els = [...document.querySelectorAll("div")].
We can use Array.some in place of manually creating a for loop with return logic
const els = Array.from(document.querySelectorAll("div"));
const filteredEls = els.filter(el => {
const attributes = Array.from(el.attributes);
return attributes.some(attribute => attribute.name.match(/^data-namespace-.*/gi));
});
console.log(filteredEls);
<div data-namespace-title="foo">title</div>
<div data-namespace-description="bar">description</div>
<div data-namespace-button="foobar">button</div>
<div data-dummy>dummy</div>
Not sure if you would be up for changing the format of you attributes, but making them all the same and adding an extra attribute could be of use if you want to using querySelectorAll
Array.from(document.querySelectorAll('[data-namespace]')).forEach(el => {
console.log(el.getAttribute('data-value'))
})
<div data-namespace="title" data-value="foo"></div>
<div data-namespace="description" data-value="bar"></div>
<div data-ns="button" data-value="foo"></div>
<div data-namespace="button" data-value="foo"></div>
Your other option is to use xpath.
Note: When using iterateNext() it will break if you modify the document before calling it.
var divs = document.evaluate('//#*[starts-with(name(.), "data-namespace")]', document, null, XPathResult.ANY_TYPE, null);
var div = divs.iterateNext()
while (div) {
alert(div.ownerElement.textContent)
div = divs.iterateNext()
}
<div data-namespace-title="foo">Foo</div>
<div data-namespace-description="bar">Bar</div>
<div data-ns-button="foo">NS Foo</div>
<div data-namespace-button="foo">Foo</div>
There's no built-in selector for such a thing, but you can still accomplish it easily enough, by selecting all elements and then filtering for those which have an attribute that starts with data-namespace:
console.log(
[...document.querySelectorAll('*')]
.filter(({ attributes }) =>
[...attributes].some(({ name }) => name.startsWith('data-namespace'))
)
);
<div data-baz="baz"></div>
<div data-namespace-title="foo"></div>
<div data-namespace-description="bar"></div>
<div data-namespace-button="foo"></div>

Using checkboxes to update UI in realtime

I'm currently in the process of trying to develop a smarter UI for one of my clients. However the only code I can use to develop this 'feature', is pure JS. I have no access to the source HTML or CSS files the only access I have is the ability to inject JavaScript through an external .js file.
I'm not too familiar with JS, but I can work my way around a basic script or two.
Scenario
What we're doing is allowing users to edit PDF Templates online using a software called Core Create. The UI accessed through the browser is quite cluttered and I would like to provide an option to hide and show UI elements <textareas>/<inputs> through the use of checkboxes.
Here is a very basic JS Fiddle that I have built with the
intention of hiding and displaying UI.
The page in question
Above is a screen grab of the page I am working with, on the left you can see the UI and its composition on the right within the 'Inspect Element' tool.
I have come to the conclusion that I need to iterate through the highlighted selection and link them accordingly with seven checkboxes. The result would then be a selection of checkboxes that would hide / display the correct UI element.
The Caveat
In realizing I cannot edit or introduce new HTML I noticed the lack of on-click attributes. So I'm a bit lost on how to invoke the JavaScript I will eventually build.
My Question
With my limited knowledge of JS I don't know how I would iterate though div elements editoraccvar - editoraccvar6 picking out the ones I need to manipulate.
Due to the lack of ID's / Names (I assume it would have to be done using Parent/Child rules somehow, as the classes are widley used by the rest of the UI. I would appreciate a small example demonstrating how I could achieve this, so I can learn from it.
I should clarify, I have already added the checkboxes to the page, I just need to build the JS link between the Checkbox and the UI element I'm attempting to target. You can find all attributes linking to these checkboxes included in the JS Fiddle.
EDIT // A Working Simplified Example;
Due to some confusion I have 'frankensteined' some code together to show the final result I am after. A working example of sorts. The actual result needs to target 7 Checkboxes and 7 Divisions. I'll list thier common properties below.
// This script is already in place and constructed by the system.
// Written inside script tags and located straight after 'editopt1'.
// $(document).ready(function() {
// $('#checkboxopt1').click(function() {
// if ($('#checkboxopt1').val() == 'true') {
// $('#opt1').val('false');
// $('#checkboxopt1').val('false');
// $('#checkboxopt1').prop('checked', false);
// $('#previewrefresh').trigger('click');
// } else {
// $('#opt1').val('true');
// $('#checkboxopt1').val('true');
// $('#checkboxopt1').prop('checked', true);
// $('#previewrefresh').trigger('click');
// };
// });
// });
function exFunction() {
// Check the function is called
console.log("200 : OK");
// grab all elements with the class, .field-summernote
var uiblocks = document.querySelectorAll('.field-summernote');
for (var i = 0; i < uiblocks.length; i++) {
var current = uiblocks[i];
if (current.className.indexOf('editoraccvar') < 0) //not found: -1
return;
// check elements in the array
console.log(current);
// control the elemets in the array.
if (document.getElementById('checkboxopt1').checked) {
uiblocks[0].style.display = 'block'; // display the element
} else {
uiblocks[0].style.display = 'none'; // hide the element
}
}
};
// Trigger the collection the check, and the control.
var x = document.getElementById("checkboxopt1");
x.addEventListener("click", function() {
console.log("Opt");
exFunction();
});
.editoraccvar1 {
width: 300px;
background: #0ff;
padding: .5em;
}
.editoropt1 {
width: 300px;
background: #ff0;
padding: .5em;
}
textarea {
display: block;
width: 95%;
resize: none;
padding: .5em;
}
<!-- I'm trying to hide & show this entire division... -->
<div class="seq-box-form-field field-summernote editoraccvar1 ">
<label for="accvar1">Ground Floor Info</label>
<div class="clearfix"></div>
<textarea id="richaccvar1" name="richaccvar1" class="summernote"></textarea>
<input type="hidden" name="accvar1" id="accvar1" value="" />
</div>
<!-- Using only what the system has supplied. -->
<div class="seq-box-form-field editoropt1 ">
<label for="opt1"><span style="padding-right: 10px; vertical-align: 1px;">Ground Floor </span>
<input type="checkbox" name="checkboxopt1" id="checkboxopt1" value="true" checked="true" />
<input type="hidden" name="opt1" id="opt1" value="true" />
</label>
</div>
Divisions <div class=""></div>
* editoraccvar,
editoraccvar1,
editoraccvar2,
editoraccvar3,
editoraccvar4,
editoraccvar5,
editoraccvar6*
Checkboxes <input id=""></input>
* checkboxopt,
checkboxopt1,
checkboxopt2,
checkboxopt3,
checkboxopt4,
checkboxopt5,
checkboxopt6,*
As far as I can see, your problem boils down to link checkboxes (that seem to have been generated in some way) to "division" parts of your html that you want to hide. Plus, you have to inject javascript code in the page (so I guess the less code the better).
One approach could be as follows:
// Wrap the code in an anonymus function, to avoid clustering the global space.
(function (domElements) {
// This is the callback that will fire when a checkbox is clicked.
function clickCallback() {
// the context of this callback is the DOM element thus we can access its attributes through this.
// extract the checkNumber of the class of the element. This number is the link to the division that we want to hide/show.
var checkNumber = ((/ editoropt(\d*) /).exec(this.className))[1],
checkBox = document.getElementById('checkboxopt' + checkNumber),
division = document.querySelectorAll('.editoraccvar' + checkNumber)[0];
// Hide/show division, update checkBox state.
toggleElements(division, checkBox, window.getComputedStyle(division).display === 'none');
}
function toggleElements(division, checkBox, isShown) {
// Toggle the division (show/hide) accordingly.
division.style.display = isShown ? 'block' : 'none';
// Due to the fact that the event listener is attached to the parent of the checkBox, we need to maintain consistency manually.
checkBox.checked = isShown;
}
// Remove from the array of DOMElements those that aren't checkboxes and add a click event listener to each of them.
domElements
.filter(function (el) {
return el.className.indexOf('editoropt') !== -1;
})
.forEach(function (el) {
el.addEventListener('click', clickCallback, false);
});
// Call the function passing the dom elements with class '.seq-box-form-field' as argument. Checkboxes are contained within them. Also, transform the nodelist
// into a proper array so that methods defined in Array.prototype can be used.
})([].slice.call(document.querySelectorAll('.seq-box-form-field')));
The code is commented and (I think) quite self-explanatory. However, if you have any doubt or want me to elaborate any point further, please, let me know.
Finally, here's the working fiddle.
UPDATE
Same function (more or less) but now it accepts an array of values that will correspond to the initial state of the checkboxes:
(function (domElements, cbState) {
function clickCallback() {
toggleElements(this.className);
}
function toggleElements(className, initialShow) {
var checkNumber = ((/ editoropt(\d*) /).exec(className))[1],
checkBox = document.getElementById('checkboxopt' + checkNumber),
division = document.querySelectorAll('.editoraccvar' + checkNumber)[0],
isShown = initialShow === undefined ? window.getComputedStyle(division).display === 'none' : initialShow;
division.style.display = isShown ? 'block' : 'none';
checkBox.checked = isShown;
}
domElements
.filter(function (el) {
return el.className.indexOf('editoropt') !== -1;
})
.forEach(function (el, index) {
el.addEventListener('click', clickCallback, false);
toggleElements(el.className, cbState[index]);
});
// Initial state of the checkboxes goes in the second parameter. The index in the array correspond to the checkbox position in the page.
})([].slice.call(document.querySelectorAll('.seq-box-form-field')), [false, false]);
Here's the Fiddle to play with. Hope it helps.
The other half of your problem, not addressed in the other answer has to do with events. Generally, adding an "onclick" attribute to the actual HTML is considered bad practice. You can attach event handlers with Javascript.
var a = document.getElementById("checkboxopt1");
a.addEventListener("click", exFunction, false);
See the manual for more info about how to use this.
Looks like that you need the elements that have the class "field-summernote", but not the class "editorbdyvar".
You can use a query selector to get elements by class name using the default tools from Javascript:
var items = document.querySelectorAll('.field-summernote');
for(var i = 0; i<items.length; i++){
var current = items[i];
if( current.className.indexOf('editoraccvar') < 0) //not found: -1
return;
//now you can manipulate the current element
console.log(current);
}
well ... you should either learn javascript, DOM, HTML and CSS or hire an somebody that can do it.
in my opinion the latter would come cheaper.
if not,
here goes something to put in your script.js file.
the checkboxes must have the id="toggleTextareas" respectively id="toggleInputs".
(function isolateScope() {
tryInit();
function tryInit() {
if(document.readyState!="complete"){
setTimeout(tryInit, 100);
}else{
createUI();
init();
}
}
function createUI(){
var div=document.createElement("div");
div.className="addon-floating-toolbar"
div.style.position="fixed";
div.style.zIndex="999999";
div.style.background="#EEE";
div.style.padding="5px";
div.innerHTML='<input type="checkbox" id="toggleTextareas">toggle Textareas<br>'
+'<input type="checkbox" id="toggleInputs">toggle Inputs';
document.body.appendChild(div);
}
function init() {
var tta=document.getElementById("toggleTextareas");
var ti=document.getElementById("toggleInputs");
var textareaVisible=true;
var inputVisible=true;
tta.onclick=toggleTextareas;
ti.onclick=toggleInputs;
function toggleTextareas() {
var elms=document.querySelectorAll("textarea");
textareaVisible=!textareaVisible;
if (textareaVisible) {
show(elms);
}else{
hide(elms);
}
}
function toggleInputs() {
var elms=document.querySelectorAll("input");
inputVisible=!inputVisible;
if (inputVisible) {
show(elms);
}else{
hide(elms);
}
}
function show(collection) {
for (var i = 0; i < collection.length; i++) {
collection[i].style.display="";
}
}
function hide(collection) {
for (var i = 0; i < collection.length; i++) {
collection[i].style.display="none";
}
}
}
})();
let me know if it works,
cheers.
You can traverse all your fields and generate a checkbox that will toggle it open/close for each of your fields. Also set the checkbox label as innerText of the corresponding field.
// Block to be run
generateCheckboxes = function() {
var button = document.getElementById("generateButton");
button.parentNode.removeChild(button);
// grab all elements with the class, .field-summernote
var uiblocks = [].slice.call(document.querySelectorAll('.field-summernote')).filter(function(x) {
return x.className.indexOf('editoraccvar') >= 0
});
if (!uiblocks.length) return;
var chcontainer = document.createElement('div');
chcontainer.style.display = "inline-block";
document.body.insertBefore(chcontainer, document.body.children[0]);
uiblocks.forEach(function(x) {
var cdiv = document.createElement('div');
var clabel = document.createElement('label');
clabel.innerHTML = x.innerText.trim();
var cinput = document.createElement('input');
cinput.type = 'checkbox';
cinput.checked = true;
cinput.onchange = function(ev) {
var checked = this.checked;
x.style.display = checked ? "" : "none";
}
cdiv.appendChild(clabel);
cdiv.appendChild(cinput);
cdiv.appendChild(document.createElement('br'));
chcontainer.appendChild(cdiv);
})
};
#container {
width: 150px;
}
input {
float: left;
}
label {
width: 120px;
display: block;
float: right;
text-align: left;
}
<button onclick="generateCheckboxes()" id="generateButton">Generate Checkboxes</button>
<div id="example" class="field-summernote editoraccvar">
<br/>
<br/>
<span>Zero</span>
<br/>
<textarea></textarea>
</div>
<div id="example1" class="field-summernote editoraccvar1">
<br/>
<br/>
<span>One</span>
<br/>
<textarea></textarea>
</div>
<div id="example2" class="field-summernote">
<br/>
<br/>
<span>Two</span>
<br/>
<textarea></textarea>
</div>
Fiddle

display form validation hint with form elements

I use this java script function to display a form validation hint. This function is working properly with input elements.. My problem is I need to modify this function with other form elements such as textarea, select box, checkbox... can anybody tell me how can I do this?
This is the function I have been using..
function prepareInputsForHints() {
var inputs = document.getElementsByTagName("input");
for (var i=0; i<inputs.length; i++){
// test to see if the hint span exists first
if (inputs[i].parentNode.getElementsByTagName("span")[0]) {
// the span exists! on focus, show the hint
inputs[i].onfocus = function () {
this.parentNode.getElementsByTagName("span")[0].style.display = "inline";
}
// when the cursor moves away from the field, hide the hint
inputs[i].onblur = function () {
this.parentNode.getElementsByTagName("span")[0].style.display = "none";
}
}
}
// repeat the same tests as above for selects
var selects = document.getElementsByTagName("select");
for (var k=0; k<selects.length; k++){
if (selects[k].parentNode.getElementsByTagName("span")[0]) {
selects[k].onfocus = function () {
this.parentNode.getElementsByTagName("span")[0].style.display = "inline";
}
selects[k].onblur = function () {
this.parentNode.getElementsByTagName("span")[0].style.display = "none";
}
}
}
}
this is Html
<div>
<label for="mobile">Mobile<img alt="required" src="images/required_star.png"> :</label>
<input id="mobile" class="text" type="text" maxlength="10" name="mobile" title="Eg: 0714556260"/>
<span class="hint">Use a 10 digits length number<span class="hint-pointer"> </span></span>
</div>
I tried something like this with textarea but it is not working...
<div>
<label for="qualification">Qualification Details<img alt="required" src="images/required_star.png">:</label>
<textarea id="qualification" class="textarea" rows="4" cols="30" name="qualification"></textarea>
<span class="hint">Describe about you<span class="hint-pointer"> </span></span>
</div>
$(document).ready( function() {
$(".hint").css({ "display":"none" });
$("input.hint_needed, select.hint_needed, textarea.hint_needed, radio.hint_needed").on("mouseenter", function() {
$(".hint").css({ "display":"inline" });
}).on("mouseleave", function() {
$(".hint").css({ "display":"none" });
});
});​
<textarea id="qualification" class="hint_needed" rows="4" cols="30" name="qualification"></textarea>
you can use this!
http://jsfiddle.net/QD3Hn/1/
Update: Per OP's request, allow hints to be displayed on hover as well.
Here's what I have based on non-jQuery implementation of the code:
(JSFiddle: http://jsfiddle.net/E9njP/)
<div>
<label for="mobile">Mobile* :</label>
<input id="mobile" class="text" type="text" maxlength="10" name="mobile" />
<span class="hint">Use a 10 digits length number</span>
</div>
<div>
<label for="qualification">Qualification Details*:</label>
<textarea id="qualification" class="textarea" rows="4" cols="30" name="qualification"></textarea>
<span class="hint">Describe about you</span>
</div>
<div>
<label for="dropdown">Dropdown*:</label>
<select id="dropdown"><option>A</option><option>B</option></select>
<span class="hint">Hints for Select</span>
</div>
<!-- This is just for demo purpose -->
<div>
<label>Tricky Input:</label>
<input/>
<span>Don't hide me! I am not a hint!</span>
</div>
... Instead of doing CSS on the element, I'm using CSS instead. Here are the classes...
div span.hint {
display: none;
}
div span.over,
div span.focus {
display: inline;
}
... and here's the javascript ...
(function() {
// Since it's likely that you'll only ever run this function once
// (Once you attached the events, you'll probably never reuse this
// function again), I put it inside an IIFE to keep it "clean".
/**
* Toggle class on element without jQuery...
*
* #param {DOMElement} el Element to apply CSS to
* #param {string} css CSS class name to be applied
* #param {boolean} on Determine whether class name should be on the element or not
**/
function getHandler(el, css, on) {
return function() {
// If we want to add CSS to the element, and it doesn't exist on the
// element yet, add it.
if (on && el.className.indexOf(css) === -1) {
el.className += ' ' + css;
}
// If we want to remove CSS from the element, and it exists, remove
// it.
else if (!on && el.className.indexOf(css) >= 0) {
el.className = el.className.replace(css, '');
}
// NOTE This solution will lead to extra spacing in CSS name...
};
}
function setHandler(inputEl, hintEl) {
// the span exists! on focus, show the hint
inputEl.onfocus = getHandler(hintEl, "focus", true);
inputEl.onmouseover = getHandler(hintEl, "over", true);
// when the cursor moves away from the field, hide the hint
inputEl.onblur = getHandler(hintEl, "focus", false);
inputEl.onmouseout = getHandler(hintEl, "over", false);
}
function prepareHintsByTag(tag) {
var inputs = document.getElementsByTagName(tag);
for (var i=0; i<inputs.length; i++){
// test to see if the hint span exists first
if (inputs[i].parentNode.getElementsByTagName("span")[0]) {
var hintEl = inputs[i].parentNode.getElementsByTagName("span")[0];
// Show "hint" only if it has the class of "hint"
if (hintEl.className.indexOf("hint") === 0) {
setHandler(inputs[i], hintEl);
}
}
}
}
// Scan the code
prepareHintsByTag("input");
prepareHintsByTag("textarea");
prepareHintsByTag("select");
})();
​
Added couple of things to the code...
By default, the hints should probably be hidden. I made that a default in CSS.
Added a check to see if the "span" class is of "hint" before toggling the CSS. (Just so you won't hide something that wasn't intended!)
I refactored the prepareHint function so it's reusable for SELECT, INPUT and TEXTAREA.
I put the function that handles prepare hints in an IIFE, since it's likely that you'll only do this one. You can read more about IIFE here: http://benalman.com/news/2010/11/immediately-invoked-function-expression/
Instead of doing style manipulation on the element's style directly, I moved those to CSS classes. It should make more sense hopefully...
This is, again, the non-jQuery version - There are more rooms for improvements, but hopefully this would be sufficient for your task.

jQuery to loop through elements with the same class

I have a load of divs with the class testimonial and I want to use jquery to loop through them to check for each div if a specific condition is true. If it is true, it should perform an action.
Does anyone know how I would do this?
Use each: 'i' is the postion in the array, obj is the DOM object that you are iterating (can be accessed through the jQuery wrapper $(this) as well).
$('.testimonial').each(function(i, obj) {
//test
});
Check the api reference for more information.
try this...
$('.testimonial').each(function(){
//if statement here
// use $(this) to reference the current div in the loop
//you can try something like...
if(condition){
}
});
It's pretty simple to do this without jQuery these days.
Without jQuery:
Just select the elements and use the .forEach() method to iterate over them:
const elements = document.querySelectorAll('.testimonial');
Array.from(elements).forEach((element, index) => {
// conditional logic here.. access element
});
In older browsers:
var testimonials = document.querySelectorAll('.testimonial');
Array.prototype.forEach.call(testimonials, function(element, index) {
// conditional logic here.. access element
});
Try this example
Html
<div class="testimonial" data-index="1">
Testimonial 1
</div>
<div class="testimonial" data-index="2">
Testimonial 2
</div>
<div class="testimonial" data-index="3">
Testimonial 3
</div>
<div class="testimonial" data-index="4">
Testimonial 4
</div>
<div class="testimonial" data-index="5">
Testimonial 5
</div>
When we want to access those divs which has data-index greater than 2 then we need this jquery.
$('div[class="testimonial"]').each(function(index,item){
if(parseInt($(item).data('index'))>2){
$(item).html('Testimonial '+(index+1)+' by each loop');
}
});
Working example fiddle
you can do it this way
$('.testimonial').each(function(index, obj){
//you can use this to access the current item
});
jQuery's .eq() can help you traverse through elements with an indexed approach.
var testimonialElements = $(".testimonial");
for(var i=0; i<testimonialElements.length; i++){
var element = testimonialElements.eq(i);
//do something with element
}
divs = $('.testimonial')
for(ind in divs){
div = divs[ind];
//do whatever you want
}
I may be missing part of the question, but I believe you can simply do this:
$('.testimonial').each((index, element) => {
if (/* Condition */) {
// Do Something
}
});
This uses jQuery's each method: https://learn.jquery.com/using-jquery-core/iterating/
You can do this concisely using .filter. The following example will hide all .testimonial divs containing the word "something":
$(".testimonial").filter(function() {
return $(this).text().toLowerCase().indexOf("something") !== -1;
}).hide();
With a simple for loop:
var testimonials= $('.testimonial');
for (var i = 0; i < testimonials.length; i++) {
// Using $() to re-wrap the element.
$(testimonials[i]).text('a');
}
Without jQuery updated
document.querySelectorAll('.testimonial').forEach(function (element, index) {
element.innerHTML = 'Testimonial ' + (index + 1);
});
<div class="testimonial"></div>
<div class="testimonial"></div>
You could use the jQuery $each method to loop through all the elements with class testimonial.
i => is the index of the element in collection and val gives you the object of that particular element and you can use "val" to further access the properties of your element and check your condition.
$.each($('.testimonal'), function(i, val) {
if(your condition){
//your action
}
});
In JavaScript ES6 .forEach()
over an array-like NodeList collection given by Element.querySelectorAll()
document.querySelectorAll(".testimonial").forEach((el, idx) => {
el.style.color = "red";
console.log(`${idx} Element ${el.tagName} with ID #${el.id} says: ${el.textContent}` );
});
<p class="testimonial" id="1">This is some text</p>
<div class="testimonial" id="2">Lorem ipsum</div>
$('.testimonal').each(function(i,v){
if (condition) {
doSomething();
}
});
More precise:
$.each($('.testimonal'), function(index, value) {
console.log(index + ':' + value);
});

Categories

Resources