Removing all classes which match multiple partial class names in javascript - javascript

I use the removeClass function and pass it a callback to remove a class which matches a partial name
Here is my code
$('.target').removeClass(function (index, className) {
return (className.match(/(^|\s)bg_\S+/g) || []).join(' ');
});
What I want to do is remove all classes which start with bg_ AND any number of other possible matches.
I tried this
$('.target').removeClass(function (index, className) {
return (className.match(/(^|\s)bg_\S+/g|/(^|\s)ag_\S+/g) || []).join(' ');
});
to Remove anything that started with 'bg' AND 'ag', but it didn't work.
I appreciate the help, thank you.

Well, you can try this.
function removeClasses(){
var classes = $(".target").attr("class").split(' ');
console.log("Before removing: ",$(".target").attr("class"))
classes.forEach(e=> {
var flag = e.substring(0, 3);
if(flag === "AND" || flag.substring(0, 2) === "ag" || flag.substring(0, 2) === "bg"){
$(".target").removeClass(e)
}
})
console.log("After removing: ",$(".target").attr("class"))
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="target bgAA AA ANDse agEF FF"></div>
<button onclick="removeClasses()">Remove</button>

Instead of trying to match the entire classname with a regexp, split it into separate classes and then filter that array.
$(".target").removeClass((i, className) => {
var classList = className.split(" ");
return classList.filter(class => /^(bg_|ag_)/.test(class)).join(" ");
});

Here is a wrapper solution I wrote with your help.
// Wrapper for JQuery removeClass - pass a collection of elements and your own regex. This will strip out any classes matching the regex
var removeClassesByPartialMatch = function (targets, regex) {
regex = new RegExp(regex);
targets.removeClass((i, classes) => {
var classes = classes.split(' ');
return classes.filter(name => regex.test(name)).join(' ');
});
}

Related

Find and replace character in multiple HTML tags

I'm trying to loop through multiple HTML elements, to replace a character in those elements.
I managed to do it with only one element
HTML
<h2>test</h2>
JS
var test = document.querySelector("h2");
var text = test.textContent;
var arr = [];
for(i=0;i<text.length;i++){
arr.push(text[i]);
}
for(j=0;j<arr.length;j++){
if(arr[j] === "t"){
arr[j] = "z";
}
}
var newText = arr.join('');
test.innerHTML = newText;
but how would I go about looping through multiple h2s? The idea is to replace the letter "t" with "z", then push the new word into the HTML.
HTML
<h2>test</h2>
<h2>teeth</h2>
<h2>trent</h2>
I tried document.querySelectorAll, but not sure how to appropriately use textContent in this case.
Thanks in advance!
This should do the trick:
const replaceInSelection = (target, replacement, selector) => {
const t = new RegExp(target, 'g')
document.querySelectorAll(selector).forEach(
el => el.textContent = el.textContent.replace(t, replacement)
)
}
<h2>test</h2>
<h2>teeth</h2>
<h2>trent</h2>
<button onclick="replaceInSelection('t', 'z', 'h2')">t -> z</button>
<button onclick="replaceInSelection('z', 't', 'h2')">z -> t</button>
That is because querySelector only retrieves a single element (the first that matches the selector). Fortunately there is querySelectorAll method that allows to retrieve all matching elements.
In addition to that, you can simplify your code quite a bit: since your goal is to replace any occurence of the letter t with the letter z then you should do just that. An element's textContent will always be a string, therefore you can use String#replace to do your operation.
document
.querySelectorAll("h2")
.forEach(elem => {
/*
You can assign the result to elem.innerHTML or
elem.textContent depending on your needs
*/
elem.innerHTML = elem.textContent.replace(/t/g, "z");
});
function replaceElementsText(selector, substr, newSubstr){
if(!selector || !substr || !newSubstr){
return;
}
const elems = [...document.querySelectorAll(selector)];
elems.forEach(el => el.innerText = el.innerText.replace(new RegExp(substr, "g"),newSubstr))
}
replaceElementsText('h2', 't','z')
var hs = document.querySelectorAll('h2');
hs.forEach(h => {
h.textContent = h.textContent.replace(/t/g /*target*/, "z"/*new char*/);
});
good luck! D;

Remove multiple elements from array

I'd like to remove multiple specific elements from my array before it displays. Here is the code I have but it results in none of the elements being displayed:
$('[data-fancybox]').on('click', function() {
var visibleLinks = $('.fancybox:visible');
$.fancybox.open( visibleLinks, {
//options go here
caption: function (instance, item) {
var caption, link, collectTags, tags, filterTags, filteredTags;
function format(tpl, binding) {
if (typeof binding != 'function') return format(tpl, function (_, name) {
return binding[name];
});
return tpl.replace(/\$(\w+)/g, binding);
}
caption = $(this).data('caption');
link = format('<br>See more pictures', item);
collectTags = $(this).parent().attr("class").split(' ');
function createTag(it) {
return format("<a href='$site$it'>$it</a>", {
site: (it == 'wedding' || it == 'concert') ? 'http://example.com/gallery/#filter=.' : 'http://example.com/gallery/#filter=.',
it: it
});
}
filterTags = ['churchevent', 'corporate'];
filteredTags = tags.filter(function(itm){return itm!== filterTags});
tags = $.map(collectTags, createTag);
return [].concat(caption ? [caption, link] : link).concat(filteredTags.slice(1).join(', ')).join('<br>');
}
}, visibleLinks.index( this ) );
return false;
});
I'm supposing that, since you wrote "remove multiple specific elements" you want to REMOVE filterTags.
If that's the case then change this:
filterTags = ['churchevent', 'corporate'];
filteredTags = tags.filter(function(itm){return itm!== filterTags});
tags = $.map(collectTags, createTag);
return [].concat(caption ? [caption, link] : link).concat(filteredTags.slice(1).join(', ')).join('<br>');
to this:
filterTags = ['churchevent', 'corporate'];
tags = $.map(collectTags, createTag);
filteredTags = tags.filter((item)=>{
for(tag in filterTags) if (item.indexOf(filterTags[tag]) != -1) return false;
return true;
});
return [].concat(caption ? [caption, link] : link).concat(filteredTags.slice(1).join(', ')).join('<br>');
else just use != -1 instead of == -1 in the filter method.
What is "tags" in the context of tags.filter? I'm assuming it is some array. In either case, your filter is checking that an item in tags is not equal to filterTags, an array. Of course a single item in an array won't be equal to an array, so this will always return true, thus not filtering anything.
I think you probably want something like:
filteredTags = tags.filter(function(itm){return filterTags.indexOf(itm) !== -1});
Are you speaking about this array?
filterTags = ['churchevent', 'corporate'];
filteredTags = tags.filter(function(itm){return itm!== filterTags});
// Of note, you are creating tags just below this code. Should you move it up?
// Or rename tags => collectionTags???
// Either way, the filter function you are using is not doing what you expect.
tags.filter(function(itm){
// itm will be whatever, I'm guessing a string of some sort like "churchevent"
// Now you are trying to compare a string like "churchevent" to the
// array filterTags.
// This is what is happening...
return itm !== ['churchevent', 'corporate'];
// What you want to do is this in ES5
return (filterTags.indexOf(itm) === -1);
// or this in ES6
return !filterTags.includes(itm);
// Note the bang in front.
// TRUE will put itm in the tags array, FALSE will not.
}
Also, please reference the filter function in MDN.
Filter Function (MDN)

Use non-english characters in List.js

I have a list of features created with List.js library. Is there any way I could match non-english characters with regular ones?
For example, the list contains this elements: 'șuncă', 'brânză', 'mărar'.
I'm curious if there's a way to find these elements even if I'm searching without the non-english characters, like this: 'sunca', 'branza', 'marar'
Use the filter() API function and a helper function to replace accented characters in a string with their base versions.
Helper functions
// generic accent removal from input string, add any missing characters
var removeAccents = (function () {
var letters1 = "äáàâăëéèêĕüúùûŭöóòôŏÄÁÀÂĂËÉÈÊĔÜÚÙÛŬÖÓÒÔŎßșȘ",
letters2 = "aaaaaeeeeeuuuuuoooooAAAAAEEEEEUUUUUOOOOOssS",
patternLetters = new RegExp("[" + letters1 + "]", "g"),
lookupLetters = {}, letterTranslator;
letters1.split("").forEach(function (letter, i) {
lookupLetters[letter] = letters2[i];
});
letterTranslator = function(match) {
return lookupLetters[match] || match;
};
return function removeAccents(input) {
return input.replace(patternLetters, letterTranslator);
};
})();
// creates a specific filter function for use in List.js
function getAccentInsensitiveFilter(property, search) {
search = removeAccents(search).toLowerCase();
return function (item) {
var value = removeAccents(item.values()[property] || "").toLowerCase();
return value.indexOf(search) > -1;
};
}
and then
// filter for "sunca" in the "featureName" property
yourList.filter(getAccentInsensitiveFilter("featureName", "șuncă"));
// remove filter
yourList.filter();

jQuery selector that simulates :starts-with or :ends-with for searching text?

If you look at the selectors list on the jQuery website, there are selectors for starts-with and ends-with on attributes. There's also a :contains selector for searching text:
alert( $("div").find("span:contains(text)").html() );
Does jQuery have an implementation for searching strings using starts-with or ends-with?
FYI: I need to search through an XML object.
Not by default as far as I know, but you can add your own pseudo-selectors through $.expr[":"]: http://jsfiddle.net/h6KYk/.
$.extend($.expr[":"], {
"starts-with": function(elem, i, data, set) {
var text = $.trim($(elem).text()),
term = data[3];
// first index is 0
return text.indexOf(term) === 0;
},
"ends-with": function(elem, i, data, set) {
var text = $.trim($(elem).text()),
term = data[3];
// last index is last possible
return text.lastIndexOf(term) === text.length - term.length;
}
});
When you don't want to extend jQuery, you can use the filter() function to create the contains functionality:
$("div").find("span").filter(function () {
return $(this).text().indexOf(text) >= 0;
});
Or create a startsWith function with a regular expression:
var expression = new RegExp('^' + text);
$("div").find("span").filter(function () {
return expression.test($.trim($(this).text()));
});
The endsWith function is quite similar:
var expression = new RegExp(text + '$');
$("div").find("span").filter(function () {
return expression.test($.trim($(this).text()));
});
Note the use of $.trim() because HTML can contain a lot of whitespace.

Remove all classes that begin with a certain string

I have a div with id="a" that may have any number of classes attached to it, from several groups. Each group has a specific prefix. In the javascript, I don't know which class from the group is on the div. I want to be able to clear all classes with a given prefix and then add a new one. If I want to remove all of the classes that begin with "bg", how do I do that? Something like this, but that actually works:
$("#a").removeClass("bg*");
A regex splitting on word boundary \b isn't the best solution for this:
var prefix = "prefix";
var classes = el.className.split(" ").filter(function(c) {
return c.lastIndexOf(prefix, 0) !== 0;
});
el.className = classes.join(" ").trim();
or as a jQuery mixin:
$.fn.removeClassPrefix = function(prefix) {
this.each(function(i, el) {
var classes = el.className.split(" ").filter(function(c) {
return c.lastIndexOf(prefix, 0) !== 0;
});
el.className = $.trim(classes.join(" "));
});
return this;
};
2018 ES6 Update:
const prefix = "prefix";
const classes = el.className.split(" ").filter(c => !c.startsWith(prefix));
el.className = classes.join(" ").trim();
With jQuery, the actual DOM element is at index zero, this should work
$('#a')[0].className = $('#a')[0].className.replace(/\bbg.*?\b/g, '');
I've written a simple jQuery plugin - alterClass, that does wildcard class removal.
Will optionally add classes too.
$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
You don't need any jQuery specific code to handle this. Just use a RegExp to replace them:
$("#a").className = $("#a").className.replace(/\bbg.*?\b/g, '');
You can modify this to support any prefix but the faster method is above as the RegExp will be compiled only once:
function removeClassByPrefix(el, prefix) {
var regx = new RegExp('\\b' + prefix + '.*?\\b', 'g');
el.className = el.className.replace(regx, '');
return el;
}
Using 2nd signature of $.fn.removeClass :
// Considering:
var $el = $('<div class=" foo-1 a b foo-2 c foo"/>');
function makeRemoveClassHandler(regex) {
return function (index, classes) {
return classes.split(/\s+/).filter(function (el) {return regex.test(el);}).join(' ');
}
}
$el.removeClass(makeRemoveClassHandler(/^foo-/));
//> [<div class=​"a b c foo">​</div>​]
For modern browsers:
let element = $('#a')[0];
let cls = 'bg';
element.classList.remove.apply(element.classList, Array.from(element.classList).filter(v=>v.startsWith(cls)));
An approach I would use using simple jQuery constructs and array handling functions, is to declare an function that takes id of the control and prefix of the class and deleted all classed. The code is attached:
function removeclasses(controlIndex,classPrefix){
var classes = $("#"+controlIndex).attr("class").split(" ");
$.each(classes,function(index) {
if(classes[index].indexOf(classPrefix)==0) {
$("#"+controlIndex).removeClass(classes[index]);
}
});
}
Now this function can be called from anywhere, onclick of button or from code:
removeclasses("a","bg");
http://www.mail-archive.com/jquery-en#googlegroups.com/msg03998.html says:
...and .removeClass() would remove all classes...
It works for me ;)
cheers
I was looking for solution for exactly the same problem. To remove all classes starting with prefix "fontid_" After reading this article I wrote a small plugin which I'm using now.
(function ($) {
$.fn.removePrefixedClasses = function (prefix) {
var classNames = $(this).attr('class').split(' '),
className,
newClassNames = [],
i;
//loop class names
for(i = 0; i < classNames.length; i++) {
className = classNames[i];
// if prefix not found at the beggining of class name
if(className.indexOf(prefix) !== 0) {
newClassNames.push(className);
continue;
}
}
// write new list excluding filtered classNames
$(this).attr('class', newClassNames.join(' '));
};
}(fQuery));
Usage:
$('#elementId').removePrefixedClasses('prefix-of-classes_');
In one line ...
Removes all classes that match a regular expression someRegExp
$('#my_element_id').removeClass( function() { return (this.className.match(/someRegExp/g) || []).join(' ').replace(prog.status.toLowerCase(),'');});
I know it's an old question, but I found out new solution and want to know if it has disadvantages?
$('#a')[0].className = $('#a')[0].className
.replace(/(^|\s)bg.*?(\s|$)/g, ' ')
.replace(/\s\s+/g, ' ')
.replace(/(^\s|\s$)/g, '');
Prestaul's answer was helpful, but it didn't quite work for me. The jQuery way to select an object by id didn't work. I had to use
document.getElementById("a").className
instead of
$("#a").className
I also use hyphen'-' and digits for class name. So my version include '\d-'
$('#a')[0].className = $('#a')[0].className.replace(/\bbg.\d-*?\b/g, '');
(function($)
{
return this.each(function()
{
var classes = $(this).attr('class');
if(!classes || !regex) return false;
var classArray = [];
classes = classes.split(' ');
for(var i=0, len=classes.length; i<len; i++) if(!classes[i].match(regex)) classArray.push(classes[i]);
$(this).attr('class', classArray.join(' '));
});
})(jQuery);
The top answer converted to jQuery for those wanting a jQuery only solution:
const prefix = 'prefix'
const classes = el.attr('class').split(' ').filter(c => !c.startsWith(prefix))
el.attr('class', classes.join(' ').trim())
$("#element").removeAttr("class").addClass("yourClass");

Categories