Cross-browser getClassName JavaScript function - javascript

I'm working on a small project that needs to get all elements by className, there is obviously the HTML5 .getElementsByClassName, but I'm trying to create a little function that provides a small polyfill for it, it's just not working. any help much appreciated. Or if there is an easier way of doing this.
function getClassName(element) {
if(!document.getElementsByClassName(element)) {
var retnode = [];
var myclass = new RegExp('\\b'+element+'\\b');
var elem = this.getElementsByTagName('*');
for (var i = 0; i < elem.length; i++) {
var classes = elem[i].className;
if (myclass.test(classes)) retnode.push(elem[i]);
}
return retnode;
} else {
document.getElementsByClassName(element);
}
}
Then calling it like so:
document.getClassName('active'){
active.className += 'new';
}

Your function is wrong.
The name implies you are getting a class name, not an element.
You use the variable element when you mean className
check for support is wrong
if(!document.getElementsByClassName) {
missing return in else
return document.getElementsByClassName(element);
I would recommend sse the one from here or here to add the polyfill
Grab yourself an addClass method...something like
function hasClass(elem,className) {
return elem.className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'));
}
function addClass(elem,className) {
if (!hasClass(elem,cls)) elem.className += " "+className;
}
Than you will just do
var elems = document.getClassName('active');
for (var i=elems.length-1; i>=0; i--) {
addClass(elems[i],"active");
}

Related

How to create a function to be re-used for later within another function

I got this code:
$(document).ready(function(){
$(".nextForm").on('click',(function(){
//check criteria
if(selectedSlots.length < 1 ||$("#positionAppliedFor").get(0).value.length < 1 ||$("#maxAmountOfHours").get(0).value.length < 1){
//error messages and array
var errorForSlots= "<h5>Select at least one availability slot</h5>";
var errorForPosition = "<h5>Enter the position you wish to apply for<h5>";
var errorForHours = "<h5>Enter the amount of hours you would like to work<h5>";
var errors = [];
//add errors to array
if(selectedSlots.length < 1){errors.push(errorForSlots)};
if($("#positionAppliedFor").get(0).value.length < 1){errors.push(errorForPosition)};
if($("#maxAmountOfHours").get(0).value.length < 1){errors.push(errorForHours)};
//create message
var div = "<div id=\"sectionError\">";
if($("#sectionError").length > 0){$("#sectionError").html('')};
$(div).appendTo($(this).get(0).parentNode);
for(var i = 0; i < errors.length; i++){
$(errors[i]).appendTo($("#sectionError"));
console.log(errors[i]);}
$("</div>").appendTo($(this).get(0).parentNode);
} else {
$("#applicationDetails").slideUp();
$("#personalDetails").slideDown();
if($("#sectionError").length > 0){$("#sectionError").remove()};
}
console.log("function finished");
}));
It all works perfectly, however, I am trying to figure out how to create a function for
//create message
var div = "<div id=\"sectionError\">";
if($("#sectionError").length > 0){$("#sectionError").html('')};
$(div).appendTo($(this).get(0).parentNode);
for(var i = 0; i < errors.length; i++){
$(errors[i]).appendTo($("#sectionError"));
console.log(errors[i]);}
$("</div>").appendTo($(this).get(0).parentNode);
I am planning to re-use this for few other sections on my form and rather than copy/paste I would like to get some help on making my code tidier.
I did try:
function myFunction(){
//message code here
}
$(document).ready(function(){
$(".nextForm").on('click',(function(){
//check criteria
...
//add errors
...
//call func
myFunction();
(I also tried this.myFunction();)
...
}));
});
However, that ended up in TypeError and I don't know where to begin...
I am also concerned about the "this" in my message code so I am also not sure how to address that in my new function...
Admitedly I am a newbie at this and I do not exactly understand all the ins and outs, hopefully you will be able to help.
Maybe there is a better way of doing this?
Let me know your thought either way!
Thanks.
I have created a small reusable framework same as how jQuery is doing behind the scene to expose reusable functions. I didn't tested the append function properly,I just explaining how you can create your own reusable plugin to reuse across the project.
You can change the parameters and method name that you want to expose based on your functionality.
Also I would suggest you to move this code to a javascript file as a plugin and drag after the jquery script.
(function (global, $) {
//you can pass the jQuery object in to this IIFE
var DisplayError = function (elementId) {
return new DisplayError.init(elementId);
}
DisplayError.prototype = {
appendError: function (errors) {
var div = "<div id=\"" + this.elementId + " \">";
if ($(this.elementId).length > 0) {
$(this.elementId).html('')
};
$(div).appendTo($(this.elementId).get(0).parentNode);
for (var i = 0; i < errors.length; i++) {
$(errors[i]).appendTo($(this.elementId));
}
$("</div>").appendTo($(this.elementId).get(0).parentNode);
}
};
DisplayError.init = function (elementId) {
var self = this;
self.elementId = elementId;
}
DisplayError.init.prototype = DisplayError.prototype;
global.DisplayError = global.DisplayError = DisplayError;
}(window, jQuery));
You can write the code for clear the html directly in init function to ensure the element is clearing while initialize the instance itself.
You can invoke the method like below ,
var displayError=DisplayError("#sectionError")
displayError.appendError(["errorId"])
or
DisplayError("#sectionError").appendError(["errorId"])
Hope this helps
New Function
function generateMessage(arg1) {
//create message for each section
console.log("generating message");
var div = "<div id=\"sectionError\">";
if ($("#sectionError").length > 0) {
$("#sectionError").html('')
}
;$(div).appendTo($(arg1).parent());
for (var i = 0; i < errors.length; i++) {
$(errors[i]).appendTo($("#sectionError"));
console.log(errors[i]);
}
$("</div>").appendTo($(arg1).parent());
}
Changed old function
$(document).ready(function() {
$("#adbutnext").on('click', (function() {
//check criteria
if (selectedSlots.length < 1 || $("#positionAppliedFor").get(0).value.length < 1 || $("#maxAmountOfHours").get(0).value.length < 1) {
//error messages and array
var errorForSlots = "<h5>Select at least one availability slot</h5>";
var errorForPosition = "<h5>Enter the position you wish to apply for<h5>";
var errorForHours = "<h5>Enter the amount of hours you would like to work<h5>";
errors = [];
//add errors to array
if (selectedSlots.length < 1) {
errors.push(errorForSlots)
}
;if ($("#positionAppliedFor").get(0).value.length < 1) {
errors.push(errorForPosition)
}
;if ($("#maxAmountOfHours").get(0).value.length < 1) {
errors.push(errorForHours)
}
;
generateMessage(this);
} else {
$("#applicationDetails").slideUp();
$("#personalDetails").slideDown();
if ($("#sectionError").length > 0) {
$("#sectionError").remove()
}
;
}
console.log("function finished");
}
));
});

javascript dynamically adding and removing classes [duplicate]

This question already has answers here:
How can I change an element's class with JavaScript?
(33 answers)
Closed 5 years ago.
I am working on a simple example, if a user clicks on element then all the elements above it should have a class and all elements below it should not have any class applied to them.
Here is my code:
<script>
function test(object) {
var pid = object.id;
var id = parseInt(pid.split("")[1]);
console.log(id);
for (var i = 1; i <= id; i++) {
var element = document.getElementById("p"+i);
console.log(element);
element.className = "active";
}
console.log(id+1);
for(var i = id+1; i <= 4; i++) {
var element = document.getElementById("p"+i);
element.className.replace(new RegExp('(?:^|\\s)'+ 'active' + '(?:\\s|$)'), ' ');
console.log(element);
}
}
</script>
<div id="divid">
<p id="p1" onclick="test(this)">one</p>
<p id="p2" onclick="test(this)">two</p>
<p id="p3" onclick="test(this)">three</p>
<p id="p4" onclick="test(this)">four</p>
</div>
So here if I click on three then the elements for one, two, three should have the class active and element four should not have any class. This is working fine.
Now if I click on one, I am expecting that two, three, four should have any css class but it is not working like that.
Can you please help me where is the issue. I want to use plain Javascript.
It might be wise to consider an alternative to using the onclick attribute due to separation of concerns. The following allows you to alter the HTML without having to consider JavaScript while you work.
https://jsfiddle.net/gseh0wxc/2/
var getList = (selector) => [].slice.call(document.querySelectorAll(selector));
var paragraphs = getList("#divid p[id ^= 'p']");
paragraphs.forEach((paragraph, index) => {
paragraph.addEventListener('click', (e) => {
for (let i = 0; i < index; i++) {
paragraphs[i].classList.remove('active');
}
for (let i = index; i < paragraphs.length; i++) {
paragraphs[i].classList.add('active');
}
});
})
Please try this code
function test(object) {
var pid = object.id;
var id = parseInt(pid.split("")[1]);
console.log(id);
for (var i = 1; i <= id; i++) {
var element = document.getElementById("p"+i);
element.classList.add("active");
}
console.log(id+1);
for(var i = id+1; i <= 4; i++) {
var element = document.getElementById("p"+i);
element.classList.remove("active");
}
}
Hope this helps.
try this simple approach instead, don't need to extract id number and all, and with a single simple loop.
function test(option) {
//this will select all p tags id starts with "p" inside div having id "divid" and return a array
var targetPTags = document.querySelectorAll("div#divid p[id^=p]")
var idx, flag=false;
//we are iterating over that array and taking each dom element in el
for(idx=0;idx<targetPTags.length;idx++) {
var el = targetPTags[idx];
if(flag) {
//do operation you want for after elements in el
} else if(option===el) {
flag=true; // we are making flag true when its the element that clicked and doing no operation
//do the operation you want for the element, may be the same as below operation in else
} else {
//do operation you want for before element in el
}
}
}
Kind of similar to "Chatterjee"'s solution, but here you go:
function test(object)
{
var parentElem = null;
var childElems = null;
var currElemSet = false;
var i=-1;
try
{
parentElem = object.parentElement;
if(parentElem!=null)
{
childElems=parentElem.getElementsByTagName(object.nodeName); // could refine to accommodate sibling nodes only
if(childElems!=null)
{
for(i=0;i<childElems.length; i++)
{
if(currElemSet) childElems[i].className = "";
else childElems[i].className = "active";
if(childElems[i]==object) currElemSet = true;
}
}
}
}
catch(e)
{
alert("Error: " + e.Message);
}
finally
{
}
}

What is the plain Javascript equivalent of .each and $(this) when used together like in this example?

What is the plain Javascript equivalent of .each and $(this).find when used together in this example?
$(document).ready(function(){
$('.rows').each(function(){
var textfield = $(this).find(".textfield");
var colorbox = $(this).find(".box");
function colorchange() {
if (textfield.val() <100 || textfield.val() == null) {
colorbox.css("background-color","red");
colorbox.html("Too Low");
}
else if (textfield.val() >300) {
colorbox.css("background-color","red");
colorbox.html("Too High");
}
else {
colorbox.css("background-color","green");
colorbox.html("Just Right");
}
}
textfield.keyup(colorchange);
}
)});
Here's a fiddle with basically what I'm trying to accomplish, I know I need to use a loop I'm just not sure exactly how to set it up. I don't want to use jquery just for this simple functionality if I don't have to
http://jsfiddle.net/8u5dj/
I deleted the code I already tried because it changed every instance of the colorbox so I'm not sure what I did wrong.
This is how to do what you want in plain javascript:
http://jsfiddle.net/johnboker/6A5WS/4/
var rows = document.getElementsByClassName('rows');
for(var i = 0; i < rows.length; i++)
{
var textfield = rows[i].getElementsByClassName('textfield')[0];
var colorbox = rows[i].getElementsByClassName('box')[0];
var colorchange = function(tf, cb)
{
return function()
{
if (tf.value < 100 || tf.value == null)
{
cb.style.backgroundColor = 'red';
cb.innerText = "Too Low";
}
else if (tf.value > 300)
{
cb.style.backgroundColor = 'red';
cb.innerText = "Too High";
}
else
{
cb.style.backgroundColor = 'green';
cb.innerText = "Just Right";
}
};
}(textfield, colorbox);
textfield.onkeyup = colorchange;
}
var rows = document.querySelectorAll('.rows');
for (var i=0; i<rows.length; i++) {
var row = rows[i];
var textfield = row.querySelector('.textfield');
var colorbox = row.querySelector('.box');
// ...
}
Note that you must use a for loop to iterate the rows because querySelectorAll() does not return an array, despite appearances. In particular, that means that .forEach() isn't valid on the returned list.

Javascript to check if a CSS class is on the page without Jquery

I'm looking for a cross-browser compatible and lightweight way to check to see if any instance of a CSS class is on a page or not.
For example, if I want to check for 'myclass', and or was anywhere on the page, then it would return true, else false.
I've tried a function like this, but it does not work:
function getElementsByClassName( clsName )
{
var arr = new Array();
var elems = document.getElementsByTagName("*");
for ( var cls, i = 0; ( elem = elems[i] ); i++ )
{
if ( elem.className == clsName )
{
arr[arr.length] = elem;
}
}
return arr;
}
if ( getElementsByClassName('myclass').length >= 1) {
// yes, it's on the page
}
Thanks.
You could try something like this: http://jsfiddle.net/sK2zd/
I just changed your code a little, but it's doing what you expect.
function getElementsByClassName(clsName) {
var arr = [];
var elems = document.getElementsByTagName("*");
for (var i = 0; i < elems.length; i++) {
if (elems[i].className == clsName) {
arr.push(elems[i]);
}
}
return arr;
}
window.onload = function () {
var all_classes = getElementsByClassName('testing');
if (all_classes.length > 0) {
// yes, it's on the page
alert("Found " + all_classes.length + " element(s) with class 'testing'");
} else {
alert("Found none");
}
};
UPDATE:
Looking back at this answer I realized I never suggested elems[i].className == clsName probably isn't correct, as the className property may be several classes separated by a space character. So there would need to be a better way to see if it has a class.
You can use querySelector method much like jQuery selectors
In HTML5 you can use document.querySelectorAll() with CSS3 selectors.
if (document.querySelectorAll('.the_class_name').length > 0) {
doIt();
}

Find all elements whose id begins with a common string

I have a XSL that created multiple elements with the id of "createdOn" plus a $unique-id
Example : createdOnid0xfff5db30
I want to find and store these in a variable using JavaScript. I've tried
var dates = document.getElementsById(/createdOn/);
but that doesn't appear to work.
Using jQuery you can use the attr starts with selector:
var dates = $('[id^="createdOnid"]');
Using modern browsers, you can use the CSS3 attribute value begins with selector along with querySelectorAll:
var dates = document.querySelectorAll('[id^="createdOnID"]');
But for a fallback for old browsers (and without jQuery) you'll need:
var dateRE = /^createdOnid/;
var dates=[],els=document.getElementsByTagName('*');
for (var i=els.length;i--;) if (dateRE.test(els[i].id)) dates.push(els[i]);
You should have just used simple CSS selector together with JavaScript's .querySelectorAll() method.
In your case :
var dates = document.querySelectorAll('[id^="createdOnId"]');
Because you didn't tag jQuery, and you probably don't need it, my suggestion would be to add a class to these elements when you create them. Then use the getElementsByClassName() function that's built into most browsers. For IE you would need to add something like this:
if (typeof document.getElementsByClassName!='function') {
document.getElementsByClassName = function() {
var elms = document.getElementsByTagName('*');
var ei = new Array();
for (i=0;i<elms.length;i++) {
if (elms[i].getAttribute('class')) {
ecl = elms[i].getAttribute('class').split(' ');
for (j=0;j<ecl.length;j++) {
if (ecl[j].toLowerCase() == arguments[0].toLowerCase()) {
ei.push(elms[i]);
}
}
} else if (elms[i].className) {
ecl = elms[i].className.split(' ');
for (j=0;j<ecl.length;j++) {
if (ecl[j].toLowerCase() == arguments[0].toLowerCase()) {
ei.push(elms[i]);
}
}
}
}
return ei;
}
}
function idsLike(str){
var nodes= document.body.getElementsByTagName('*'),
L= nodes.length, A= [], temp;
while(L){
temp= nodes[--L].id || '';
if(temp.indexOf(str)== 0) A.push(temp);
}
return A;
}
idsLike('createdOn')
Try the following:
var values = new Array(valueKey_1);
var keys = new Array("nameKey_1");
var form = document.forms[0];
for (var i = 0; i < form.length; i++) {
name = form.elements[i].name;
var startName = name.toLowerCase().substring(0, 18);
if (startName == 'startStringExample') {
values.push(name.value);
keys.push(name);
}
}

Categories

Resources