jQuery data attr not setting - javascript

This appears very simple but I cannot see why it's not working. The selector is correct however the div .faqContent is simply not being updated with the data-height attribute.
$('.faqItem .faqContent').each(function(){
var h = $(this).height();
$(this).data('height',h);
});
I have checked that var h is correct, it is in colsole.log as correctly holding the height.
EDIT
It's absolutely not conflict, and console shows no errors.

The data function confuses a lot of people, it's not just you. :-)
data manages jQuery's internal data object for the element, not data-* attributes. data only uses data-* attributes to set initial values, and more, it guesses at what type you want those to be based on what they look like (so something that looks like a number is converted to a number; something that looks like JSON gets converted to an object). The data method never sets data-* attributes on elements, it only sets the data on its internal data object. That means the two (the internal data object and the attribute) get out of sync:
const t = $("#target");
let value;
// Getting the attribute always gets a string
value = t.attr("data-height");
console.log(`${value} (${typeof value})`); // 1 (string)
// Using `.data`, jQuery will guess that because the attribute looks like a number,
// you want it converted to a number
value = t.data("height");
console.log(`${value} (${typeof value})`); // 1 (number)
// `data` only sets the internal data object properties, not the attribute...
t.data("height", 2);
// ...so the attribute still has `"1"`
value = t.attr("data-height");
console.log(`${value} (${typeof value})`); // 1 (string)
// ...even though the data object has 2
value = t.data("height");
console.log(`${value} (${typeof value})`); // 2 (number)
<div id="target" data-height="1"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
If you want to actually set a data-* attribute, use attr:
$(this).attr("data-height", h);
const t = $("#target");
let value;
value = t.attr("data-height");
console.log(`${value} (${typeof value})`); // 1 (string)
// `attr` converts whatever you give it to string
t.attr("data-height", 2);
value = t.attr("data-height");
console.log(`${value} (${typeof value})`); // 2 (string)
<div id="target" data-height="1"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
But if you only want this information for future use, data is fine (assuming you're okay with its automatic type conversion), just don't expect to see it in the DOM inspector, because jQuery doesn't write this information to the DOM.

You will not be able to see it in the element inspector but it is there as jquery set the data attribute internally.
try console.log($(this).data('height'));

.data() is only stores the associated new value in memory(or internally). It'll not change the attribute in the DOM hence you cannot see it updated using inspector tools.
To change the attribute, you can use .attr():
$('.faqItem .faqContent').each(function(){
var h = $(this).height();
$(this).attr('data-height',h);
});

JQuery .data() stores the value on the element itself, it won't add an attribute.
http://api.jquery.com/data/
If you want to add an attribute, use attr:
$('.faqItem .faqContent').each(function(){
var h = $(this).height();
$(this).attr('data-height', h);
});
http://api.jquery.com/attr/

Related

Why element.setAttribute('checked', true) doesn't work?

I want to do something like this:
elementX.setAttribute('checked', true); // this is input type checkbox
elementY.appendChild(elementX);
It is everything ok with rendering and other things but on the page, the input is not checked.
When I look at elements in chrome console I can see:
<input type="checkbox" checked="true">
What should I do?
I've already tried
elementX.setAttribute('checked', true);
elementX.setAttribute('checked', 'true');
elementX.setAttribute('checked', 'checked');
I don't have any errors in the console.
See MDN:
checked
A Boolean attribute indicating whether or not this checkbox is checked by default (when the page loads). It does not indicate whether this checkbox is currently checked: if the checkbox’s state is changed, this content attribute does not reflect the change. (Only the HTMLInputElement’s checked IDL attribute is updated.).
While setting the checked attribute will show a change in the serialization of the element, it won't actually check the checkbox. For that, you have to invoke the setter, eg
elementX.checked = true;
Firstly, #CertainPerformance answer is the one that I upvoted, and it's correct!
I simply wanted to shed more light on the nuances of IDL( Interface Design Language ) attributes versus content attributes and what it means for them to be reflective or not.
In this case an IDL attribute is a JavaScript Property on a DOM representation of an Element. Not just any property, but one that was predefined within the W3 Specification. IDL Examples
Attributes specified in your HTML are considered content attributes. These attributes are used to populate IDL attributes on DOM Nodes during the rendering process. content attributes are accessible from the DOM Node through a few ways including the getAttribute method, but they are not stored on it as IDL attributes are. In simple terms element.getAttribute("checked") and element.checked are actually looking in two completely different objects for the key checked.
So what's it mean to be reflective?
A DOM Node's property and its HTML attribute are interchangeable from the point of rendering if the node is not altered - but also if specific attributes are changed.
Altering id and class in any way, whether directly on the DOM Node or within the Attribute object using the element.setAttribute method, will result in both values being changed.
id and class are reflective IDL attributes because they, in effect, watch their content attributes for changes and vice versa.
Alternatively checked and value IDL attributes are not reflective. When the value or checked properties are altered on either the DOM Node or the Attribute Object, it does not alter the corresponding attributes of the other.
Outside of those properties( there are more than id and class - though there's no real list of reflective vs not reflective - I would presume it's any property related to the identity of the Node in the DOM that would cause a re-render ) the content attributes and DOM Node properties are not bound together. This makes using getAttribute and setAttribute useless if the intent is to update or get current data, because the current data is only found within the DOM Node properties.
The examples below illustrate the difference:
ID change example: Both Attribute and Property Reflect Each Other
let i = document.querySelector("input");
i.addEventListener("id_change", function() {
let HTML_Attribute = i.getAttribute("id"),
DOM_Node_Property = i.id;
console.log("HTML Attribute 'value': " + HTML_Attribute +
"\n DOM Node Property 'value': " + DOM_Node_Property);
})
let n = 1;
let timer = setInterval(function() {
if(n > 2) clearInterval(timer);
i.setAttribute("id", "newId_" + String.fromCharCode(Math.floor(Math.random() * 26) + 65));
i.dispatchEvent(new CustomEvent("id_change"));
n++;
}, 1000);
<input value="Hello World"/>
Value change example: Attribute and Property Are Different
let i = document.querySelector("input");
i.addEventListener("input", function() {
let HTML_Attribute = i.getAttribute("value"),
DOM_Node_Property = i.value;
console.log("HTML Attribute 'value': " + HTML_Attribute +
"\n DOM Node Property 'value': " + DOM_Node_Property);
})
<input value="Hello World"/> <em><small>Type into the Box</small></em>

How to get value of nested attributes of element

When i did the "inspect Element" the HTML code i got is,
<domain-picker class="pull-right"
current="{"label":"AMN/GRP","value":"assf2324234"}" in-header="true" show-in-header="true">
</domain-picker>
Could anyone please let me know in jquery
how to get the value "assf2324234" of the above "domain-picker" element.
how to set with new string for the "value" attribute of the above "domain-picker" element
Following is commented to show steps
// target element
var $picker = $('domain-picker'),
// parse current attribute value string to object
current= JSON.parse( $picker.attr('current'));
// change value
current.value ='someOtherString';
// stringify object and put back as attribute value
$picker.attr('current', JSON.stringify(current));
Modify your HTML, Use single quotes for current attribute
<domain-picker class="pull-right"
current='{"label":"AMN/GRP","value":"assf2324234"}' in-header="true" show-in-header="true">
</domain-picker>
in jQuery
var json = $("domain-picker").attr("current");
json = JSON.parse(json)
var value = json.value;
Here is working demo https://jsfiddle.net/758y0fp1/1/
As #charlietfl mentioned, if you wanna use jQuery, his answer is the 1 you need, this can be done with pure Javascript too, ie.
// getting the element
var picker = document.getElementsByTagName('domain-picker')[0];
// parsing current attribute string to object
var current= JSON.parse(picker.getAttribute('current'));
// changing the value
current.value ='newString';
// stringify the object and set the attribute again like
picker.setAttribute('current', JSON.stringify(current));
You need to first get the value of attribute .attr() in jquery or getAttribute() in javascript will help. Now since the value is an invalid JSON(as per the html provided by you), convert the invalid JSON to valid and then select the value.
var obj = document.querySelector("domain-picker").getAttribute("current");
var json = obj.replace((/'/g), "\"");
var obj = JSON.parse(json)
//console log the retrieved value.
console.log("value :", obj["value"])
// set attribute now
obj["value"] = "1234567";
document.querySelector("domain-picker").setAttribute('current', JSON.stringify(obj));
<domain-picker class="pull-right"
current="{'label':'AMN/GRP','value':'assf2324234'}" in-header="true" show-in-header="true">
Hello inpsect me to see the changed attribute value.
</domain-picker>

Getting attribute of a path

I am trying to access the d attribute of a path created in Javascript. The result of printing the path element is:
path class=​"coastline"
d="M641.2565741281438,207.45837080935186L640.7046722156485,207.0278378856494L640.6985715873882,207.1279196729914L640.8663103175278,207.53837609537672L640.8542041922302,207.73856415298116L641.04637606029"
... with a longer path. I can access the class attribute by using the getAttribute method on class. However, when I try to access the d attribute, it gives me null. Is there something else I should be doing?
edit: here is how I am currently attempting to access the d attribute (I specifically want the coastline):
var path = d3.geo.path().projection(globe.projection).pointRadius(7);
var coastline = d3.select(".coastline");
console.log(coastline[0][0]);
console.log(coastline[0][0].getAttribute('class'));
console.log(coastline[0][0].getAttribute('d'));
The d attribute of the SVGPathElement "is a string which contains a series of path descriptions."
You can get it and set it through the getAttribute()/setAttribute() methods.
Once interpreted by the browser, the Path Object will contain an SVGPathSegListcreated from this string. This SVGPathSegList will itself contain different PathSegXTo objects.
You can access this list and modify each of the Path Segments by getting the pathSegList property of your path object, which is an ArrayLike Object, but the original string is only accessible through the getAttribute method.
var p = document.createElementNS('http://www.w3.org/2000/svg', 'path');
p.setAttribute('class', 'coastline');
svg.appendChild(p);
// set the attribute
p.setAttribute('d', 'M50,25L60,105L65,65');
// move the third point on x axis after 1 second
setTimeout(function() {
p.pathSegList[2].x += 50;
var coastline = d3.select(".coastline");
// get the attribute with DOM method
snippet.log('from getAttribute : ' + coastline[0][0].getAttribute('d'));
// get it from d3 method
snippet.log('from d3.attr() : ' + coastline.attr('d'));
}, 1000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<svg id="svg"></svg>
Sorry! I want to not express my opinion clearly, check the following code directly
var p = document.getElementById('test');
// general attribute | property, bi-directional
console.log(p.id);// test
console.log(p.getAttribute('id'));// test
// custom attribute, <p class='m-test' id='test' data='data'></p> and p.setAttribute('data', 'data'); one-way, only object.getAttribute() works
console.log(p.data);// undefined
console.log(p.getAttribute('data'))// data
// custom property; one-way ,only object.propery works
p.proData = 'property';
console.log(p.proData);// property
console.log(p.getAttribute('proData'));// null
<p class='m-test' id='test' data='data'>
this is a prograph
<p/>
you can set the 'd' attribute by using setAttribute method, only by getAttribute() method you get value the 'd' attribute.

Add an attribute on focus

What is the best way to add an attribute to an <input /> on focus using js / jQuery?
Right now, off the top of my head, I would think
$(document).ready(function(){
$('input').focus(function(){
$(this).attr(attributeHere);
});
});
Is that correct? Does the attribute have to have quotes around it?
Right now, it is just going to be an attribute with no value. Value will be added later.
This is what you can do :
$(document).ready(function(){
$('input').on("focus",function() {
$(this).attr('name', 'value'); // value could be '' if you would like to specify it later.
});
});
I hope it helps.
Looks fine to me. Only one thing I would add is that even if you want to leave the attribute empty, you should give it an empty string as a value.
var attrName = 'someAttr';
$(this).attr(attrName,'');
By not passing a value (even an empty string), you are actually calling the getter function for the attribute where you really want to be calling the setter.
You need to do this -
$(this).attr('attributeName','attributeValue');
What you are trying .attr(attributeName) is used to access attribute value
Description: Get the value of an attribute for the first element in
the set of matched elements.
See the api :
http://api.jquery.com/attr/
.attr( attributeName, value )
attributeName
Type: String <-- Either a var containing string or an "string"
The name of the attribute to set.
value
Type: String or Number
A value to set for the attribute.

Does the data("key", value) method set data- attributes?

Will the jQuery $("..").data("key", value) method set the data-key attribute if one is present?
Adam Freeman's Pro jQuery states that it does:
Tip The data method takes the data attributes into account when
setting values as well. When you specify a key, such a [sic] product, the
data method checks to see whether there is a corresponding HTML5 data
attribute, such as data-product. If there is, then the value you
specified is assigned to the attribute. If not, then the data is
stored internally by jQuery.
But I thought that it didn't, and the test that I ran implies that it doesn't. (I checked the errata section—nothing)
Full code is below, but the short of it is that when I set the data-name attribute by calling the attr method, the attribute value changes and can be seen in the chrome elements tab, and retrieved into newValue. When I set it with the data method, neither of these conditions are satisfied; it seems as though using data() always sets the value internally and never on the attribute, even if one is present.
Unfortunately, the docs' only mention of html5 data-attributes is in the section of the data method that takes only a key, and returns the concomitant value; the description of data("key", value) doesn't seem to mention html5 data-attributes at all.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.js"></script>
<script type="text/javascript">
$(function () {
var oldValue = $("#d").data("name");
alert("old value " + oldValue);
$("#d").data("name", "Adam");
//$("#d").attr("data-name", "Adam");
var newValue = $("#d").attr("data-name");
alert("new value " + newValue);
});
</script>
</head>
<body>
<div id="d" data-name="none"></div>
</body>
</html>
I think that Adam Freeman's description is incorrect, or at least not completely accurate.
According to the jQuery documentation:
As of jQuery 1.4.3 HTML 5 data- attributes will be automatically
pulled in to jQuery's data object.
This implies that jQuery pulls these attributes into its own internal representation, rather than overriding the values in the actual attributes.
A quick perusal of the code suggests the same.
According to jQuery's .data() method documentation:
Note that this method currently does not provide cross-platform
support for setting data on XML documents, as Internet Explorer does
not allow data to be attached via expando properties.
It seems it uses the data= if it's there and doesn't throw an error.
Take a look for yourself:
function dataAttr( elem, key, data ) {
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
if ( data === undefined && elem.nodeType === 1 ) {
var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
data = elem.getAttribute( name );
if ( typeof data === "string" ) {
try {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
jQuery.isNumeric( data ) ? +data :
rbrace.test( data ) ? jQuery.parseJSON( data ) :
data;
} catch( e ) {}
// Make sure we set the data so it isn't changed later
jQuery.data( elem, key, data );
} else {
data = undefined;
}
}
return data;
}
jQuery's .data() function doesn't interact with the HTML5 data-* attributes at all, other than taking the initial values from them; I'm not entirely sure when this is done, though - another answer suggests it's done at the first call to .data(), which may be correct (it definitely makes sense).
Using .attr() to specify a new value for a data-* attribute doesn't modify the value that jQuery has stored to access using .data(). To illustrate, take a look at this jsFiddle. If you inspect the <div> element and then click on the button, you can see that whilst the attribute on the element has its value changed the two console.log() calls output the same value.

Categories