Finding the value of a class within a list - javascript

I have
<ul id="list">
<li data-markerid="0" class="">
<div class="list-label">A</div>
<div class="list-details">
<div class="list-content">
<div class="loc-id">2</div>
<div class="loc-addr">England</div>
<div class="loc-dist">2 miles</div>
<div class="loc-addr2">Test</div>
<div class="loc-addr2">Bristol</div>
</div>
</div>
</li>
<li data-markerid="1" class="">
<div class="list-label">A</div>
<div class="list-details">
<div class="list-content">
<div class="loc-id">3</div>
<div class="loc-addr">England</div>
<div class="loc-dist">60 miles</div>
<div class="loc-addr2">Test</div>
<div class="loc-addr2">London</div>
</div>
</div>
</li>
</ul>
I'm wanting to extract the value of this using JQuery.
I tried:
var targetID = $(this).find('.loc-id').text();
But this gets me values of both loc-id's. I want just the one that I'm selecting (clicking).
For full context, please look here: Parsing data using JQuery
$('#list').click(function () {
//Change the src of img
var targetID = $(this).find('.loc-id').text(); // Get the ID
// Since array of objects isn't indexed, need to loop to find the correct one
var foundObject = null;
for (var key in parsedArray) {
if (parsedArray.hasOwnProperty(key) && parsedArray[key].id == targetID) {
foundObject = parsedArray[key];
break;
}
}
// If the object is found, extract the image and set!
if (!foundObject)
return;
var imageSrc = foundObject.LocationPhoto; // From the object
$('#location-image').attr('src', imageSrc); // Set the new source
});
Thanks

In your click handler, this references the <ul> element which has multiple <li> children.
Change the click handler to act as a delegate instead:
$('#list').on('click', 'li', function () {
Now, inside the click handler, this references an <li> element so the search should only yield a single value.

For var targetID = $(this).find('.loc-id').text(); to work, you must be clicking an element that is an ascendant of only one .loc-id. For example:
$('.list-details').on('click',function(){
var targetID = $(this).find('.loc-id').text();
});

You need to change selector. In your event handler. $(this) referes to ul which has multiple loc-id thus when you are using text() its concatenating text.
Use
$('#list li').click(function () {
//Change the src of img
var targetID = $(this).find('.loc-id').text(); // Get the ID
alert('targetID: ' + targetID)
});
instead of
// When we select the item
$('#list').click(function () {
//Change the src of img
var targetID = $(this).find('.loc-id').text(); // Get the ID
DEMO

You could use event.target in case you are delegating on #list:
Demo: http://jsfiddle.net/abhitalks/CxcU8/
$("#list").on("click", function(e) {
var $t = $(e.target);
if ($t.hasClass('loc-id')) {
alert($t.text());
}
});

Related

Find the parents parent element using jquery

I have the HTML as follows. what i need is when someone clicks on the span element i want to find its parents parent element check some conditions. i used prev() method but it gives me only the near parent(parent2 here)
<div class="container">
<div class="contain">
<div id="parent1">
<div class="parent2">
<span> Click here</span>
</div>
</div>
</div>
</div>
var currentComponent = $(event.target).prev(); //here i get parent2
How can i find the parents parent element(in this case parent2). i am not very familiar with jquery so any help would be appreciated.
You can try .closest.
From the docs:
the .closest() method searches through these elements and their ancestors in the DOM tree and constructs a new jQuery object from the matching elements.
(...)
get the first element that matches the selector by testing the element itself and .
It traverses up through the element ancestors in the DOM and returns the first one that matches the selector you passed as an argument. So, in your example, you can do something like that:
$("span").on("click", function(e) {
var myParent = $(this).closest(".parent2");
var parentOfMyParent = $(this).closest(".parent1");
var contain = $(this).closest(".contain");
var containerAbove = $(this).closest(".container");
});
What you need is
var currentComponent = $(event.target).parent().parent()
To do it in a single call, you can use
var currentComponent = $(event.target).closest(".parent1")
Fiddle:
https://jsfiddle.net/c624re4o/
Code:
var grandParent = $(this).parent().parent();
Full Working Code
$(document).ready(function () {
$("span").click(function () {
var grandParent = $(this).parent().parent();
alert(grandParent.attr('id')); // Just for Testing
});
});
$(document).ready(function () {
$("span").click(function () {
var grandParent = $(this).parent().parent();
alert(grandParent.attr('id')); // Just for Testing
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="contain">
<div id="parent1">
<div class="parent2">
<span> Click here</span>
</div>
</div>
</div>
</div>
you can use .closest() or .parents() function with selector like .parents('#elementid')

Get Values of sub elements of clicked class using jquery

I have a class amt and when that class is clicked I want to get the values of the clicked <h6>, <span> and <label> tags.
How do I do this in jquery? I have already seen a question here Get value of List Item with jQuery but it uses same under tag but i have to get different elemet value under same tag
<li class="amt" id="diecut_am1">
<h6>50</h6>
<span>$59.00</span>
<label>$51.30</label>
</li>
<li class="amt" id="diecut_am2">
<h6>100</h6>
<span>$68.00</span>
<label>$61.20</label>
</li>
Try this
$(".amt").click(function() {
var elem1 = $(this).find("h6").html();
var elem2 = $(this).find("span").html();
var elem3 = $(this).find("label").html();
alert(elem1);
alert(elem2);
alert(elem3);
});
https://jsfiddle.net/kLe5kLc3/1/
You could do something like this:
$( document ).ready(function() {
$('.amt').on("click", function() {
var h6 = $(this).find('h6').text();
var span = $(this).find('span').text();
var label = $(this).find('label').text();
});
});
Demo: https://jsfiddle.net/12q12k52/
here's the JS way :
var amt = document.querySelectorAll('.amt')
//add event listener to all .amt elements
var amtArr = [].slice.call(amt)
amtArr.forEach(function (x) {
x.addEventListener('click', listChilds, true)
});
//we retrive the target properties
function listChilds(e) {
console.log(e.path[1]) //all the children
//if you want one in particular it would be
console.log(e.target.childNodes[0])
}
<li class="amt" id="diecut_am1">
<h6>50</h6>
<span>$59.00</span>
<label>$51.30</label>
</li>
<li class="amt" id="diecut_am2">
<h6>100</h6>
<span>$68.00</span>
<label>$61.20</label>
</li>
You can iterate over the children of the clicked elements
$(this).children()

Attaching data to DOM elements

I m new to jquey.I m facing a problem to attach data to particular inner div's. I am writing a demo code for the problem that i faced which did the same behaviour as original one. I have to small div inside a big div and i want to store (for some further processing) and show some data to small div's based on user input.
[html code]
<div id="ctrl-1001" class="big">
<div id="m1" class="small"></div>
<div id="m2" class="small"></div>
</div>
<div id="input" class="control-group module">
<label class="control-label">Module Name</label>
<div class="controls">
<select id="ModuleName" name="DSname" class="input-large">
<option>TitleImage</option>
<option>SearchBox</option>
<option>CategoryLinks</option>
<option selected>BannerSlides</option>
</select>
</div>
<button id="sa">save</button>
</div>
[jquery code]
$('.small').click(function(){
$('#input').show();
var myId = $(this).attr("id");
var myParentId = $(this).parents('.big').attr('id');
var uniqueId = '#'+myParentId+' #'+myId;
create(uniqueId);
});
function create(uniqueId){
$('#input').show();
$('#ModuleName').change(function(){
var name = this.value;
$('#sa').click(function(){
save_name(name,uniqueId);
});
});
}
function save_name(name,uniqueId){
var div = $(uniqueId)[0];
jQuery.data(div,'store',name);
//alert(uniqueId);
//var val = jQuery.data(div,'store');
$(uniqueId).text(name);
$('#input').hide();
}
But the problem is when I click on second div to store some data the first div also changes the value which second one contains. demo on Jsfiddle
It is because when you click the first time one change handler is added to the select with targeting #m1 element, then again when you click on #m2 a new change handler is added without removing the first one, so when you click the button both these code gets executed.
So try
$('.small').click(function () {
var uniqueId = '#' + this.id;
create(uniqueId);
});
function create(uniqueId) {
$('#input').show();
//remove previously added handlers
//take a look at namespaced event handlers
//also there is no need to have a change handler for the select element
$('#sa').off('click.create').on('click.create', function () {
var name = $('#ModuleName').val();
save_name(name, uniqueId);
});
}
function save_name(name, uniqueId) {
var div = $(uniqueId);
//you can use the .data() method instead of the static jQuery.data() method
div.data('store', name);
//alert(uniqueId);
var val = div.data('store');
$(uniqueId).text(name);
$('#input').hide();
}
Demo: Fiddle
But a more jQueryish solution might look like
var $smalls = $('.small').click(function () {
var uniqueId = '#' + this.id;
$smalls.filter('.active').removeClass('active');
$(this).addClass('active');
$('#input').show();
});
$('#sa').on('click', function () {
var name = $('#ModuleName').val();
save_name(name, '.small.active');
});
function save_name(name, target) {
var div = $(target);
//you can use the .data() method instead of the static jQuery.data() method
div.data('store', name);
//alert(uniqueId);
var val = div.data('store');
div.text(name);
$('#input').hide();
}
Demo: Fiddle

When one is clicked, disable the other

So I have a mini slide menu in my website there is a menu you can choose what you want to read. There are points to click, when u clicked it the point get a red background.
But there is a problem.
When i click one point and then an other point the first clicked point have to lose his background.
Here is my HTML:
<div id="slide_button" onClick="clicked(this);"><dir class="button_1"></dir></div>
<div id="slide_button" onClick="clicked(this);"><dir class="button_2"></dir></div>
<div id="slide_button" onClick="clicked(this);"><dir class="button_3"></dir></div>
<div id="slide_button" onClick="clicked(this);"><dir class="button_4"></dir></div>
<div id="slide_button" onClick="clicked(this);"><dir class="button_5"></dir></div>
Here is my JS:
function clicked(slide_button) {
slide_button.getElementsByTagName("dir")[0].style.backgroundColor="red";
}
HERE IS AN EXAMPLE ON FIDDLE.
My "QUESTION IS" what i have to do to solve that?
What should I pay attention?
First you need to fix your HTML becaue your id values aren't unique. In fact, you don't even need id values, so you should use "slide_button" as a class. You can then use it to select all the buttons:
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
The CSS needs to be changed now so "slide_button" is a class selector, instead of an id selector:
.slide_button {
display: inline-block;
}
As for clearing the background, clear all of them before coloring the selected one red:
function clicked(slide_button) {
var buttons = document.getElementsByClassName('slide_button');
for(var i = 0; i < buttons.length; i++) {
buttons[i].getElementsByTagName('dir')[0].style.backgroundColor = '';
}
slide_button.getElementsByTagName('dir')[0].style.backgroundColor = 'red';
}
jsfiddle
This uses just JavaScript with no JQuery, but if you are using JQuery, you might as well use it here. The code is a lot shorter and easier to follow.
Here's a JQuery version:
$(function() {
$('.slide_button').click(function() {
var $button = $(this);
$button.children(':first').css({ backgroundColor: 'red' });
$button.siblings().children(':first').css({ backgroundColor: '' });
});
});
Note: This registers a click-handler, so you can get rid of the "onclick" attirbutes.
jsfiddle
You have to select all other points and set their background to none.
Or remeber which point is selected and on select another just remove background on last and remeber current point, then set its background to red.
See fiddle: http://fiddle.jshell.net/399Dm/5/
At first id should be unique per element.
<div class="slide_button"><dir class="button"></dir></div>
<div class="slide_button"><dir class="button"></dir></div>
<div class="slide_button"><dir class="button"></dir></div>
<div class="slide_button"><dir class="button"></dir></div>
<div class="slide_button"><dir class="button"></dir></div>
Second, you should store reference of clicked element if you want later remove background color, and instead of inline event handlers or binding all elements would be better if you use event delegation.
Demonstration
(function () {
"use strict";
// getting parent node of divs, due to bind click event. then
var ele = document.querySelector(".slide_button").parentNode,
prev = null; // store previous clicked element
ele.addEventListener("click", clickHandler); // event handler.
function clickHandler(e) {
var t = e.target; // get target of clicked element
// filter by target node name and class. edit: removed class checking
if (t.nodeName.toLowerCase() === "dir") {
// checking value of prev !== null and it's not same element.
if (prev && prev !== t) {
prev.style.backgroundColor = "";
}
prev = t; // store clicked element
t.style.backgroundColor = "red";
}
}
}());
I have fixed the fiddle so that it works hopefully as you plan.
http://jsfiddle.net/399Dm/8/ There you go!
var forEach = function(ctn, callback){
return Array.prototype.forEach.call(ctn, callback);
}
function clear(element, index, array) {
element.getElementsByTagName("dir")[0].style.backgroundColor="";
}
function clicked(slide_button) {
forEach(document.getElementsByClassName("slide_button"), clear);
//.style.backgroundColor="";
slide_button.getElementsByTagName("dir")[0].style.backgroundColor="red";
}
I had a slightly different method than #atlavis but a similar result.
http://fiddle.jshell.net/2AGJQ/
JSFIDDLE DEMO
jQuery
$('.slide_button').click(function(){
$('.slide_button dir').css("background-color", "inherit");
$(this).find('dir').css("background-color", "red");
});
HTML - Your markup is invalid because you have duplicate ids. Make them classes as below instead.
<div class="slide_button" >
<dir class="button_1"></dir>
</div>
<div class="slide_button">
<dir class="button_2"></dir>
</div>
<div class="slide_button">
<dir class="button_3"></dir>
</div>
<div class="slide_button">
<dir class="button_4"></dir>
</div>
<div class="slide_button">
<dir class="button_5"></dir>
</div>
CSS change
.slide_button {
display: inline-block;
}
If you can look at the following jsfiddle, I used jQuery to get what you want.

can this JavaScript function be refactored?

I need to use prototype JavaScript library on a project and wanted to add tabbed box to HTML.
The click handler has a simple task - set selected on parent <li> element and show linked DIV id element (rel tag on <li> has element id name)
<div class="tabInterface">
<ul class="tabSelector">
<li class="selected" rel="searchLast">Popularna iskanja</li>
<li rel="searchMine">Moje zadnje iskanje</li>
</ul>
<div class="tabContent selected" id="searchMine">
box 1 content
</div>
<div class="tabContent" id="searchLast">
box 2 content
</div>
</div>
Final result after 1 hour of hard labour.
initTabInterface = function() {
//requires prototype
var tabClick = function(event){
Event.stop(event);
var $el = Event.element(event);
var $menu = $el.up('.tabSelector');
var liList = $menu.descendants().filter(function(el){return el.match('li')});
liList.invoke('removeClassName', 'selected');
$el.up().addClassName('selected');
var rel = $el.up().readAttribute('rel');
var $interface = $menu.up('.tabInterface');
var tabList = $interface.descendants().filter(function(el){return el.match('.tabContent')});
tabList.invoke('removeClassName', 'selected');
$interface.down('#'+rel).addClassName('selected');
};
$$('.tabInterface .tabSelector li a').each(function(el){
var $el = $(el);
Event.observe($el, 'click', tabClick);
});
};
Event.observe(window,"load", function(){
initTabInterface();
});
Is there an easier way of traversing in prototype than with the bunch of up, down, filter, match, invoke and each?
This is pretty much you can get:
initTabInterface = function() {
//requires prototype
var tabClick = function(event){
Event.stop(event);
var $el = Event.element(event);
var rel = $el.up().readAttribute('rel');
// remove old selected classes
$el.up('.tabInterface').select('.selected')
.invoke('removeClassName', 'selected');
// add new selected classes
[ $(rel), $el.up() ].invoke('addClassName', 'selected');
};
$$('.tabSelector li a').each(function(el){
Event.observe($(el), 'click', tabClick);
});
};
Event.observe(window,"load", function(){
initTabInterface();
});​
I do not know Prototype well enough to quickly refactor your code, but you can use Element.siblings instead of going up and then descending down. Alternatively, you can just enumerate by class names (doesn't work well if you have more than one tab control).
$el.siblings().invoke('removeClassName', 'selected');
Also
$interface.down('#'+rel).addClassName('selected');
is unnecessary because you can only have one element with an id in the whole document. Can change it to:
$(rel).addClassName('selected');

Categories