Jquery .each() .click() only getting data in last element - javascript

I use the following to get the json for each member and create an element with a click listener.
$.getJSON('/api/members', function (membersJson) {
$(membersJson).each(function (i, item) {
$('#contacts').append('<div class="membercard">' + item.Name + '</div>');
.click(() => show_details(item));
})
});
function show_details(item) {
$('#memberName').val(item.Name);
$('#memberOcc').val(item.Occupation);
}
When a membercard is clicked it is meant to send its info to a more detailed div. However, when clicking on any of the dynamically created divs, only the item data from the last json in the loop is sent to the detailed view. Why is this and how can I fix it?

you are binding and iterating inside a loop, this is to avoid in general, because the scope of the function will in the click, will take only the last element of the loop
Try refactoring like this:
$('#contacts').on('click', '.membercard', function() {
show_details($(this).data('item'));
});
$.getJSON('/api/members', function (membersJson) {
$(membersJson).each(function (i, item) {
var div = $('<div class="membercard">' + item.Name + '</div>');
div.data('item', item);
$('#contacts').append(div)
})
});
function show_details(item) {
$('#memberName').val(item.Name);
$('#memberOcc').val(item.Occupation);
}

This is a common problem with JavaScript. Essentially, because the click event happens after the loop, the “item” variable is equal to the last item. To fix this, simply change:
$(“#contacts”).click(() => show_details(item));
To:
let _item = item;
$(“#contacts”).click(() => show_details(_item));
This creates a copy of the variable that will have the same value even after the loop completes.

Related

Passing data to a click listener

I have a button in my html that when clicked, I need it to pass the index attribute value to my click listener:
<button class="btn buy-button js-prevent-cart-listener guys" index="1">Add To Cart</button>
and the listener:
$('.girls').on('click', buyButtonGirlsClickHandler, index);
So that when I run this function, I can access the event value and use it within the function:
function buyButtonClickHandler(evt) {
console.log(evt.value);
}
I dont want to change it to have an 'onclick()' attached to the button. Is this possible and if so how? Obviously the code above is not able to pass the index value, and i have tried numerous times
You need not to pass the index in on function. You should try changing your on function to
$('.girls').on('click', buyButtonGirlsClickHandler);
and in the handler you can receive it by attr
function buyButtonClickHandler(evt) {
console.log(evt.value);
var index= $(event.target).attr("index");
}
https://jsfiddle.net/525npjfn/
or as #Andreas commented , use this inside click.
function buyButtonGirlsClickHandler(evt) {
console.log(evt.value);
var index = this.getAttribute("index");
alert(index);
}
https://jsfiddle.net/525npjfn/2/
On button click, you can store it's index value in a variable and then pass it into the desired function. This is the clean snippet to solve your problem.
Please use data- prefix to use custom HTML attribute otherwise HTML validators will cry for this.
$(document).ready(function() {
$('.js-prevent-cart-listener').click(function() {
var idx = $(this).attr('data-index');
buyButtonClickHandler(idx);
})
});
function buyButtonClickHandler(idx) {
console.log("This is index value " + idx);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="btn buy-button js-prevent-cart-listener guys" data-index="1">Add To Cart</button>
Instead of passing the event handler directly, wrap it inside a new function. Your index data will be passed because it stays in the scope.
let index = "whatever your index data is";
$('.girls').on('click', (e, index) => buyButtonGirlsClickHandler(e, index) );
Note: I'm using ES6 syntax there, may not work on old browsers.

Using .after but only if the value does not exist

I am running this code to insert a HTML line after the id #wp_menu:
$(document).on('closing', '.remodal', function (e) {
$('.menu_name').each(function() {
$('#wp_menu').after('<div class="tag">' + $(this).val() + '</div>');
});
});
The problem is, every time I run this loop, I'll get duplicated values and this is not what I want. How can I check if the code was inserted before?
This is a simple example that may explain my problem: https://jsfiddle.net/vLqonqpk/
So when you click on "add" multiple times, it will add the same values over and over again.
You could do something like this:
arr = [];
$('button').click(function() {
$('ul input').each(function() {
if ($.inArray($(this).val(), arr) == -1) {
$('#wp_menu').after('<div class="tag">' + $(this).val() + '</div>');
arr.push($(this).val());
}
});
console.log(arr);
});
DEMO: https://jsfiddle.net/vLqonqpk/1/
So, create array of values, check if current val(s) from inputs are duplicated, and place just unique values. Of course, you can add additional checks for empty string, and give user some alerts/warnings (create else block for that purpose), if needed, etc, etc...
But this is basic idea which should work.
Simply isolate the jQuery selector and check its existence.
$(document).on('closing', '.remodal', function (e) {
$('.menu_name').each(function() {
var $wp_menu = $('#wp_menu');
var $tag = $wp_menu.next('.tag'); // .siblings() also works
// Now you check if it exists, and create it if not
if (!$tag.length)
$tag = $('<div class="tag">').insertAfter($wp_menu);
// Simply update the content, element will always exist
$tag.text($(this).val()); // .html() also works
});
});
I'm sure there's several ways to do it, this is just one of them.
I now realize your problem is not duplicating tags, but values. Basically you want a HashSet. Please accept sinisake's answer instead

Jquery chosen update appending selections

I have looked everywhere for this, and all I am getting is stuff about dynamically appending more options.
I have a function that calls the following:
$("#" + id_name).val(result).trigger("chosen:updated");
this is called when clicking a suggested button, which then is supposed to add it to the chosen-container-multi container that has all the inputs and so on.
If I call the function again, it erases the previous result and puts the new one in that field. This container is supposed to be able to hold multiple results. How could I go about doing this such that it appends the result to the prior results rather than replace it?
http://jsfiddle.net/16Lj1whL/2/
function addValue(id_name,result)
{
$s=$('#'+id_name);
$s.find('option[value="'+result+'"]').prop('selected',true);
$s.trigger("chosen:updated");
}
Try .prop( propertyName, function )
$("#" + id_name).prop("value", function(_, val) {
return val + result
}).trigger("chosen:updated");
var input = $("input")
, result = 0
, update = function() {
input.prop("value", function (_, val) {
return val + ++result
})
};
$("button").on("click", update)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button>click</button>
<input type="text" value="0">

How to add multiple listeners in jQuery/javascript?

for (key in this.mybutton)
button = this.mybutton[key]
$(button).click(function() {
console.log("click:" + button)
});
The result is always the name of the last button. How can I add multiple listeners in jQuery/javascript or erase the javascript reference button to a string in the for.
thanks in advance
You need a closure new scope :
for (key in this.mybutton)
(function(button) {
$(button).click(function() {
console.log("click:" + button)
});
})(this.mybutton[key]);
}
or just use this:
$(button).click(function() {
console.log("click:" + this)
});
Concatenating a DOM element and a string in the console log doesn't seem like a very good idea ?

assigning click method to variable

I am creating an array & assigning the value to each index in a function through variables.
I also want to attach a jquery click method to each variable. However, I am getting 'undefined' in return when the click method is called.
var i = 0;
var eCreditTransactions = new Array(6); // 6 members created which will be recycled
function abc()
{
addingElements (i);
}
/* **** THE FOLLOWING IS THE PROBLEM AREA **** */
$(eCreditTransactions[i]).click (function () // if user clicks on the transaction box
{
creditTransactionSlideIn (eCreditTransactions[0], 150); //another function called
});
/* **** this is the function being called in the first function above **** */
function addingElements (arrayIndex) // func called from within the 'createCreditTransaction()' func
{
eCreditTransactions[i] = $(document.createElement('div')).addClass("cCreditTransaction").appendTo(eCreditSystem);
$(eCreditTransactions[i]).attr ('id', ('trans' + i));
$(eCreditTransactions[i]).html ('<div class="cCreditContainer"><span class="cCreditsNo">-50</span> <img class="cCurrency" src="" alt="" /></div><span class="cCloseMsg">Click box to close.</span><div class="dots"></div><div class="dots"></div><div class="dots"></div>');
creditTransactionSlideOut (eCreditTransactions[i], 666); // calling slideOut animation
counterFunc ();
return i++;
}
Try this:
$(document).ready(function() {
$(".cCreditTransaction").click(function() {
//do what you want on click event
});
});
Hope it helps
Given that it looks like each element you're adding to the array has a classname (cCreditTransaction) you can hookup the click events using something like
$(document).delegate(".cCreditTransaction", "click", function() {
// code to fire on click goes here.
});
or in jQuery 1.7+ you can use .on instead of .delegate
You don't then need to hook up n events, but just one event that matches all items in the selector (in your case, the class name)
You should also change $(document) to a container element that has an Id, so that the DOM traversal to find the classes is trimmed down as much as possible. Why? Because finding elements by class name is a relatively expensive procedure, as opposed to finding tags or even better, an ID.
it looks like there should be a loop in this part:
function abc()
{
addingElements (i);
}
there is a call to addingElements, and an 'i' parameter being passed, but 'i' is at that moment still defined as 0.
it should say something like
function abc()
{
for (i=0;i<=7;i++)
{
addingElements (i);
}
}

Categories