I have the following HTML:
<div class="cols someclass"></div> <!--like this cols1, cols2, etc..-->
<div class="columns someclass"></div> <!--like this columns1, columns2, etc...-->
<div class="col-1 someclass"></div> <!--like this col-2, col-3,etc...-->
<div class="column-1 someclass"></div> <!--like this column-2, column-3, etc...-->
How to remove all classes starting with "col"?
I believe there is no jQuery magic for this, so here's my solution:
$('[class*=col]').each(function() {
this.className = $.grep(this.className.split(' '), function(el) {
return !/^col/.test(el);
}).join(' ');
});
Fiddle
Basically, it selects elements that have col in their classes and iterate over them, iterating over their classes and removing those that begin with col.
Or without regex:
$('[class*=col]').each(function() {
this.className = $.grep(this.className.split(' '), function(cl) {
return cl.lastIndexOf('col', 0);
}).join(' ');
});
Fiddle
Using a modified version of this answer. lastIndexOf will return 0 if the class starts with col which is a falsy value and thus grep will remove it. If the class does not begin with col, then -1 is returned which is a truthy value. You can use return cl.lastIndexOf('col', 0) !== 0; for a bit extra readability as well.
Or with regex only:
$('[class*=col]').each(function() {
this.className = this.className.replace(/(^| )col[^ ]*/g, '');
});
Fiddle
Matches col at beginning of the string or after a space, removes it together with all leading characters up to another space or end of the string.
Referece
jQuery.grep - Finds the elements of an array which satisfy a filter function. The original array is not affected.
element.className - gets and sets the value of the class attribute of the specified element.
Of course, this selector is not optimal - if an element has foocol the $('[class*=col]') will select it, but the $.grep/regex will not remove it as it does not begin with col. I can't think of any better selector (there's no attribute selector to select a value beginning with a partial string in a space-separated list AFAIK), nevertheless this should suffice just fine.
Related
I have a span element with a piece of inner text. I need to target specific pieces of that text through regex and turn my matches into span elements with a class attribute class="hightlight-yellow" and a custom attribute called my-custom-attribute="hello".
Here is my input and expected output...
Input
<span class="message"> This is some text $HIGH:LOW $LOW:HIGH </span>
Output
<span> This is some text <span class="highlight-yellow" my-custom-attribute="hello">$HIGH:LOW</span> <span class="highlight-yellow" my-custom-attribute="hello">$LOW:HIGH</span></span>
How can I do the replace? Here is my current code colleting the matches
function handle()
{
let element = document.getElementsByClassName('message')
let text = element[0].innerText;
let regex = /([^=])\$([A-Za-z:]{1,})/g;
let matches = text.match(regex);
if(matches != null)
{
for(let i = 0; i < matches.length; ++i)
{
// TODO takes matches are replace with spans with attributes.
}
}
}
You can simply use your regex in String.prototype.replace() and replace it with the desired markup wrapping your capturing group.
I have removed the first capturing group since it matches the empty whitespace before, which is not what you want. On top of that, I'd suggest using querySelectorAll and iterate through the node list to future proof your setup.
If you really only want to select the first element that matches the selector .message, that's also possible.
NOTE: Your output also seems to remove the message class from your original <span> element, but I'm not sure if that is a typo or intentional.
See proof-of-concept below:
function handle() {
const regex = /\$([A-Za-z:]{1,})/g;
document.querySelectorAll('.message').forEach(el => {
el.innerHTML = el.innerText.replace(regex, '<span class="highlight-yellow" my-custom-attribute="hello">$1</span>');
});
}
handle();
span.highlight-yellow {
background-color: yellow;
}
<span class="message">This is some text $HIGH:LOW $LOW:HIGH</span>
I have many classes and want to remove the commas in them if any commas exist there.
I wrote the below code but the code does not work correctly. The second class value is replaced with the first value.
var removebox = $(".remove"),
removeboxHtml = removebox.html();
removebox.html(removeboxHtml.replace(/,/g , ''));
<html>
<head>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.12.4.min.js"></script>
</head>
<body>
<span class="remove">,17500000</span>
<span class="remove">,2479000</span>
</body>
</html>
Try this. Updated your code:
$(".remove").each(function(){
$(this).html($(this).html().replace(/,/g , ''));
});
<html>
<head>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.12.4.min.js"></script>
</head>
<body>
<span class="remove">,17500000</span>
<span class="remove">,2479000</span>
</body>
</html>
I would iterate over each element and change its' text:
var removebox = $(".remove");
removebox.each(function () {
var oldtext = $(this).text();
$(this).text(oldtext.replace(',', ''));
});
While you've already accepted an answer to this problem it's worth pointing out that they're both rather too verbose, and one answer, shennan's (at the time of writing), will only remove one comma from each of the given elements should multiple commas be present therein.
That said, a more concise version is below:
// select the elements to update:
$('.remove')
// we then use the text method's anonymous function,
// using the two arguments:
// index: the index of the current element in the collection,
// currentText: the text of the current element of the
// collection over the text method iterates:
.text(function(index, currentText) {
// here we access the currentText variable and use
// String.prototype.replace(), with a regular literal (/.../)
// to remove all occurrences (g) of the specified comma character
// replacing those occurrences with an empty string (''); this
// is comma-removed string is returned to the text method in
// order to update the text of each element as required:
return currentText.replace(/,/g, '');
});
$('.remove').text(function(index, currentText) {
return currentText.replace(/,/g, '');
});
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.12.4.min.js"></script>
<span class="remove">,17500000</span>
<span class="remove">,2479000</span>
<span class="remove">5,279,000</span>
Of course it's also worth showing that the above is perfectly possible in plain JavaScript, and still relatively concise:
// we use document.querySelectorAll() to retrieve
// a non-live HTMLCollection of elements matched
// by the supplied CSS selector:
var elements = document.querySelectorAll('.remove');
// we use Array.from() to convert an Array-like Object
// into an Array, in order that we can then iterate
// over those elements using Array.prototype.forEach():
Array.from(elements).forEach(function(elem) {
// 'elem', the first argument, is a reference to the
// current element of the Array of elements over
// which we're iterating.
// here we retrieve the current text-content of the
// current element, and use String.prototype.replace(),
// with a regular expression (exactly as above) to
// replace all occurrences ('g') of the comma character
// (',') in the string supplied by elem.textContent and
// we replace those commas with a empty string (''):
elem.textContent = elem.textContent.replace(/,/g, '');
});
var elements = document.querySelectorAll('.remove');
Array.from(elements).forEach(function(elem) {
elem.textContent = elem.textContent.replace(/,/g, '');
});
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.12.4.min.js"></script>
<span class="remove">,17500000</span>
<span class="remove">,2479000</span>
<span class="remove">5,279,000</span>
References:
JavaScript:
Array.from().
Array.prototype.forEach().
Document.querySelectorAll().
"Guide to JavaScript Regular Expressions."
String.prototype.replace().
jQuery:
text().
Lets say I have this in my html:
<div id="myDiv" class="a b-32"/>
I'm trying to get the index of 'b' class (in my example '32')
The only way I know how to do it is by:
var index;
var myDiv = $("#myDiv").attr("class");
var classes = myDiv.split(' ');
for(var i=0; i<classes.size(); i++){
if(classes[i].matches((b-)+[\d]*) ){
index = classes[i].replace("b-","");
}
}
alert(index);
Is there any solution that doesn't imply iterating all the classes manually? Because my solution seems dull. Surely there must be a better way, I just can't find it.
Y'know, for all that people claim jQuery makes it so you have to write less code, Vanilla JS is surprisingly good at one-liners :p
alert((document.getElementById('myDiv').className
.match(/(?:^| )b-(\d+)/) || [0,0])[1]);
(Whitespace added for readability)
Returns 0 in the event where myDiv doesn't have a b-number class.
EDIT: As #A.Wolff pointed out in a comment on your question, you may wish to consider this:
<div id="myDiv" class="a" data-b="32"></div>
Then you can get:
alert(document.getElementById('myDiv').getAttribute("data-b"));
A regular expression can help:
var index;
var myDivClasses = $("#myDiv").attr("class");
var cls = myDivClasses.match(/(?:^| )b-(\d+)(?:$| )/);
if (cls) {
index = cls[1];
}
(Use parseInt if you want it as a number.)
That looks for b-### where ### is one or more digits, with either whitespace or a boundary (start of string, end of string) on either side, and extracts the digits.
I have the following HTML code:
<ul>
<li>apples <span id="apples-density">1</span></li>
<li>pears <span id="pears-density">0</span></li>
<li>oranges <span id="oranges-density">2</span></li>
</ul>
<textarea>This is where I love to eat apples and oranges</textarea>
<textarea>I also like oranges on Sundays!</textarea>
What I would to achieve is that when ever the textarea is updated (on key up), the density of the 3 specific words is counted and then the value inside the SPAN is updated.
However, the page can contain up to 10 words that will need to be counted and also an unlimited number of TEXTAREA elements. And... the actual 3 words that are being counted are different each time, so the code has to allow for some sort of automation.
I can sort of see how it should work in my head, but not quite how to implement...
perform a jquery .each on the textarea values.
perform a jquery to grab each of the <li> values
so some sort of regex to match the content of the textarea's and count the words.
update the .text of the correct to show the value.
My own suggestion would be:
function wordsUsed(){
// get all the text from all the textarea elements together in one string:
var text = $('textarea').map(function(){
return $(this).val();
}).get().join(' '),
reg;
// iterate over the span elements found in each li element:
$('li > span').each(function(i,el){
// cache the variable (in case you want to use it more than once):
var that = $(el);
// create a RegExp (regular expression) object:
// the '\\b' is a word boundary double-escaped because it's a string;
// we shorten the id of the current element by removing '-frequency'
// (I didn't think 'density' was an appropriate description) to find
// the word we're looking for;
// 'gi' we look through the whole of the string (the 'g') and
// ignore the case of the text (the 'i'):
reg = new RegExp('\\b' + el.id.replace('-frequency','') + '\\b', 'gi');
// we look for the regular-expression ('reg') matches in the string ('text'):
var matched = text.match(reg),
// if matched does not exist (there were no matched words) we set
// the count to 0, otherwise we use the number of matches (length):
matches = !matched ? 0 : matched.length;
// setting the text of the current element:
that.text(matches);
});
}
$('textarea')
// binding the keyup event-handler, using 'on()':
.on('keyup', wordsUsed)
// triggering the keyup event, so the count is accurate on page-load:
.keyup();
JS Fiddle demo.
The above works on the (pedantically) modified HTML:
<ul>
<li>apples <span id="apples-frequency"></span>
</li>
<li>pears <span id="pears-frequency"></span>
</li>
<li>oranges <span id="oranges-frequency"></span>
</li>
</ul>
<textarea>actual text removed for brevity</textarea>
<textarea>actual text removed for brevity</textarea>
References:
'Plain' JavaScript:
JavaScript regular expressions.
RegExp().
String.prototype.match().
String.prototype.replace().
jQuery:
each().
get().
map().
on().
text().
// Get all the textarea values
var all_text = '';
$('textarea').each(function() {
all_text += ' ' + $(this).text();
}
// Process each of the LIs
$('li span').each(function() {
var word = this.id.split('-')[0]; // Get the search word
// Convert it to a regular expression. Use 'g' option to match all occurrences.
var regex = new RegEx('\b'+word+'\b', 'g');
var count = all_text.match(regex).length;
$(this).text(count);
}
I need to use Javascript to do three things:
Select all nodes with a class of "foo".
Find all words inside these nodes that begin with "*".
Surround those words with <span class="xyz"> ... </span>, where xyz is the word itself.
For example, the content:
<ul>
<li class="foo">
*abc def *ghi
</li>
<li class="bar">
abc *def *ghi
</li>
</ul>
would become
<ul>
<li class="foo">
<span class="abc">*abc</span> def <span class="ghi">*ghi</span>
</li>
<li class="bar">
abc *def *ghi <!-- Not part of a node with class "foo", so
</li> no changes made. -->
</ul>
How might I do this? (P.S. Solutions involving jQuery work too, but other than that I'd prefer not include any additional dependencies.)
No jQuery required:
UE_replacer = function (node) {
// just for performance, skip attribute and
// comment nodes (types 2 and 8, respectively)
if (node.nodeType == 2) return;
if (node.nodeType == 8) return;
// for text nodes (type 3), wrap words of the
// form *xyzzy with a span that has class xyzzy
if (node.nodeType == 3) {
// in the actual text, the nodeValue, change
// all strings ('g'=global) that start and end
// on a word boundary ('\b') where the first
// character is '*' and is followed by one or
// more ('+'=one or more) 'word' characters
// ('\w'=word character). save all the word
// characters (that's what parens do) so that
// they can be used in the replacement string
// ('$1'=re-use saved characters).
var text = node.nodeValue.replace(
/\b\*(\w+)\b/g,
'<span class="$1">*$1</span>' // <== Wrong!
);
// set the new text back into the nodeValue
node.nodeValue = text;
return;
}
// for all other node types, call this function
// recursively on all its child nodes
for (var i=0; i<node.childNodes.length; ++i) {
UE_replacer( node.childNodes[i] );
}
}
// start the replacement on 'document', which is
// the root node
UE_replacer( document );
Updated: To contrast the direction of strager's answer, I got rid of my botched jQuery and kept the regular expression as simple as possible. This 'raw' javascript approach turns out to be much easier than I expected.
Although jQuery is clearly good for manipulating DOM structure, it's actually not easy to figure out how to manipulate text elements.
Don't try to process the innerHTML/html() of an element. This will never work because regex is not powerful enough to parse HTML. Just walk over the Text nodes looking for what you want:
// Replace words in text content, recursively walking element children.
//
function wrapWordsInDescendants(element, tagName, className) {
for (var i= element.childNodes.length; i-->0;) {
var child= element.childNodes[i];
if (child.nodeType==1) // Node.ELEMENT_NODE
wrapWordsInDescendants(child, tagName, className);
else if (child.nodeType==3) // Node.TEXT_NODE
wrapWordsInText(child, tagName, className);
}
}
// Replace words in a single text node
//
function wrapWordsInText(node, tagName, className) {
// Get list of *word indexes
//
var ixs= [];
var match;
while (match= starword.exec(node.data))
ixs.push([match.index, match.index+match[0].length]);
// Wrap each in the given element
//
for (var i= ixs.length; i-->0;) {
var element= document.createElement(tagName);
element.className= className;
node.splitText(ixs[i][1]);
element.appendChild(node.splitText(ixs[i][0]));
node.parentNode.insertBefore(element, node.nextSibling);
}
}
var starword= /(^|\W)\*\w+\b/g;
// Process all elements with class 'foo'
//
$('.foo').each(function() {
wrapWordsInDescendants(this, 'span', 'xyz');
});
// If you're not using jQuery, you'll need the below bits instead of $...
// Fix missing indexOf method on IE
//
if (![].indexOf) Array.prototype.indexOf= function(item) {
for (var i= 0; i<this.length; i++)
if (this[i]==item)
return i;
return -1;
}
// Iterating over '*' (all elements) is not fast; if possible, reduce to
// all elements called 'li', or all element inside a certain element etc.
//
var elements= document.getElementsByTagName('*');
for (var i= elements.length; i-->0;)
if (elements[i].className.split(' ').indexOf('foo')!=-1)
wrapWordsInDescendants(elements[i], 'span', 'xyz');
The regexp would look something like this (sed-ish syntax):
s/\*\(\w+\)\b\(?![^<]*>\)/<span class="\1">*\1</span>/g
Thus:
$('li.foo').each(function() {
var html = $(this).html();
html = html.replace(/\*(\w+)\b(?![^<]*>)/g, "<span class=\"$1\">*$1</span>");
$(this).html(html);
});
The \*(\w+)\b segment is the important piece. It finds an asterisk followed by one or more word characters followed by some sort of word termination (e.g. end of line, or a space). The word is captured into $1, which is then used as the text and the class of the output.
The part just after that ((?![^<]*>)) is a negative lookahead. It asserts that a closing angle bracket does not follow, unless there is an opening angle bracket before it. This prevents a match where the string is inside an HTML tag. This doesn't handle malformed HTML, but that shouldn't be the case anyway.