Case-insensitive attribute-value selector with Jquery - javascript

I need to get the value of the content attribute of a certain meta tag.
var someContent = $("meta[name=someKindOfId]").attr("content");
is how I usually do it. For business reasons, someKindOfId may be somekindofid. It could be other combinations of cases as well. I don't know.
What is the best way to search for this meta tag? Adding an id or other identifier is out of the question.

You could use the jquery filter function like so
var meta = $('meta[name]').filter(function() {
return this.name.toLowerCase() == 'somekindofid';
});
Based upon CSS selector case insensitive for attributes
http://jsfiddle.net/nickywaites/mkBvC/

Also, for case insensitive attribute *= selector:
$("meta[name*=someKindOfId]")
You can use:
$('meta').filter(function() {
return (/somekindofid/i).test($(this).attr('name'));
}).attr("content")

How about this?
You can reuse the case-insensitive jQuery expression, as shown in the snippet below (execute it to see how the first div matches, while the second does not).
$.expr[':'].iAttrContains = function(node, stackIndex, properties){
var args = properties[3].split(',').map(function(arg) {
return arg.replace(/^\s*["']|["']\s*$/g, '');
});
if ($(node).attr(args[0])) {
//exact match:
return $(node).attr(args[0]).toLowerCase() == args[1].toLowerCase();
//if you actually prefer a "contains" behavior:
//return -1 !== $(node).attr(args[0]).toLowerCase().indexOf(args[1].toLowerCase());
}
};
$("div:iAttrContains('data-name', 'test')").addClass('matched');
div{background:red;}
div.matched{background:green;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div data-name="This is a test">First div</div>
<div data-name="This is a div">Second div</div>

Related

How to get class name of element has specific text using javascript/jquery?

I need a JavaScript or jQuery way of extracting the Class name of DIV element by the text it contains.
Let's illustrate. If I had let's say following code:
<div class="_className">UniqueText</div>
I need to to know how to programmatically do something like this:
getClassNameWhereText("UniqueText");
In this case output should be:
_className
Is there a way to do this?
JQuery :contains selector select element has specific text but it isn't exact. For example
$("div:contains(UniqueText)")
Select both of bottom divs
<div class="_className">UniqueText</div>
<div class="_className2">UniqueText2</div>
You can use .filter() to filter selected element by text.
var className = $("*").filter(function(){
return $(this).text() == "UniqueText";
}).attr("class");
var className = $("*").filter(function(){
return $(this).text() == "UniqueText";
}).attr("class");
console.log(className);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="_className">UniqueText</div>
<div class="_className2">UniqueText2</div>
By getting all the div with each function you can search through all the divs and place a condition in which you the value of the div is equal to the particular text that you want to find. Then get the class name by using .attr('class').
$( "div" ).each(function(){
if($(this).text() == "UniqueText"){
var output = $(this).attr('class');
$(".output").html(output);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="_classname">UniqueText</div>
<div class="output"></div>
It might be a bit long for a code but it gets the work done nicely. :)
You can use :contains(word)
var className = $( "div:contains('John')" ).attr("class");
console.log(className)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="foo">John Resig</div>
<div class="bar">George Martin</div>
<div class="foo">Malcom John Sinclair</div>
<div class="baz">J. Ohn</div>
You can keep an id for your div, as per your information your text will be unique.
<div id="UniqueText" class="_className">UniqueText</div>
and the js code will be
function getClassNameWhereText(text){
var className = $('#'+text).attr('class');
console.log(className);
}
UPDATE : if you want to using contains
then you can do this,
function getClassNameWhereText(text){
var val = document.getElementById(text).value;
if(text.indexOf(val)>=0){
var className = $('#'+text).attr('class');
console.log(className);
}
}
This should be faster than using jQuery (but a bit more to type):
var xpath = "//div[text()='UniqueText']";
var result = document.evaluate(xpath,
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE);
var node = result.singleNodeValue;
if (node) {
console.log(node.className);
} else {
console.error("Not found!");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="_className">UniqueText</div>
The reason is, browser's CSS selectors don't support :contains selector, and jQuery needs to emulate it by checking every node matching the rest of the selector. Ditto for using .filter. But XPath is done natively by the browser.
You also cannot specify exact match using the jQuery :contains, like here. If substring matching was indeed needed, you can change the XPath:
var xpath = "//div[contains(text(),'UniqueText')]";
XPath is very powerful, but a bit finicky and largely unknown, so I find it is very under-utilised, even when its use would be a perfect fit.

Return default value if condition can not be satisfied

I have HTML like that :
<div id="MyArea">
<div class="data-content">The content is not satisfied </div>
<div class="data-content">[value] </div>
<div class="data-content">[valueme] </div>
</div>
Now, I want run a Function in each class (data-content) that have brackets. Others class (have no brackets), keep default and do not change anything. I use script below, but it is be error.
$("#MyArea .data-content").each(function() {
var content = $(this).html(),
values = content.match(/[^[\]]+(?=])/g);
if (value !== "") {
$(this).closest(".data-content").myFunc({
//Run myFunc in this .data-content if values has brackets.
}
else {
//return the default value and do not change the content inside of that class if it has no brackets. How can I do that?}
});
}
);
I'm not sure exactly what you're trying to do here given the numerous syntax problems, but you can use test in the condition to see if the regex matches anything. Also, you cannot return anything from each iteration in a $.each loop, so that is redundant.
Try this:
$("#MyArea .data-content").each(function () {
var content = $(this).html();
if (/[^[\]]+(?=])/g.test(content)) {
$(this).closest(".data-content").css('color', '#C00');
};
});
Example fiddle
In place of .css() in my example you could call your function.

jQuery comment/uncomment <!--element-->

I am looking for a way to wrap, with jQuery, an element into a comment, like:
<!--
<div class="my_element"></div>
-->
and also a way to remove the comments.
Is this possible?
To wrap an element with comment, or more specifically to replace an element with a comment node having that element's HTML:
my_element_jq = $('.my_element');
comment = document.createComment(my_element_jq.get(0).outerHTML);
my_element_jq.replaceWith(comment);
To switch it back:
$(comment).replaceWith(comment.nodeValue);
If you don't have the reference to the comment node then you need to traverse the DOM tree and check nodeType of each node. If its value is 8 then it is a comment.
For example:
<div id="foo">
<div>bar</div>
<!-- <div>hello world!</div> -->
<div>bar</div>
</div>
JavaScript:
// .contents() returns the children of each element in the set of matched elements,
// including text and comment nodes.
$("#foo").contents().each(function(index, node) {
if (node.nodeType == 8) {
// node is a comment
$(node).replaceWith(node.nodeValue);
}
});
You can comment the element out by doing the following:
function comment(element){
element.wrap(function() {
return '<!--' + this.outerHTML + '"-->';
});
}
DEMO:
http://jsfiddle.net/dirtyd77/THBpD/27/
I'm impresed nobody gave the following solution. The following solution require a container. This container will have inside, the commented / uncommented code.
function comment(element) {
element.html('<!--' + element.html() + '-->')
}
function uncomment(element) {
element.html(element.html().substring(4, element.html().length - 3))
}
function isCommented(element) {
return element.html().substring(0, 4) == '<!--';
}
Example: https://jsfiddle.net/ConsoleTVs/r6bm5nhz/
For wrapping?
function wrap(jQueryElement){
jQueryElement.before("<!--").after("-->");
}
Not sure how successful you'd be finding the comments once wrapped though. A text search on the body element using regular expressions is an option.
Or this - is it possible to remove an html comment from dom using jquery

Hide all 'a' elements with text or innerHTML that matches the number '0' or a custom value using javascript or jQuery

I need to Hide all <a> elements with text or innerHTML that matches the number 'foo' or a custom value using javascript or jQuery.
<li>foo</li>
I have tried
jQuery(document).ready(function() {
if (jquery().text().html("foo"){
('li >a').fadeOut()
}
});
$('a:contains(foo)').hide();
Done.
Or:
var customValue = "foo"
$('a').filter(function(){
return this.innerHTML === customValue;
}).fadeOut();
With the later option you custom it a lot more, like:
var customValue = "foo"
$('a').filter(function(){
return this.innerHTML === customValue &&
$(this).closest('div').length;
}).fadeOut();
One approach, assuming the text you're searching for is exactly the string you use, shamelessly stealing from paying homage to Jonathan Sampson:
Creating the :exactly selector:
$.extend($.expr[":"], {
exactly: function( element, index, details, collection ){
return $(element).text() === details[3];
}
});
Used like so:
$('a:exactly("foo")').fadeOut();
References:
Jonathan Sampson:
The blog entry for :exactly() selector: http://sampsonblog.com/279/creating-your-own-custom-jquery-filters
The Stack Overflow question that prompted the creation of :exactly(): Is there any selector to do a perfect match against text?

How to select consecutive elements that match a filter

Given this example:
<img class="a" />
<img />
<img class="a" />
<img class="a" id="active" />
<img class="a" />
<img class="a" />
<img />
<img class="a" />
(I've just used img tags as an example, that's not what it is in my code)
Using jQuery, how would you select the img tags with class "a" that are adjacent to #active (the middle four, in this example)?
You could do it fairly easily by looping over all the following and preceding elements, stopping when the filter condition fails, but I was wondering if jQuery could it natively?
Here's what I came up with in the end.
// here's our active element.
var $active = $('#active');
// here is the filter we'll be testing against.
var filter = "img.a";
// $all will be the final jQuery object with all the consecutively matched elements.
// start it out by populating it with the current object.
var $all = $active;
for ($curr = $active.prev(filter); $curr.length > 0; $curr = $curr.prev(filter)) {
$all = $all.add($curr);
}
for ($curr = $td.next(filter); $curr.length > 0; $curr = $curr.next(filter)) {
$all = $all.add($curr);
}
For a follow up question, I could see how this could easily be generalised by making it into a function which takes two arguments: an initial element, and a filter string - can anyone point me in the right direction to find out how to extend the jQuery object to add such a function?
Edit: I've since found that the each() function would do this rather well for some purposes. In my own case it doesn't work as cleanly, since I want a single jQuery object for all those elements, but here's how you could use each for a different purpose (hiding consecutive ".a" elements, in this example:)
$('#active')
.nextAll()
.each(hideConsecutive)
.end()
.prevAll()
.each(hideConsecutive)
;
function hideConsecutive(index, element) {
var $e = $(element);
if (!$e.is(".a")) {
return false; // this stops the each function.
} else {
$e.hide('slow');
}
}
--
Edit: I've put this together into a plugin now. Take a look at http://plugins.jquery.com/project/Adjacent if you're interested.
I believe looping is your best bet. But you could try, each active, and then move before and after until the condition breaks, which if the set is large enough would be faster.
The below code will add two new functions, nextConsecutive() and prevConsecutive(). They should do what you want.
$.each( ['prev', 'next'], function(unusedIndex, name) {
$.fn[ name + 'Consecutive' ] = function(matchExpr) {
var $all =
(name == 'prev')
? $(this).prevAll()
: $(this).nextAll();
if (!matchExpr)
return $all;
var $notMatch = $($all).not(matchExpr).filter(':first');
if ($all.index($notMatch) != -1)
return $allConsecutive = $all.slice(0, $all.index($notMatch));
return $all;
};
});
The tilde (~) is the siblings selector:
$('#active ~ img.a').hide();
#Prestaul
$('#active ~ img.a')
would only select the following siblings, and would include the non-consecutive siblings too. Docs: http://docs.jquery.com/Selectors/siblings#prevsiblings
This is another way to do it, though the sibling selector answer is pretty cool:
var next = $('#active').next('.a');
var prev = $('#active').prev('.a');
Edit: I re-read your requirements and this isn't quite what you want. You could use nextAll and prevAll, but those, too, would not stop at the IMGs without the class name.

Categories

Resources