Find all elements whose id begins with a common string - javascript

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);
}
}

Related

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.

Cross-browser getClassName JavaScript function

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");
}

jQuery convert data-* attributes to lower camel case properties

I have the following jQuery script to intialise a jQuery plugin called poshytips. I want configure the plugin using Html5 data attributes. I am repeating myself big time, can anyone come up with a better way to do this?
$('.poshytip-trigger').each(function (index) {
var $this = $(this);
var data = $this.data();
var options = {};
if (data['class-name']) {
options.className = data['class-name'];
}
if (data['align-x']) {
options.alignX = data['align-x'];
}
if (data['align-y']) {
options.alignY = data['align-y'];
}
if (data['offset-y']) {
options.offsetY = data['offset-y'];
}
if (data['offset-x']) {
options.offsetX = data['offset-x'];
}
$this.poshytip(options);
});
I would use a for..in loop to read the data-* tags.. Also you don't need to camelcase as jQuery converts it to camelCase internally... Source code reference.
$('.poshytip-trigger').each(function (index) {
var $this = $(this);
var data = $this.data();
var options = {};
for (var keys in data) {
options[keys] = data[keys];
}
// For older versions of jQuery you can use $.camelCase function
for (var keys in data) {
options[$.camelCase(keys)] = data[keys];
}
});
DEMO
for jQuery 1.4.4,
$('.poshytip-trigger').each(function(index) {
var $this = $(this);
var data = $this.data();
var options = {};
for (var keys in data) {
options[camelCase(keys)] = data[keys];
}
});
//copied from http://james.padolsey.com/jquery/#v=git&fn=jQuery.camelCase
function camelCase(str) {
return str.replace(/^-ms-/, "ms-").replace(/-([a-z]|[0-9])/ig, function(all, letter) {
return (letter + "").toUpperCase();
});
}
DEMO for 1.4.4
Something like this - It does convert offset-x to offsetX:
http://jsfiddle.net/8C4rZ/1/
HTML:
<p data-test="sdsd" data-test2="4434"></p>​
JavaScript:
$(document).ready(function() {
var options = {};
for (var key in $("p").data()) {
options[key] = $("p").data(key);
}
console.log(options);
});​
But I think Daniel's approach is better, since he explicitly controls which attributes gets set. This will take all data- attributes.
var names = ["className", "alignY", ...];
$(names).each(function(ind, name){
var dataName = name.replace(/[A-Z]/, function(letter){
return letter.toLowerCase();
});
if(data[dataName]){
options[name] = data[dataName];
}
});
Does this work? Unlike the other answers, this piece of code both convert only explicitly set attributes and keeps the options-object attribute name camelCase.
Try using a for in loop.
var array = ['class-name', 'align-x', 'align-y', 'offset-y', 'offset-x'];
for (x in array) {
if(data[array[x]]) {
options[array[x]] = data[array[x]];
}
}
Update: In response to the OP's clarification, he could write something like this:
var Pair = function(hyphenated, camcelCased) {
this.hyphenated = hyphenated;
this.camelCased = camelCased;
}
var array = [
new Pair('class-name', 'ClassName'),
new Pair('align-x', 'alignX'),
new Pair('align-y', 'alignY'),
new Pair('offset-x', 'offsetX'),
new Pair('offset-y', 'offsetY')];
var i, optionNameHyphenated, optionNameCamelCased;
for(i = 0; i < array.length; i++) {
optionNameHyphenated = array[i]['hyphenated'];
optionNameCamelCased = array[i]['camelCased'];
if (data[optionNameHyphenated]);
options[optionNameCamelCased] = data[optionNameHyphenated];
}

Remove all attributes not working properly in ie8 because of extra (system default) attributes

I have a function which removes all attributes in all tags except a few like colspan,color or align
When I send HTML code to this function it work well in Firefox and IE9, but in IE8 and IE7 it's finding lots of attributes which the elements don't have. For example, when I send:
jRemoveAtt("<button color=\"red\" id=\"start\">Hello World</button>")
It should find the color attribute and skip it, then find the id attribute and remove it.
But in IE8 it finds more attributes like onwrite, onunwrite, onpage, onbeforeactivate, and more.
This function is for clean up HTML and sending it to a printable newwindow. It's cleaning up really fast but in IE8 it takes 8-9 seconds and meanwhile makes the browser unresponsive.
I don't know how I can make it to ignore unwritten attributes in HTML strings. Any ideas?
Here is my function:
function jRemoveAtt(x){
if(!x)return '';
var str=$('<div>'+x+'</div>');
$('*',str).each(function(){
var c=$(this);
var attributes = $.map(this.attributes, function(item) {
var a=item.name.toLowerCase();
/*alert(a); */ //this alert shows the extra tags when activated
if (a!='align'&&a!='colspan'&&a!='span'&&a!='color'&&a!='size') {
c.removeAttr(item);
}
});
});
return $(str).html();
};
You can do this in pure JS.
HTML:
<div color="red" id="start" align="center">Hello World</div>
JS:
var test = document.getElementById("start");
purgeAttributes(test);
postAttributes(test);
function purgeAttributes(el)
{
//keep these attributes
var whitelist = ["colspan", "color", "align"];
for(var i=0;i<el.attributes.length;i++)
{
var attr = el.attributes.item(i);
var whiteListCheck = false;
//loop through whitelist
for(var j=0;j<whitelist.length;j++)
{
if(attr.nodeName === whitelist[j])
{
whiteListCheck = true;
break;
}
}
if(!whiteListCheck)
{
//second parameter means a case-sensitive search
el.removeAttribute(attr.nodeName, 1);
}
}
}
function postAttributes(el)
{
var txtHolder = document.createElement("p");
var titleTxt = document.createTextNode("attributes: ");
document.body.appendChild(txtHolder);
txtHolder.appendChild(titleTxt);
for(var i=0;i<el.attributes.length;i++)
{
var attr = el.attributes.item(i);
if(attr.nodeValue)
{
var txt = document.createTextNode(attr.nodeName + ": " + attr.nodeValue + " ");
txtHolder.appendChild(txt);
}
}
}
http://jsfiddle.net/mkmcdonald/ZsezN/3/
Tested as working in Firefox 4, IE 8, IE 7 (Quirks Mode), IE 6, Chrome 4, Safari 4, and Opera 11. One small quirk to note is IE in Quirks Mode will display the contentEditable attribute.
How about this: You're removing all of the element's attributes, correct? How about instead of removing all of it's attributes, you do this:
HTML:
<div id="myElement" fakeAttr="1" fakeAttr2="2">This is a test.</div>
jQuery:
var before = $("#myElement");
var after = $("<"+before[0].tagName+"/>", { html: before.html() });
alert( "Before: "+before[0].outerHTML );
alert( "After: "+after[0].outerHTML );
Same thing, but done in another way...
EDIT:
Added in feature where array of "good" attributes could be set...
var attrObj = function(el, good){
var obj = {}, attribs = el[0].attributes;
var tLC = function(s){ return s.toLowerCase() };
for(var i=0; i<attribs.length; i++){
var isGd = false;
for(var i2=0; i2<good.length; i2++){
if(tLC(attribs[i].name) == tLC(good[i2])){ isGd = true; break; }
}
if(isGd){ obj[attribs[i].name] = attribs[i].value; }
}
return obj;
};
var before = $("#myElement");
var newAttr = attrObj(before, ["id"]);
newAttr.html = before.html();
var after = $("<"+before[0].tagName+"/>", newAttr);
alert( "Before: "+before[0].outerHTML );
alert( "After: "+after[0].outerHTML );
Expanding on my comment, something like this should do the trick for purging:
function purgeAttributes(el) {
var curIndex = 0;
var whitelist = ["colspan", "color", "align"];
var initialLength = el.attributes.length;
var whiteListCheck = false;
for (var i = 0; i < initialLength; i++) {
var attr = el.attributes.item(curIndex);
for(var j = 0; j < whitelist.length; j++) {
if(attr.nodeName === whitelist[j]) {
whiteListCheck = true;
// We know that there is an item at curIndex we want to keep, proceed to the next
curIndex++;
break;
}
}
if(!whiteListCheck) {
el.removeAttribute(attr.nodeName);
}
};
}

getElementByName & Regex

How do I loop through all elements using regular expression in getElementByName?
If you mean like:
var elementArray = document.getElementsByName("/regexhere/");
then no that would not be possible.
To do what you want to do you would have to get all the elements, then go through each one and check the name of it.
Heres a function that will go through all the elements and add all the elements with a certain name to an array:
function findElements(name)
{
var elArray = [];
var tmp = document.getElementsByTagName("*");
var regex = new RegExp("(^|\\s)" + name + "(\\s|$)");
for ( var i = 0; i < tmp.length; i++ ) {
if ( regex.test(tmp[i].name) ) {
elArray.push(tmp[i]);
}
}
return elArray;
}
And use as:
var elName = "customcontrol";
var elArray = customcontrol(elName);
Or it might be easier by className
function findElements(className)
{
var elArray = [];
var tmp = document.getElementsByTagName("*");
var regex = new RegExp("(^|\\s)" + className+ "(\\s|$)");
for ( var i = 0; i < tmp.length; i++ ) {
if ( regex.test(tmp[i].className) ) {
elArray.push(tmp[i]);
}
}
return elArray;
}
And use as:
var elClassName = "classname";
var elArray;
if (!document.getElementsByClassName)
{
elArray= findElements(elClassName );
}
else
{
elArray = document.getElementsByClassName(elClassName);
}
This would do what you want, without the need for getElementByName.
Although I think you meant getElementsByName
If you wanted to look for an element with only the name "customcontrol" you would use:
var regex = new RegExp("(^|\\s)" + name + "(\\s|$)");
If you wanted to look for an element with that STARTED with the name "customcontrol" you would use:
var regex = new RegExp("(^|\\s)" + name);
EDIT:
If your using jQuery, which would be easier, then this would do:
var elArray = $("*[name^='customcontrol']");
//Use JavaScript to loop through
for (var a = 0; a< elArray.length;a++)
{
//Loop through each element
alert(elArray[a]);
}
//Or
$("*[name^='customcontrol']").css("color","red"); //Or whatever you want to do to the elements
Use a custom selector in jQuery. You probably want an example with parameters.

Categories

Resources