javascript: html5 getting and setting data-* - javascript

I've used
var activeFilter = $('<li></li>').data('input-id', 'mycustomId');
$('#container').append(activeFilter);
Now I need to get the particular < li > element out of multiple < li > elements in known < ul >.
However the obvious selector doesn't work.
var existing = $('li[data-input-id=mycustomId]');
alert(existing.length);
Useful links:
.prop() vs .attr()
How to get, set and select elements with data attributes?
Summary:
.prop() sets/gets DOM properties.. e.g. className
.attr() sets/gets TAG ATTRIBUTES.. e.g. class, thus making selectors $('obj[class=xxx]') possible.
.data() sets/gets jQuery internal Cache attributes and doesn't map onto attributes or properties.
HOWEVER, in html5 ATTRIBUTES set with .attr() and containing prefix "data-" are being correctly accessible with .data(), BUT NOT VICE VERSA!!
http://jsfiddle.net/wjEvM/
In debugger there is NO property data-input-id listed, but it's accessible through
$('#container li:firstchild').data('input-id');
The question is how do I get (which selector do I have to use) the li (object i.e.) with given value of dataset, like obj.getChildWithData('data-id', 'mycustomId');
OTHER THAN in a loop checking each li's dataset. Or using stupid document.querySelectorAll, because it doesn't do what is needed.
Please explain if applicable if it supposed to work so. Getting data-* attributes set as attributes doesn't allow me to use .data() which is recommended by html5. So I want go get it right.

You are using attribute selector here, this works if you set your HTML5 data as this:
activeFilter.attr('data-input-id', 'mycustomId');
But, you should acces it using correct synthax:
$('#container li:firstchild').data('inputId');
And to answer to your comment, you can retrieve it using .filter():
var existing = $('li').filter(function(){return $(this).data('inputId') === "mycustomId"});
SEE DEMO

Unfortunately for your method, jQuery does not store data set via .data() in the DOM node's data attribute (see this question).
Instead, you'll want to set it with .attr(), and then you can use $('li[data-input-id=mycustomId]'):
$('<li></li>').attr('data-input-id', 'mycustomId');

Related

Get CSS selector of all matching items in jQuery

I want to get CSS selector of jQuery items set.
By jQuery items set in this case I mean jQuery set created basing on some css selector and extended by some jQuery functions like .children etc like $(".basic-selector").children();
It's easy to get for simple scenario like direct selection:
$("div.someclaass").selector //works ok - gives div.someclass
But I also need to get css selector for more complex scenarios (and here jQuery is not returning valid css selector)
$("div.someclass").children("p").selector //schould give div.someclass > p
And for more comples scenarios like
$("ul, ol").children("li").selector //should give ul > li, ol >li
Is it possible?
Requirements:
It must be valid css selector
I cant change js code of creating sets
It should work for all this kind of jQuery functions that can have
css selector - like children, find, next, nextAll, .filter (with css param) etc.
There are some functions like .prev or .parent that will not have css selector - I'm aware of that.
Why do I need that? - I've got my plugin. It takes some jQuery set that was created basing on selector and executes some function on those items. But also - function needs to be executed in the future on new items added later that would match the set if they would exisit in the time of set creation code execution. For good understanding please check plugin page.
The .selector property is deprecated and can only be used when the jQuery element set was created by passing a selector string directly. As you have seen, .selector stops representing a valid selector altogether once you start chaining traversal or filtering methods from the original set. Judging from the sort of values that .selector can have it would seem that it was simply not intended for anything other than internal use.
But the real problem here is that not all element sets can be represented with a valid CSS selector (not without enumerating all possible :nth-child() permutations anyway), not the least of which is because many of jQuery's non-standard selectors have no standard equivalents. Even if you limit yourself to standard selectors and traversal methods that can be represented with a selector, if the original element set was obtained through some other means, or if it was obtained normally and then tampered with, you won't be able to detect this, not even using .selector which as I mentioned is deprecated anyway.
If you really need a selector string to match your selection, the easiest way is to just write it manually and store it in a separate variable.

Using HTML5 Data Attribute in jQuery Selector

Noob Question on Data Attribute
I was wondering will using data-attribute in jQuery Selector can bring any trouble in the future?
I'm trying to reduced the usage of .class and #id as jQuery Selector, since most of data I'm working on will generated from data-attribute
example of the code
$(document).ready(function(){
var mydata = $(document).data('my-data-attribute');
});
will the code above slowing the load time?
or
$('[data-suffix-attribute="some_value"]').each(function(){
......
});
or
$('[data-suffix-attribute="delete"]').click(function(){
// delete action happening here
});
will this bring trouble?
$(document).ready(function(){
var mydata = $(document).data('my-data-attribute');
});
The code above will not work. If you want to read the HTML5 data attribute of an element using the jQuery .data() method firstly you need to select the relevant element using a jQuery selector and then you can use the method as is shown below:
var mydata = $('.example').data('suffix');
This will read the value of the data-suffix attribute of an element with a class of "example".
The other important thing to note when using the .data() method is that you have to omit the data- prefix from the selector to read the value stored in that attribute.
The way you have selected the attribute before the .each() method will work:
$('[data-suffix-attribute="some_value"]');
However, it would be better if you can narrow it down to a specific element like:
$('div[data-suffix-attribute="some_value"]');
This is because the first selector will go through every node in the document which will take more time whereas the second will only go through the div tags in the document.
The attribute selector is supported by the native query selectors so it is fine. As far as future is concerned I don't think in near future it will be a problem.
But it will be better if you can use a element selector attached to the attribute selector like $('div[data-suffix-attribute="delete"]')
If you are very worried about performance it will be a better choice to add a class attribute to the desired elements and then use class selector
It would be better to use id in selector which is fast obviously,
If you have multiple data attributes then it is better to use $('[data-suffix-attribute="delete"]').click();.
Instead of this you can use the parent selector for your data-attribute elements like,
$('#parentId').on('click','[data-suffix-attribute="delete"]',function(){
// delete action happening here
});
#parentId contains all data attribute elements

Alternative to (deprecated) value attribute for li elements

I'm currently working on a web application using HTML 5, CSS and JQuery. I have an unordered list (ul) for displaying page links, with each li element containing the page link. This list is created dynamically using jQuery.
What I would like to do is to have the list elements display only the page name in the link, but at the same time retain the full link path. For example, "http://www.foo.com/xyz/contactus" would be displayed as "contactus", but the li element would still "know" the full link path. For this purpose the value attribute of li would have been perfect, since i could set them like this:
var ul = $('<ul/>').attr('id', 'linkList');
for (var i = 0; i < linksOnPage.length; i++) // linksOnPage is an array with all the links
{
var pgName = linksOnPage[i].toString().slice(steps[i].toString().lastIndexOf('/') + 1);
// Create list element and append content
var li = $('<li/>').text(pgName); // Set the text to the page name
li.attr('value', linksOnPage[i].toString()); // Set the value to the full link
ul.append(li);
}
This would create a list like:
<ul>
<li value="http://www.foo.com/xyz/contactus">contactus</li>
...
</ul>
Unfortunately the value attribute of li has been deprecated since HTML 4.01 (anyone know the rationale behind this? Seems pretty useful to me...).
So, I would like some advice on how to proceed. One option is to ignore the deprecation and use the value attribute anyway, since all the major browsers still support it, but I'm not very keen on using a deprecated feature and it just feels wrong.
Any ideas?
Change from:
<li value="http://www.foo.com/xyz/contactus">contactus</li>
To:
<li data-value="http://www.foo.com/xyz/contactus">contactus</li>
data-* pattern is the new HTML5 way of keeping values in DOM elements.
You can get the values in one of the two ways:
$('#li-Id').data('value');
$('#li-Id').attr('data-value');
You can read this blog post of John Resig on those attributes.
jQuery data function
Simply use a data attribute (intro; longer tutorial; spec):
<li data-path="http://www.foo.com/xyz/contactus">contactus</li>
As a plus, jQuery conveniently detects and exposes the values of such attributes through the .data method.
Even though value was deprecated, it could still be used and accessed w/JavaScript. You're only giving up validation status!
Alternatively you could either use data-* attributes (as I see others have suggested) or map values directly to DOM elements - since you're generating this markup at runtime you could just add a property like so (JS allowing you to do this is both a blessing and a curse):
li.someLinkPath = 'some url here';
//and in the click handler you could access this as
this.someLinkPath;
Still... if you're intending to use this for navigation, why not just use an anchor with an href?

Add some properties to a <div> element

I want to add some properties to a <div> element. All of the below works except for the .data(). I cannot see it appear in Firefox/Firebug.
$('#menu-container')
.css('background-image','url("'+big_image+'")')
.addClass('click_2')
.data("new_link", "new_link.html")
.css('z-index',"99");
Am I doing it wrong?
data is not just any ordinary attribute you can add, it is a way to attach objects and data to DOM elements. You can't see it in the HTML source or in Firebug, but you can query it using .data()
The data itself is not stored on the element. It's actually stored in $.cache
.data() is working but it won't show up as an element's attribute.
If you wanted to see it working you can try console.log($('#menu-container').data('new-link'));
If attributes are what you want then you can do .attr('new-link','new-link.html')
Use
$('#menu-container').attr('data-new_link','new_link.html');
it will appear in firebug, and you can also use the expected jQuery behavior
$('#menu-container').data('new_link');
to retrieve the value stored..
But there is really no need to do it this way. It gets stored at the .data() collection, regardless of being added as an attribute to the DOM element..

Using jQuery to delete all elements with a given id

I have a form with several spans with id="myid". I'd like to be able to remove all elements with this id from the DOM, and I think jQuery is the best way to do it. I figured out how to use the $.remove() method to remove one instance of this id, by simply doing:
$('#myid').remove()
but of course that only removes the first instance of myid. How do I iterate over ALL instances of myid and remove them all? I thought the jQuery $.each() method might be the way, but I can't figure out the syntax to iterate over all instances of myid and remove them all.
If there's a clean way to do this with regular JS (not using jQuery) I'm open to that too. Maybe the problem is that id's are supposed to be unique (i.e. you're not supposed to have multiple elements with id="myid")?
.remove() should remove all of them. I think the problem is that you're using an ID. There's only supposed to be one HTML element with a particular ID on the page, so jQuery is optimizing and not searching for them all. Use a class instead.
All your elements should have a unique IDs, so there should not be more than one element with #myid
An "id" is a unique identifier. Each time this attribute is used in a document it must have a different value. If you are using this attribute as a hook for style sheets it may be more appropriate to use classes (which group elements) than id (which are used to identify exactly one element).
Neverthless, try this:
$("span[id=myid]").remove();
id of DOM element shout be unique. Use class instead (<span class='myclass'>).
To remove all span with this class:
$('.myclass').remove()
if you want to remove all elements with matching ID parts, for example:
<span id='myID_123'>
<span id='myID_456'>
<span id='myID_789'>
try this:
$("span[id*=myID]").remove();
don't forget the '*' - this will remove them all at once - cheers
Working Demo
The cleanest way to do it is by using html5 selectors api, specifically querySelectorAll().
var contentToRemove = document.querySelectorAll("#myid");
$(contentToRemove).remove();
The querySelectorAll() function returns an array of dom elements matching a specific id. Once you have assigned the returned array to a var, then you can pass it as an argument to jquery remove().
You should be using a class for multiple elements as an id is meant to be only a single element. To answer your question on the .each() syntax though, this is what it would look like:
$('#myID').each(function() {
$(this).remove();
});
Official jQuery documentation here.
As already said, only one element can have a specific ID. Use classes instead. Here is jQuery-free version to remove the nodes:
var form = document.getElementById('your-form-id');
var spans = form.getElementsByTagName('span');
for(var i = spans.length; i--;) {
var span = spans[i];
if(span.className.match(/\btheclass\b/)) {
span.parentNode.removeChild(span);
}
}
getElementsByTagName is the most cross-browser-compatible method that can be used here. getElementsByClassName would be much better, but is not supported by Internet Explorer <= IE 8.
Working Demo

Categories