Onclick function changing to the same function for all changed elements - javascript

What I'm trying to do is based on data gotten via AJAX I am changing certain elements on the page to be different. A simplified version is this:
Example:
HTML:
<ul id="friends">
<li id="1-1" onclick="dont_alert()"> Andy </li>
<li id="1-2" onclick="dont_alert()"> Paul </li>
<li id="1-3" onclick="dont_alert()"> Saul </li>
<li id="1-4" onclick="dont_alert()"> Rita </li>
<li id="1-5" onclick="dont_alert()"> Greg </li>
</ul>
<input type="button" onclick='callback()' value="Go!" />
Relevant JS:
function alert_this(value) {
alert(value);
}
function dont_alert() {
alert('...');
}
function callback() {
var data_received = [["1","1","Andy"], ["1","5","Greg"]];
for (friend in data_received) {
if (data_received[friend][0] == undefined) continue;
var friend_id = '#'+ data_received[friend][0] +'-'+ data_received[friend][1];
$(friend_id).attr('onclick', '');
$(friend_id).css('background', 'red');
$(friend_id).click(function () {
alert_this(data_received[friend][2]);
});
}
}
The result of this is both elements alert 'Greg' instead of the appropriate value.
Any prod towards the answer will be very much appreciated! :D

You need to create a closure, otherwise, the .click() handler will always alert the value of the last assigned friend in the loop, since all they have is a reference to this variable.
function callback() {
var data_received = [["1","1","Andy"], ["1","5","Greg"]];
for (var friend in data_received) {
if (data_received[friend][0] == undefined) continue;
var friend_id = '#'+ data_received[friend][0] +'-'+ data_received[friend][1];
console.log(friend_id);
$(friend_id).attr('onclick', '');
$(friend_id).css('background', 'red');
(function() {
var savedValue = data_received[friend][2];
$(friend_id).click(function(){
alert(savedValue);
});
})();
}
}​
DEMO.

First off, you shouldn't be using inline event handlers in your HTML. Instead, attach them with jQuery.
Your problem is with closures - friend has function scope, within callback. The event handlers create a closure on the friend variable. When callback finished, friend == 1. The event handlers then use this value. A fix is to use $.each to iterate your arrays, which creates a closure on the value of the variable.
HTML
<ul id="friends">
<li id="1-1"> Andy </li>
<li id="1-2"> Paul </li>
<li id="1-3"> Saul </li>
<li id="1-4"> Rita </li>
<li id="1-5"> Greg </li>
</ul>
<input type="button" id="go" value="Go!" />
Js
$('#friends').on('click', 'li', function() {
alert('...');
});
$('#go').on('click', function() {
var data_received = [["1","1","Andy"], ["1","5","Greg"]];
$.each(data_received, function(i, friend) {
if (friend[0] === undefined) return;
$('#'+ friend[0] +'-'+ friend[1])
.css('background', 'red');
.click(function() {
alert(friend[2]);
return false;
});
});
});

Related

Iterating a list of items and append () html if the text of the item corresponds to "something" (using jquery)

I have a list of items, and I would like:
if the text of an item corresponds to another text, then I have to add in a span with a class (class is an icon font).
<div id="block-system-main-menu">
<ul>
<li>Home</li>
<li>Mappe</li>
<li>Vulc</li>
<li>Equa</li>
<li>About</li>
</ul>
</div>
Strangely however adds the class to to all the items and I do not understand why ....
$('#block-system-main-menu li').each(function () {
if (($(this).children().text()) == 'Mappe' || 'Vulc' || 'Equa'){
$(this).append('<span class="fa fa-caret-right"></span>');
}
});
thanks
DEMO
Because your condition satisfies for all the scenarios. You need to separate the concern in or condition:
$('#block-system-main-menu li').each(function () {
var text=$(this).find('a').text(); //get the a's text using find and store it as
//reference in variable
if (text == 'Mappe' || text== 'Vulc' || text== 'Equa'){
$(this).append('<span class="fa fa-caret-right"></span>');
}
});
Please have a look at below snippet. You have to check for each text as follows:
$('#block-system-main-menu li').each(function () {
if (($(this).children().text()) == 'Mappe' || $(this).children().text() =='Vulc' || $(this).children().text() =='Equa'){
$(this).append('<span class="fa fa-caret-right"></span>');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="block-system-main-menu">
<ul>
<li>Home</li>
<li>Mappe</li>
<li>Vulc</li>
<li>Equa</li>
<li>About</li>
</ul>
</div>
Hope this will be helpful
$('#block-system-main-menu li').each(function () {
var _getCondition =$(this).children().text()
if (_getCondition == 'Mappe' || _getCondition == 'Vulc' || _getCondition== 'Equa'){
$(this).append('<span class="fa fa-caret-right">Hello</span>');
}
});
Added hello in span just for validation
jsfiddle

Ask for multiple id's with the same data attribute

I'm trying to check for a data attribute in multiple list items.
My HTML:
<ul id="year">
<li id="2006">2006</li>
<li id="2007">2007</li>
<li id="2008">2008</li>
<li id="2009">2009</li>
<li id="2010">2010</li>
<li id="2011">2011</li>
<li id="2012">2012</li>
<li id="2013">2013</li>
<li id="2014">2014</li>
</ul>
And this is the jQuery:
jQuery('#year li').click(function()
{
var year = jQuery(this).attr('id');
if ((jQuery(this).data('state') === undefined) || (jQuery(this).data('state') == "off"))
{
jQuery(this).data('state', 'on');
}
else
{
jQuery(this).data('state', 'off');
}
});
Now i am trying to check if there are any list items where the "state" == "on"
Like this:
if ((jQuery('#year li').data('state') == "on"))
But it does not seem to be working...
EDIT: So i tried all the different snippets you gave me: none of them worked so i made a simple for loop that looks in every list point itself:
for ( var y = 2006, l = 2015; y < l; y++ )
{
if ((jQuery('#year #'+y).data('state') == "on"))
{
alert('data found');
}
Another problem was that i didnt had any event before my code!
Thanks for the support!
the jQuery('#year li') will return an array of jquery objects.
you will need to loop each one
$('#year li').each(function () {
if ((jQuery(this).data('state') === "on")){
alert("on state found");
}
});
You can use .filter() then check length property
var list = jQuery('#year li').filter(function(){
return $(this).data('state') == "on";
//OR, using native dataset
//return this.dataset.state == 'on'
});
if (list.length){
//li with state on exits
}
The reason this doesn't work for you is that jQuery doesn't store data values in the "standard" element dataset. You can acheive your goal by doing that yourself:
$('#year li').click(function() {
this.dataset.state = this.dataset.state === 'off' ? 'on' : 'off';
if($('#year li[data-state="on"]').length > 0) {
alert('Found!')
}
});
#year li[data-state="on"] {
color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="year">
<li id="2006">2006</li>
<li id="2007">2007</li>
<li id="2008">2008</li>
<li id="2009">2009</li>
<li id="2010">2010</li>
<li id="2011">2011</li>
<li id="2012">2012</li>
<li id="2013">2013</li>
<li id="2014">2014</li>
</ul>

Reference array element in jsView

I have simple test app, I want to remove and add tags, I have code like this:
<script id="tags_template" type="text/x-jsrender">
<div class="tags">
Tags:
<ul>
{^{for tags}}
<li>{{:name}}<a>×</a></li>
{{/for}}
<li><input /></li>
</ul>
</div>
</script>
and JS
var $view = $('#view');
var tags_tmpl = $.templates("#tags_template");
var tags = [];
tags_tmpl.link('#view', {tags: tags});
$view.find('input').keydown(function(e) {
if (e.which == 13) {
$.observable(tags).insert({name: $(this).val()});
$(this).val('');
}
});
$view.find('ul').on('click', 'a', function() {
// how to remove the tag?
});
Now how can I remove the tag? There is $.observable(array).remove but how can I reference that element in template and how can I get it in javascript?
Yes, your own answer is correct. But you may be interested in using a more data-driven and declarative approach, as follows:
<div id="view"></div>
<script id="items_template" type="text/x-jsrender">
Items (Hit Enter to add):
<ul>
{^{for items}}
<li>
{{:name}}
<a class="remove" data-link="{on ~remove}">×</a>
</li>
{{/for}}
</ul>
<input data-link="{:newName trigger=true:} {on 'keydown' ~insert}"/>
</script>
And
var items_tmpl = $.templates("#items_template");
var items = [];
items_tmpl.link('#view', {items: items}, {
insert: function(ev) {
if (ev.which === 13) {
// 'this' is the data item
$.observable(items).insert({name: this.newName});
$.observable(this).setProperty('newName', '');
}
},
remove: function() {
// 'this' is the data item
$.observable(items).remove($.inArray(this, items));
}
});
Alternatives for remove would be:
remove: function(ev) {
var view = $.view(ev.target);
$.observable(items).remove(view.index);
}
Or:
remove: function(ev, eventArgs) {
var view = $.view(eventArgs.linkCtx.elem);
$.observable(items).remove(view.index);
}
http://jsfiddle.net/BorisMoore/f90vn4mg/
BTW new documentation for {on ... event binding coming soon on http://jsviews.com
Found it in the docs:
$view.find('ul').on('click', 'a', function() {
var view = $.view(this);
$.observable(tags).remove(view.index);
});

Determine the .length index of the <li> item clicked [duplicate]

This question already has answers here:
Get index of clicked element using pure javascript
(10 answers)
Closed 9 years ago.
I have a set of <li> items:
<ul id="listings">
<li id="item-0">
<div class="content">hi</div>
<li>
<li id="item-1">
<div class="content">hi</div>
<li>
<li id="item-2">
<div class="content">hi</div>
<li>
</ul>
//etc
My question is: How do I determine the index number of the clicked <li> item?.
Like if I click: <li id="item-1"> I want to know it's the second <li> index.
I can easily determine the total lenght of all <li>'s by doing:
document.querySelectorAll('#listings li').length;
And I currently have the following click listener:
document.getElementById("listings").addEventListener("click", function(e) {
if(e.target && e.target.nodeName == "LI") {
console.log(e.target.id + " was clicked");
}
});
<ul id="listings">
<li id="item-0" onclick="isClicked(0)">
<div class="content">hi</div>
</li>
<li id="item-1" onclick="isClicked(1)">
<div class="content">hi</div>
</li>
<li id="item-2" onclick="isClicked(2)">
<div class="content">hi</div>
</li>
//...
I would add an onclick function to the li. Using javascript you can collect the data.
function isClicked(number){
alert("Clicked element: "+ number);
}
var ulLength = document.getElementById('listings');
var elements = [].slice.call(ulLength.childNodes);
//[].slice.call() is used to convert array-like objects/collections into an array
function getSiblings() {
var _s = [];
elements.forEach(function (i, d) {
if (i.nodeType === 1) //prevents text nodes to be counted as siblings
_s.push(i);
});
return _s;
}
function getElmIndex(elm) {
var _siblings = getSiblings();
for (var i = 0; i < _siblings.length; i++) {
if (!(_siblings[i] && _siblings[i] !== elm)) {
return i;
}
}
}
elements.forEach(function (elm, d) {
elm.addEventListener("click", function (e) {
var _index = getElmIndex(this);
alert("Index: " + _index);
});
});
Fiddle Link
If using Jquery is not a problem, I suggest the use of the index() method: http://jsfiddle.net/JLkPs/ .
Source: http://api.jquery.com/index/

Select sub element based on classes it has

Below is the HTML that I have
<ul id="QBS">
<li>
<a class="qb_mode starting Rodgers" href="#">See Stats</a>
</li>
<li>
<a class="qb_mode Manning" href="#">See Stats</a>
</li>
<li>
<a class="qb_mode Brady" href="#">See Stats</a>
</li>
</ul>
I want to find this unordered list, then tell which item has the starting qb class and then return the class that has their name (brady rodger manning) etc.
What's throwing me in a loop is the fact that the link is wrapped in the list element.
Here is what I am trying:
element = $("#qbs"); // pretty sure I want this vs getElementbyDocumentID
children = element.children();` // gets me all the list elements
for (i=0;i<children.length;i++) {
grandchild = children[i].children();
???? How would I get the 3rd class on this element?
}
Sorry about the formatting.
How about this?
var allClasses = $("#QBS").find('li a[class^="qb_"]')
.map(function () {
return this.className.split(" ").pop();
}).get();
console.log(allClasses);
Fiddle
Provided the class started with qb_* is at the beginning and you want to take only the last class of the match.
if all your class names are qb_mode then:
var allClasses = $("#QBS").find('.qb_mode').map(function () {
return this.className.split(" ").pop();
}).get();
if you want all of them then:
var allClasses = $("#QBS").find('.qb_mode').map(function () {
var cls = this.className.replace(/qb_mode/,'');
return cls.trim().split(/\W+/);
}).get();
console.log(allClasses);
Fiddle
If I understood you correctly, how about:
var name = $('#QBS a.qb_mode.starting').prop('class').replace(/\s*(qb_mode|starting)\s*/g,'');
console.log(name); // Rogers
See demo here.
a=document.getElementById('QBS');
var b=a.getElementsByClassName("qb_mode");
var i, j=b.length, result=[];
for(i=0;i<j;i++) {
c=b[i].className.split(" ");
result.push(c.pop());
}
return result;
fiddle http://jsfiddle.net/3Amt3/
var names=[];
$("#QBS > li a").each(function(i){
var a=$(this).attr("class").split(" ");
names[i]=a[(a.length-1)];
console.log("Name is " + names[i]);
});
or a more precise selector
$("#QBS > li a.qb_mode").each( ....

Categories

Resources