jQuery get items with attribute like - javascript

Lets say I've got
<div color-opacity="0.8" color-whatever="something" color-whateverbadinga="something">content</div>
What I want to do is to select every item that has attribute that begins with color- (attribute name, not attribute value)
so <div color-dsjdjkdskjsd="something">content</div> will match too.
Is it possible without iterating throught every item and checking every attribute?

jQuery selectors doesn't work with filtering the attribute names, you should read the attribute's name yourself, here is how you can filter the elements using .filter() method and attributes property. However, I don't recommend it as it is very inefficient and generally a bad practice. Adding a class name to the elements that have such attributes and using class selector makes more sense:
$('div').filter(function() {
var a = this.attributes;
for (var i = 0; i < a.length; i++) {
if (a[i].nodeName.indexOf('color') === 0)
return true;
}
return false;
});

I do not know of a way to get what you want directly from JQuery.
The easiest solution to the root problem is to add a class ("hasColor") on all elements when you add the color attribute. This is of course assuming that you are generating the elements.

I dont recommend creating your own attributes. However, You could do this with data attribute:
<div data-coloropacity="0.8" data-colorwhatever="something"
data-colorwhateverbadinga="something">content</div>
Then create your own jquery data2 selector:
jQuery.expr.pseudos.data2= $.expr.createPseudo(function(arg) {
var regexp = new RegExp(arg);
return function(elem) {
for(var i = 0; i < elem.attributes.length; i++) {
var attr = elem.attributes[i];
if(regexp.test(attr.name)) {
return true;
}
}
return false;
};
});
Then you can use it like this:
console.log($(":data2('color')").html());
DEMO

Related

Return class that matches element from list

I have a nodelist of elements in js that were collected by querying many classes and then a "for" statement that loops through the list. What I need is a quicky one-line way to return what class each element was selected by within the loop so I can perform an action based on that. Here is my code blip:
var nodeList = document.querySelectorAll(".class1, .class2, .etc...");
for (var i = 0; i < nodeList.length; i++) {
var classOfCurrentDiv = [...]
//perform action using classOfCurrentDiv
}
I know I can do something like
if (nodeList[i].classList.contains(class1)) {
//perform code
}
and repeat that for each class, or do a comparison of the element's classlist and the list of classes I'm searching for, but all I need to do is insert the name of the class into a string, so I'd prefer a single line solution to obtain the class that returned the element in the query. The class that returned the element may not be that element's only class which is why I can't just pull the element's classlist.
This is probably very simple and I'm just blanking on how to do it, but let me know. The list of queried classes will be hardcoded and each element's classlist will only contain one of the queried classes if that helps.
Thanks!
You can use Element.matches to do this with a 1 liner.
Element.matches(selector) lets you specify a css selector to an element and it will return if the element is matched by the selector. Since your selector works out to be a comma separated list of classes, you can find which class matched the particular element by splitting the selector on commas to an array, loop thru that array as each class via filter and filter out elements that don't match. Full example below:
function classOfCurrentDiv(div, selector) {
return selector.split(", ").filter(_class => div.matches(_class))[0];
}
const selector = ".class1, .class2, .class3";
const nodeList = document.querySelectorAll(selector);
for (let i = 0; i < nodeList.length; i++) {
console.log("selector of element " + i + ":", classOfCurrentDiv(nodeList[i], selector));
}
<div class="class1 foo"></div>
<div class="class3 bar"></div>
<div class="class2 baz"></div>
Something like that ?
const classList = [".ps-fixed", ".class1", ".class2"]
const nodeList = document.querySelectorAll(classList)
nodeList.forEach((node) => {
classList.forEach((ClassMatch) => {
if (node.classList.contains(ClassMatch.slice(1))) { //slice 1 to remove the "." before the class names in the array
console.log(node)
}
})
});

Get all the elements that start with a particular innerHTML using query selector?

I am currently having problem with selecting and matching the innerHTML using querySelectorAll.
Here is what i did:
document.querySelectorAll('*[class^="js-display-url"]').contains('product')
What the html is:
<span class="js-display-url">product/poss/newslanges</span>
But i want to match the class js-display-url starting with product but can't do that. please help.
With DOM selectors you cannot select elements based on the inner HTML, but you can loop through all the elements with that class and single out the ones that match your condition:
var allElements = document.querySelectorAll('*[class^="js-display-url"]');
var myElements = [];
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].innerHTML.startsWith('product')) {
myElements.push(allElements[i]);
}
}
There isn't a DOM selector which will filter based on text nodes, but you can filter using some array methods, since a NodeList is array-like.
In particular, Array.prototype.filter can get the elements that meet your criteria.
var filter = Array.prototype.filter;
var allElements = document.querySelectorAll('.js-display-url');
var productElements = filter.call(allElements, function(element) {
return element.innerText.startsWith('product');
});
console.log(productElements);
<span class="js-display-url">product/poss/newslanges</span>

How to get all HTML attributes which start with something (the attribute names, *not* their values!)

I would like to get all the elements/nodes in an HTML page which contain attributes that start with something (again, the attribute names start with something, not their values!). For example, TinyMCE has a tendency of adding custom attributes to the elements it saves, like "mce_style", "mce_href", "mce_bogus", etc. I would like to have something like the CSS3 selector for attribute values, [attr^="mce_"], but not for the values, the attribute names.
Of course, I can iterate through all DOM nodes and their attributes and check them one by one, but I was wondering whether there is a more efficient way.
Please don't give me TinyMCE-specific answers, I'm pretty sure there's a flag which would prevent TinyMCE for saving these attributes, but the question is generic.
here's a simple demo to find all elements that contain an attribute starting with mce_. might need some refinements.
function getMCE() {
var el, attr, i, j, arr = [],
reg = new RegExp('^mce_', 'i'), //case insensitive mce_ pattern
els = document.body.getElementsByTagName('*'); //get all tags in body
for (i = 0; i < els.length; i++) { //loop through all tags
el = els[i] //our current element
attr = el.attributes; //its attributes
dance: for (j = 0; j < attr.length; j++) { //loop through all attributes
if (reg.test(attr[j].name)) { //if an attribute starts with mce_
arr.push(el); //push to collection
break dance; //break this loop
}
}
}
return arr;
}
console.log(getMCE())​
Try this:
FUNCTIONS
//custom selector expression
$.extend($.expr[':'],{
attr:function(o,i,m){
var attrs=$.getAttrAll(o),re=m[3],found=false;
$.each(attrs,function(k,v){
if(new RegExp(re).test(v)) { return found=true;}
});
return found;
}
});
// get all atrributes of an element
$.getAttrAll=function(el){
var rect = [];
for (var i=0, attrs=el.attributes, len=attrs.length; i<len; i++){
rect.push(attrs.item(i).nodeName);
}
return rect;
};
`
USAGE
// calling custom selector expression :attr(regexp)
$(function(){
$('body').find(':attr("^mce_")').css({background:'yellow'});
});
HTML
<body>
<p mce_style="height:50px" id="x" data-hello="hello">selected</p>
<div not_mce_bogus="abc">not_mce_bogus</div>
<div mce_href="http://rahenrangan.com">selected</div>
<p>othrs</p>
</body>
One option, if you don't mind temporarily altering your DOM, is to extract your HTML into a string and search for the attributes via RegExp. When you find the attributes, you could append a "needle" in the DOM so that you can use jQuery to select the elements.
Here is a working concept (run with console open):
http://jsfiddle.net/skylar/N43Bm/
Code:
$.fn.extend({
findAttributes: function(attribute) {
var attributeFinder = new RegExp(attribute + '(.+)="', "gi");
var elementHTML = this.html().replace(attributeFinder, "data-needle='pin' "+attribute+"$1=\"");
this.html(elementHTML);
return this.find("[data-needle=pin]").removeAttr('data-needle');
}
});
console.log($("body").findAttributes('mce_'));
Note: my regexp is not great. You'll have to take better care than I have in this example.
Try this: (I tried putting * instead of a tag but it colored all the elements including those who do not have mce_style attribute as well)
a[mce_style] { color : red; }​
Demo : http://jsfiddle.net/Tcdmb/
More info : https://developer.mozilla.org/en/CSS/Attribute_selectors

assign id for table header in javascript

Please let me know how to assign id for table header (th) with class="tableHeader" and table id="requestview_table" using javascript(after html table is constructed). Currently, the table headers don't have any id.
Please let me know how to insert id (any number) for with class tableHeader.
$("#requestview_table").find("th.tableHeader").each(function(index) { $(this).attr('id','header' + index); });
m0sa's answer is cleaner (yeay! jQuery) but if you want a JavaScript only solution then this is my stab at it:
Firstly you need a method to get items based on class name (which is something I modified from here: http://www.tek-tips.com/viewthread.cfm?qid=1143850&page=1).
function getElementsByClassName(strClassName, obj) {
var arrClassElements = [];
if (obj) {
if (obj['className'] && obj.className.indexOf(strClassName) != -1) {
arrClassElements.push(obj);
}
for (var i = 0; i < obj.childNodes.length; i++) {
arrClassElements = arrClassElements.concat(getElementsByClassName(strClassName, obj.childNodes[i]));
}
}
return arrClassElements;
}
Then you use this to iterate through the elements it picked up, using setAttribute to add an ID to the element.
var headers = getElementsByClassName('tableHeader', document.getElementById('requestview_table'));
for(var i=0;i<headers.length;i++){
headers[i].setAttribute('id', 'header' + i)
alert(headers[i].id);
}
This is it working here: http://jsfiddle.net/jonathon/W6JyE/
Again, I recommend you use jQuery if you can. It's much better and cleaner for doing the type of operations you're looking to do. This is just one of many alternative solutions.

Is there a way to loop through all fields in a fieldset?

I would like to change the class for all the fields in a specific fieldset.
Is there a way to loop through the fields in a fieldset?
You can use getElementsByTagName.
var fieldset= document.getElementById('something');
var fieldtags= ['input', 'textarea', 'select', 'button'];
for (var tagi= fieldtags.length; tagi-->0) {
var fields= fieldset.getElementsByTagName(fieldtags[tagi]);
for (var fieldi= fields.length; fieldi-->0;) {
fields[fieldi].className= 'hello';
}
}
(If you only care about input fields, you could lose the outer tag loop.)
If you needed them in document order (rather than grouped by tag) you'd have to walk over the elements manually, which will be a pain and a bit slow. You could use fieldset.querySelectorAll('input, textarea, select, button'), but not all browsers support that yet. (In particular, IE6-7 predate it.)
Using jQuery (yay!):
$('#fieldset-id :input').each(function(index,element) {
//element is the specific field:
$(element).doSomething();
});
Note the solution below is for NON-JQUERY Implementations.
Implement a getElementsByClassName Method like this:
After you implement the code below you can then use document.getElementsByClassName("elementsInFieldSetClass") it will return an array of the elements with that class.
function initializeGetElementsByClassName ()
{
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
}
}
}
window.onload = function () {
initializeGetElementsByClassName();
};
Another jQuery solution here.
If you are simply adding a class(es) to the elements, it's this simple:
$('fieldset :input').addClass('newClass');
.addClass() (like many other jQuery functions) will work on all of the elements that match the selector.
Example: http://jsfiddle.net/HANSG/8/
Permanently? Find & replace in your editor of choice.
When the user clicks something? jQuery way:
$('fieldset <selector>').each(function() {
$(this).removeClass('old').addClass('new');
});

Categories