Store data on element before appending - javascript

I want to store JSON on an html element using jquery data(). However my elements are actually an html string and are not yet in the DOM like so.
$(".test").each(function() {
el += "<span>"+ 25 +"</span>";
});
$("body").append(el);
I have tried this (within each function)
el += $("<span>"+ 25 +"</span>").data("test", {"name":"john"});
But when I append el, I get [object][object] appended instead
How can I associate the data with the element and be able to retrieve it after its appended?
FIDDLE: https://jsfiddle.net/6mhgwtk1/1/

You did it right, but it's an object. When you print or alert an object it will always appear as [Object]. Instead of printing the object print it's properties instead, like this: el.data("test").name.
see: https://jsfiddle.net/6mhgwtk1/
Based on your example code, I've updated your fiddle with working code. See the comments for the explanation.. https://jsfiddle.net/6mhgwtk1/3/
var el;
$("div").each(function() {
// el is not a string here, (it's a jQuery object) so you can't concatentate it using +=
// instead you will have to append each one to the body separately
el = $("<span>"+ 25 +"</span>").data("test", {"name":"john"});
$("body").append(el);
});
$("body").find("span").each(function(){
var data = $(this).data("test");
console.log(data);
});

For retrieving, Try getting attributes of el (since it is an object).

Related

How to get updated DOM element javascript

I am trying the fetch dynamic DOM elements from javascript and as per the current development, I can successfully fetch the updated DOM HTMLCollection array object. But when I try to print the innerHTML it gives previous DOM value. Below the console output which I am facing right now:
Console output for HTMLcollection: Highlighted part, that I want to fetch:
But when I try to get innerHTML for that element, I am getting the previous innerHTML instead I want to print current DOM innerHTML. Below is the screenshot of the output:
as we can see both screenshots of the same DOM element, gives different output. and this is javascript code I am trying fetch innerHTML:
var $wrap = document.getElementsByClassName('single_variation_wrap')[0];
var $deposit_amount = document.getElementById('deposit-amount');
var $display_amount = document.getElementsByClassName('woocommerce-variation single_variation');
$display_amount = $display_amount[0];
var $final_display_amount = document.getElementsByClassName('woocommerce-variation-price');
console.log($deposit_amount, $final_display_amount);
for(var i=0; i<$final_display_amount[0].childNodes.length;i++){
console.log($final_display_amount[0].childNodes[i].innerHTML);
}
Please suggest, where am I doing things wrong?

Deleting an element from JSON in javascript/jquery

I have a problem in deleting data from a JSON object in javascript. I'm creating this JSON dynamically and the removal shall also take place dynamically. Below is my JSON and the situation I'm in to.
{brands:[51,2046,53,67,64]}
Now, I have to remove 53 from this which I am calculating using some elements property, but I'm not able to remove the data and unable to find the solution for this situation. Please help me folks, thank you.
Try to use Array.prototyp.splice,
var data = { brands:[51,2046,53,67,64] };
data.brands.splice(2,1);
Since you want to remove an element from an array inside of a simple object. And splice will return an array of removed elements.
If you do not know the position of the element going to be removed, then use .indexOf() to find the index of the dynamic element,
var elementTobeRemoved = 53;
var data = { brands:[51,2046,53,67,64] };
var target = data.brands;
target.splice(target.indexOf(elementTobeRemoved),1);
You could write the same thing as a function like below,
function removeItem(arr,element){
return arr.splice(arr.indexOf(element),1);
}
var data = { brands:[51,2046,53,67,64] };
var removed = removeItem(data.brands,53);

How can I save changes to the context in a jQuery each loop?

I have the following code, which preprocesses some response data from an AJAX call before displaying it (the displaying part is not shown). In particular, it sets the src attribute of the image in each li element of the response.
$(response.items).filter('li').each(function(i){
$('img', this).attr('src', 'images/Picture.jpg');
if (i==0){
console.log(this);
console.log(response.items);
}
});
The output of console.log(this) shows that the src attribute gets set correctly in the context represented by this, but the output of console.log(response.items) shows that response.items is unchanged.
Is there a (preferably non-hacky) way to persist all changes to the li elements to response.items?
I think the problem here is that you're using the filter method. Filter (and also map) don't modify the original array, they essentially make a copy of it. So if you would check the return value of this whole code block like this:
var processed = $(response.items).filter('li').each(function(i){
$('img', this).attr('src', 'images/Picture.jpg');
if (i==0){
console.log(this);
}
});
console.log(processed);
It should properly show the changed values. Depending on what you want to do you could also use a map method after the each.

Javascript: assign onclick inside class

I created a constructor that will handle a custom list control. I created a method in order to allow the user to add elements to the list, and I need to assign event handlers to the click events of the list elements (divs).
A simplified version of the code is here. The list elements are created using the innerHTML property and a string template upon which I substitute specific parts. Later I get the element by it's id and assign it a function in closure:
function prueba(){
var plantilla = '<div id="«id»">«texto»</div>';
var f = function(nombre){
return function(){console.log('mi nombre es ' + nombre)};
};
this.agregar = function(id, texto){
var tmp = plantilla.replace('«id»', id);
tmp = tmp.replace('«texto»', texto);
document.body.innerHTML += tmp;
document.getElementById(id).onclick = f(id);
};
};
The problem is that, apparently, the event handler is unasigned to previous created divs, so is only retained by the last one, as it can be tested with the following code:
var p = new prueba;
p.agregar('i1', 'texto1');
console.log(document.getElementById('i1').onclick.toString());//shows the function code
p.agregar('i2', 'texto2');
console.log(document.getElementById('i2').onclick.toString());//shows the function code
console.log(document.getElementById('i1').onclick.toString());//returns 'null' error
p.agregar('i3', 'texto3');
console.log(document.getElementById('i3').onclick.toString());//shows the function code
console.log(document.getElementById('i2').onclick.toString());//returns 'null' error
This happens in Iceweasel as well as in Chromium. It does NOT happen when I add 'onclick = f(«id»)' in the template (which I cannot do here because of the assigned function scope), and neither happens if I use document.createElement. What am I doing wrong?
You destroy elements previously created when you do this:
document.body.innerHTML += tmp;
Instead use insertAdjacentHMTL() if you want to append using HTML markup.
document.body.insertAdjacentHTML("beforeend", tmp);
Now instead of going through this destructive process...
serialize the existing DOM nodes to HTML
concatenate the new HTML fragment to the serialized nodes
destroy the old nodes
recreate the nodes with the new nodes
...it simply creates the new content and places it before the close of the body element.
Basically, remove element.innerHTML += ... from your coding practices. It's never necessary, it's inefficient and it causes problems like what you've described.
FYI, the .insertAdjacentHTML() method receives 4 different string possibilities as the first argument. Each one designates a position relative to the element on which you're calling it.
The strings are...
"beforebegin"
"afterbegin"
"beforeend"
"afterend"
The labels are pretty self-explanatory. They position the new content before the current element, inside the current element at the beginning, inside the current element at the end, or after the current element, respectively.
Your full code will look like this, which I shortened a bit too since the tmp really isn't needed here:
function prueba(){
var plantilla = '<div id="«id»">«texto»</div>';
var f = function(nombre){
return function(){console.log('mi nombre es ' + nombre)};
};
this.agregar = function(id, texto){
document.body.insertAdjacentHTML("beforeend",
plantilla.replace('«id»', id)
.replace('«texto»', texto));
document.getElementById(id).onclick = f(id);
};
};

Adding custom data attribute for a new node in Jquery does not work

I tried to use the method data (jQuery 1.7.1) in this code:
var q = '<div class="form-error-marker"></div>';
var t = $(q).data('message', message).insertAfter(el);
and it does not work.
Note that this works:
var t = $(q).attr('data-message', message).insertAfter(el);
Why does the first variant not work?
EDIT: insertAfter works correctly and new div is added after el (which is instance of one element which I get by getElementById() function; long story short I have a library that I extend).
When I say 'it does not work' I mean that the attribute 'data-message' is not stored.
Using data like that sets an arbitrary piece of data for this node; it doesn't add a new data- attribute. Just add the attribute with the attr function, and then access it with data
var q = $('<div class="form-error-marker"></div>').attr("data-message", message);
Now access it like this:
var message = q.data("message");
Here's a fiddle
When you use jQuery.data you don't change element attributes, instead your data saved in $.cache.
So if you want to change element attributes use jQuery.attr, when you want to save some info use jQuery.data

Categories