Call a function on regex match - javascript

Is there a way to call a function when an id matches a regex?
I have an app where I have about 20 or so divs calling the same function by onclick and I'm trying to get rid of the onclicks and just find those divs by id. The divs id's start the same way for instance: sameId_xxx
This is what I have working but I was wondering if I could put the condition in the function call so it's not being called for every div on the page.
$("div").click(function () {
var id = this.id;
if (id.match(/sameId_/)) {
}
}

$('div[id^="sameId_"]').click(...)
Demo: http://jsfiddle.net/kpcxu/
For more info, see Attribute Starts With selector.

Try the jQuery 'attribute contains selector':
$('div[id*="sameId_"]').click(function() {
// Do stuff
});

I think better filter all div with using necessary condition and next add handler.
For example:
$('div')
.filter(function() { return $(this).attr('id') % 2 })
.click(function(){alert($(this).attr('id'))});​
Live demo on JSFiddle
Or you can use var id = $(this).attr('id') in your code.

I think the other answers (with filtering on the id up front) are better, but for posterity, here is what you actually asked for:
$("div").click(function () {
var id = this.id;
if (id.match(/(sameId_)(.)+/)) {
console.log("matched");
}
}​);​
where "sameId_" is a case sensitive representation of what you want to match.

Related

Referencing parameters in the CSS section of a jQuery function

This function toggles all checkboxes in a given column of an HTML table when selecting or deselecting a checkbox.
function GlobalCheckboxSwitch0(checkboxID, tableID)
{
if ($(checkboxID).is(':checked'))
{
$('#table0 input[type=checkbox]').each(function ()
{
$(this).prop("checked", true);
});
}
else
{
$('#table0 input[type=checkbox]').each(function ()
{
$(this).prop("checked", false);
});
}
}
Invoking it like this works only for table0:
<input type="checkbox" id="selectall0" onClick="GlobalCheckboxSwitch0('#selectall0', '#table0')">
The problem is that table0 is hard coded in the function.
With the help of the second parameter tableID I would like it to work for any table ID.
selectall0 is the ID of the checkbox.
Trying to refer the tableID parameter like this:
$('$(tableID) input[type=checkbox]')
yields a syntax error.
What should I change in the way I refer to tableID?
Thank you.
Use the tableID selector the same way you do for checkboxID along with find().
You can also skip the if and the each and do the following:
function GlobalCheckboxSwitch0(checkboxID, tableID) {
var allChecked = $(checkboxID).is(':checked');
$(tableID).find('input[type=checkbox]').prop('checked', allChecked );
}
jQuery will do the each internally
It's a jQuery selector syntax error, to be precise - it's not actually a JavaScript syntax error.
You need to learn concatenation, which means joining strings and variables/expressions.
As it stands...
$('$(tableID) input[type=checkbox]')
...will be executed literally. In other words, you're telling jQuery to go find an element whose tag name is tableID.
Instead you need to concatenate between the formulaic and dynamic parts of the jQuery selector. Concatenation in JavaScript is done via +.
$('#'+tableID+' input[type=checkbox]') //<-- note #

JavaScript - Find ID that matches data attribute value

I have a variable that finds the data attribute of an element that is clicked on in a callback function:
var dropdown = document.getElementsByClassName('js-dropdown');
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener("click", callBack (dropdown[i]));
}
function callBack (i) {
return function () {
var thisDropdown = i.getAttribute('data-dropdown');
//rest of the code here
}
}
I am basically trying to do this
$('#' + thisDropdown ).toggleClass('is-active');
...but in vanilla JS.
This works fine using jQuery however I would like a vanilla version.
So when a user clicks on an element that activates a drop down, I want it to dynamically find its relevant ID matching value within the document so it can toggle a show/hide class.
I've searched through a lot of SO questions and everyone replies with a jQuery answer which is not what I am looking for.
I've been trying to do something along the lines of
var idValue = document.getElementById(thisDropdown);
Then
var findId= idValue + thisDropdown;
findId.toggleClass('is-active');
Obviously that does not work the same way the jQuery statement works... any ideas?
Ignore the toggleClass method! Some of you may find this contradictory as I want vanilla JS.
To replace $('#' + thisDropdown ).toggleClass('is-active'); with plain js, use Element.classList. Like this:
const someElement = document.querySelector('#' + thisDropdown);
someElement.classList.toggle("is-active");
I like #kamyl's answer, but you might need backward compatibility. For that, see if you can find a polyfill.
If you have to write it yourself, use string.split(" ") to get your list of active attributes and iterate to find if it exists; add if not, remove if so...then array.join(" ") and replace the class attribute with it.

How to use jQuery wildcards with removeClass

I am trying to modify a div that has a given class with the following jquery code:
$("[class^=delay-][class$='+number+']").each(function(index) {
var delayTime = $(this).attr('class').match(/delay-(\d+)/)[1];
$(this).removeClass("[class^=delay-][class$='+number+']");
$(this).data('data-wow-delay', delayTime + 's');
});
Find the divs that has delay-1, or delay-3, and so on...
Get the number as a variable.
Remove the class because I don't need it anymore.
Add to the div data-wow-delay="1s"
I am using the above script but it doesn't seem to succeed in identifying the class.
jquery wildcards don't work with removeClass
This is correct, because removeClass doesn't use a selector, it uses explicit class names - it's directly equivalent would be addClass, for which it makes no sense to have wildcards.
You can get all the classes and loop through them, giving an exact value for remove class, and, in your case for the delayTime value.
// match where all the classes might contain a relevant one
$("[class*='delay-']").each(function() {
// Keep 'this' for inside later loop
var el = $(this);
// get all the classes
var classList = el.attr('class').split(/\s+/);
// loop each class to check if it's one to remove
$.each(classList, function(index, item) {
if (item.startsWith("delay-")) {
el.removeClass(item);
var delayTime = parseInt(item.substring(6), 10);
el.data('data-wow-delay', delayTime + 's');
}
});
});
You could reduce the code with $.map, but this gives the idea.
Working fiddle: https://jsfiddle.net/hne72o8m/
The removeClass function takes a function argument since jQuery 1.4.
So it can be done with a one-liner. See Best answer in jQuery removeClass wildcard

Select tags that starts with "x-" in jQuery

How can I select nodes that begin with a "x-" tag name, here is an hierarchy DOM tree example:
<div>
<x-tab>
<div></div>
<div>
<x-map></x-map>
</div>
</x-tab>
</div>
<x-footer></x-footer>
jQuery does not allow me to query $('x-*'), is there any way that I could achieve this?
The below is just working fine. Though I am not sure about performance as I am using regex.
$('body *').filter(function(){
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
Working fiddle
PS: In above sample, I am considering body tag as parent element.
UPDATE :
After checking Mohamed Meligy's post, It seems regex is faster than string manipulation in this condition. and It could become more faster (or same) if we use find. Something like this:
$('body').find('*').filter(function(){
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
jsperf test
UPDATE 2:
If you want to search in document then you can do the below which is fastest:
$(Array.prototype.slice.call(document.all)).filter(function () {
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
jsperf test
There is no native way to do this, it has worst performance, so, just do it yourself.
Example:
var results = $("div").find("*").filter(function(){
return /^x\-/i.test(this.nodeName);
});
Full example:
http://jsfiddle.net/6b8YY/3/
Notes: (Updated, see comments)
If you are wondering why I use this way for checking tag name, see:
JavaScript: case-insensitive search
and see comments as well.
Also, if you are wondering about the find method instead of adding to selector, since selectors are matched from right not from left, it may be better to separate the selector. I could also do this:
$("*", $("div")). Preferably though instead of just div add an ID or something to it so that parent match is quick.
In the comments you'll find a proof that it's not faster. This applies to very simple documents though I believe, where the cost of creating a jQuery object is higher than the cost of searching all DOM elements. In realistic page sizes though this will not be the case.
Update:
I also really like Teifi's answer. You can do it in one place and then reuse it everywhere. For example, let me mix my way with his:
// In some shared libraries location:
$.extend($.expr[':'], {
x : function(e) {
return /^x\-/i.test(this.nodeName);
}
});
// Then you can use it like:
$(function(){
// One way
var results = $("div").find(":x");
// But even nicer, you can mix with other selectors
// Say you want to get <a> tags directly inside x-* tags inside <section>
var anchors = $("section :x > a");
// Another example to show the power, say using a class name with it:
var highlightedResults = $(":x.highlight");
// Note I made the CSS class right most to be matched first for speed
});
It's the same performance hit, but more convenient API.
It might not be efficient, but consider it as a last option if you do not get any answer.
Try adding a custom attribute to these tags. What i mean is when you add a tag for eg. <x-tag>, add a custom attribute with it and assign it the same value as the tag, so the html looks like <x-tag CustAttr="x-tag">.
Now to get tags starting with x-, you can use the following jQuery code:
$("[CustAttr^=x-]")
and you will get all the tags that start with x-
custom jquery selector
jQuery(function($) {
$.extend($.expr[':'], {
X : function(e) {
return /^x-/i.test(e.tagName);
}
});
});
than, use $(":X") or $("*:X") to select your nodes.
Although this does not answer the question directly it could provide a solution, by "defining" the tags in the selector you can get all of that type?
$('x-tab, x-map, x-footer')
Workaround: if you want this thing more than once, it might be a lot more efficient to add a class based on the tag - which you only do once at the beginning, and then you filter for the tag the trivial way.
What I mean is,
function addTagMarks() {
// call when the document is ready, or when you have new tags
var prefix = "tag--"; // choose a prefix that avoids collision
var newbies = $("*").not("[class^='"+prefix+"']"); // skip what's done already
newbies.each(function() {
var tagName = $(this).prop("tagName").toLowerCase();
$(this).addClass(prefix + tagName);
});
}
After this, you can do a $("[class^='tag--x-']") or the same thing with querySelectorAll and it will be reasonably fast.
See if this works!
function getXNodes() {
var regex = /x-/, i = 0, totalnodes = [];
while (i !== document.all.length) {
if (regex.test(document.all[i].nodeName)) {
totalnodes.push(document.all[i]);
}
i++;
}
return totalnodes;
}
Demo Fiddle
var i=0;
for(i=0; i< document.all.length; i++){
if(document.all[i].nodeName.toLowerCase().indexOf('x-') !== -1){
$(document.all[i].nodeName.toLowerCase()).addClass('test');
}
}
Try this
var test = $('[x-]');
if(test)
alert('eureka!');
Basically jQuery selector works like CSS selector.
Read jQuery selector API here.

jQuery replace strings in many classes

I'm trying to use jQuery to replace all occurrences of a particular string that occurs in a certain class. There are multiple classes of this type on the page.
So far I have the following code:
var el = $('div.myclass');
if(el != null && el.html() != null )
{
el.html(el.html().replace(/this/ig, "that"));
}
This doesn't work if there is more than one div with class myclass. If there is more than one div then the second div is replaced with the contents of the first! It is as if jQuery performs the replacement on the first div and then replaces all classes of myclass with the result.
Anyone know how I should be doing this? I'm thinking some kind of loop over all instances of mychass divs - but my JS is a bit weak.
I think what you are looking for is something like this:
$('div.myclass').each(function(){
var content = $(this).html();
content = content.replace(/this/ig,'that');
$(this).html(content);
});
(not tested)
slightly different of previous answer:
$('div.myclass').each(function(i, el) {
if($(el).html() != "" ) {
$(el).html($(el).html().replace(/this/ig, "that"));
}
});
should work
If the contents of your .myclass elements are purely textual, you can get away with this. But if they contain other elements your regex processing might change attribute values by mistake. Don't process HTML with regex.
Also by writing to the innerHTML/html(), you would lose any non-serialisable data in any child element, such as form field values, event handlers and other JS references.
function isTextNode(){
return this.nodeType===3; // Node.TEXT_NODE
}
$('div.myclass, div.myclass *').each(function () {
$(this).contents().filter(isTextNode).each(function() {
this.data= this.data.replace(/this/g, 'that');
});
});

Categories