I am rendering 'rows' of job listings represented by li elements created by calling map on a prop that holds an array of job listings.
Each li has an onClick handler within which I need to access the id associated with the clicked row in order to show the detail page of the job listing with that id. Note that the map adds the id values of the job listings as the key properties of the li elements.
The map function looks something like this:
var jobListRow = this.props.joblists.map(function(jobrowobj) {
return (
<li key={jobrowobj.id} onClick={this.handleClick}>
<div>bla bla</div>
<span>bla bla</span>
</li>
);
});
And the onClick handler looks like this:
handleClick: function(event) {
console.log(event.target);
}
Inside the handler I hoped to use the target of the clicked li to get the value of the key property for that li, but the target returned seems to be different every time and happens to be a varying child element of the li. How can I access the key of the li that was clicked? Or, phrased differently: how can I access the id of the job listing that was clicked?
This should work, you need to have the right context binding:
var jobListRow = this.props.joblists.map(function(jobrowobj, i){
return(
<li key={jobrowobj.id} onClick={this.handleClick.bind(this,i)}>
<div>bla bla</div>
<span>bla bla</span>
</li>
)
});
handleClick: function(i) {
console.log('You clicked: ' + this.props.joblists[i]);
}
Found this implementation here: https://facebook.github.io/react/tips/communicate-between-components.html
It seems it fits your needs. Hope it helped
The map function has an option to pass 'this' as a second parameter. I do it this way.
var vm = this;
var jobListRow = this.props.joblists.map(function(jobrowobj){
return(
<li key={jobrowobj.id} id={jobrowobj.id} onClick={this.handleClick}>
<div>bla bla</div>
<span>bla bla</span>
</li>
)
}, vm);
handleClick: function(event) {
console.log('You clicked: ' + event.target.id);
}
Related
I have a function that adds list items that all have the same id to a ul. I want to be able to click a specific list item and change the id of only the one I clicked.
so I'll call the function a few times and have it spit out:
thing1
thing2
thing3
then when I click thing2 the color changes from black to red.
edit: in response to request for the code I tried.
function addlist(){
var ask = prompt("what is the list item", "title");
document.getElementById("thing").innerHTML += "<li id='vid'><a href='#'>" + ask+ "</a></li>";
}
When you dynamically create the list items, as others have pointed out, you should give them different id="". I am assuming you could implement a solution where you ensure a unique ID and add an onmousedown attribute onto each <li>.
HTML
This assumes you add the onmousedown attribute to each <li> and have given each item a specific ID.
<ul>
<li id="theone" onmousedown="changeColor(this.id)">Click 1</li>
<li id="thetwo" onmousedown="changeColor(this.id)">Click 2</li>
<li id="thethree" onmousedown="changeColor(this.id)">Click 3</li>
</ul>
Javascript
function changeColor(id) {
//Do whatever you want to the specific element
var listitem = document.getElementById(id);
listitem.style.backgroundColor = "red";
}
Demo: http://jsfiddle.net/codyogden/t8xfeL0p/
You shouldn't use the same id. Instead give them all the same class. http://jsfiddle.net/anw66zu7/4/
HTML
<ul>
<li class="black">One</li>
<li class="black">Two</li>
<li class="black">Three</li>
</ul>
Javascript
window.onload = function() {
//when window loads
var blackelements = document.getElementsByClassName("black");
// get all elements with class "black"
for(var i=0; i < blackelements.length;i++) {
//create a for loop to go through each of these elements.
//the variable i increments until it reaches the amount of elements
//stored in the variable blackelements
var blackelement = blackelements[i];
//get the element with the index of the variable i
blackelement.addEventListener("click", function() {
//add an event listener to this element that checks for a mouse click
this.style.backgroundColor = "red";
//if clicked change the background color to red.
});
//close out of the event listener
}
//close out of the for loop
}
//close out of the onload function
Basically what happens is that it looks for all elements with the class "black" - it then loops through them and adds an event listener that looks for the "click" event to each of them. When you click it changes the background color of that specific item "this" to red.
First, your <li>s need to contain buttons to click and onclick call a function:
<input type="button" onclick="functionName(this)">Thing1</input>
In the function, you will call on the object and use the id function to change the id and the backgroundColor to change the color:
function functionName(obj)
{
obj.id = "new id"
obj.backgroundColor = "red"
}
I'm trying to add an active classname to the li that is clicked on. Showing that it's selected.
My template:
var legCatagoryTemplate = "<ul>{{#legs:i}}<li><a href='#' on-click='selectCategory:{{this}},{{i}}' data-id='{{i}}'><figure><div class='imgWrapper'><img src='{{preview}}'></div><figcaption><h4>{{name}}</h4><p>W: {{width}}" H:<span></span>: {{material}}</p></figcaption></figure></a></li>{{/legs}}</ul>";
How its called:
var legCategoryView = new Ractive({
el: "#catalog",
template: legCatagoryTemplate,
data: response_from_ajax
});
How I'm handling the event:
legCategoryView.on('selectCategory', function ( event, self, index ){
console.log(event.target, self, index);
}
What I've found:
event.target is the element inside of the a that was clicked (eg div.imgwrapper, figcaption)
Non Ractive behaves similarly: click event on a div should not be triggered by it's children
What is a good solution to targeting the element with the on-click proxy object?
You might just traverse the DOM and find the li element but that can cause troubles in certain situations. If you call ractive.set('legs', new_data), Ractive will reuse the existing nodes, so your class will remain there. There are several solutions for this problem (the third is probably the best):
Use ractive.merge() instead of ractive.set().
Use splice() and push() instead of ractive.set().
Change your template and let Ractive manage the class:
<ul>
{{#legs:i}}
<li class="{{#.active }}active{{/}}">
<a href='#' on-click='selectCategory:{{this}},{{i}}' data-id='{{i}}'>
<figure>
<div class='imgWrapper'><img src='{{preview}}'></div>
<figcaption>
<h4>{{name}}</h4>
<p>W: {{width}}" H:<span></span>: {{material}}</p>
</figcaption>
</figure>
</a>
</li>
{{/legs}}
</ul>
ractive.on('selectCategory', function ( e ) {
ractive.set(e.keypath + '.active', true);
});
I just had the idea of using jQuery to traverse up the dom with $.closest() like this
legCategoryView.on('selectCategory', function ( event, self, index ){
$(event.original.target).closest('li').addClass("active");
}
That works actually.
I am trying to figure out a more efficient way to write my code which works but it seems inefficient. Essentially I have a series of Id elements in a nav that trigger a click function on various ids elsewhere on the page. I tried combining my elements but that does not seem to work:
$("#red, #green, #blue").bind("click", (function () {
$("#section-red, #section-green, #section-blue").trigger("click");
alert("#section-red (Red heading) has been triggered!");
alert("#section-green (Green heading) has been triggered!");
alert("#section-blue (Blue heading) has been triggered!");
}));
... but this just seems to trigger everything.
I can do this below but for lots of ids, it will be a monster to maintain and update. Not sure if there is a better way.
$("#red").bind("click", (function () {
$("#section-red").trigger("click");
alert("#section-red (Red heading) has been triggered!");
}));
$("#green").bind("click", (function () {
$("#section-green").trigger("click");
alert("#section-green (Green heading) has been triggered!");
}));
// etc...
I have a fiddle here that I have been playing with but still no joy. Essentially a click on the top nav trigger a simulated click on an H2 heading which works but it's just the code efficiency at this point.
I would add data attributes to your nav elements like:
<ul>
<li id="red" data-trigger-id="#section-red">Section Red</li>
<li id="green" data-trigger-id="#section-green">Section Green</li>
<li id="blue" data-trigger-id="#section-blue">Section Blue</li>
</ul>
then in jQuery:
$("#red, #green, #blue").bind("click", (function () {
var triggerID = $(this).data("trigger-id");
$(triggerID).trigger("click");
}
Using event delegation you only need to register two event handlers.
$("ul").delegate("li", "click", function() {
var id = $(this).attr("id");
$("#section-"+id).trigger("click");
});
$(document).delegate("h2", "click", function() {
console.log($(this).attr("id"));
});
EDIT
You could make it more efficient by caching the element lookups
var h2 = [];
h2['red'] = $("#section-red");
h2['blue'] = $("#section-blue");
h2['green'] = $("#section-green");
Inside the ul delegate click handler
h2[id].trigger('click');
Fiddle
First, I would create a class for the ul - in this example, I called it "sections":
<ul class="sections">
<li id="red">Section Red</li>
<li id="green">Section Green</li>
<li id="blue">Section Blue</li>
</ul>
Next, bind a click even to $('.sections>li'), get the index, and apply it to the relative div.
$(".sections>li").click(function () {
var index=$(this).index();
$('.faqfield-question.accordion').eq(index).click();
});
That's all there is to it!
DEMO:
http://jsfiddle.net/6aT64/43/
Hope this helps and let me know if you have any questions!
How about doing something like this. This works for all browsers(including IE ;-) )
document.onclick = function(event){
event = event || window.event; //IE does not pass Object of event.
var target = event.target || event.srcElement;
switch(target.id){
case "header-red":
case "red-section":
redClicked();
break;
case "header-green":
case "green-section":
greenClicked();
break;
}
};
I have a video array, and then a list of thumbs that correspond to the array. When you click on one of the buttons, it needs to be deactivated for the duration of the video. I have it so that after the first click, it deactivates the whole list
$('li', '.thumbs').on('touchend click', function() {
$("#myVid").on("loadeddata", function() {
$("#bigPic").addClass("move");
$("#MyT").fadeOut(750);
});
playVideo2( $(this).index() );
$('li', '.thumbs').unbind();
});
if each item in the list is set up like this:
<li rel='1' id="first">
<div style="top:0px;">
<img src="graphics/filler.png" alt="" width="280" height="128" />
</div>
</li>
with the id being different for each, can I just put the id instead of the .thumbs, and just have it unbind or turn off itself? I know this must be inefficient, but I'm not sure how else to do it. Do I use this() somehow? If so, how?
You could make use of a global variable to check which video is playing.
//init
var currentlyPlaying = undefined;
Within your event handling part you set this variable to the ID of the clicked button.
currentlyPlaying = $(this).attr('id');
With that setup you can check the variable before doing anything in your script.
if ( !(currentlyPlaying == $(this).attr('id')) ) {
// your script
}
Alternatively, you can use the ID to unbind as you suggested, of course.
$('li', '.thumbs #' + $(this).attr('id')).unbind();
I have the following code.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<div id="hello">Hello <div>Child-Of-Hello</div></div>
<br />
<div id="goodbye">Goodbye <div>Child-Of-Goodbye</div></div>
<script type="text/javascript">
<!--
function fun(evt) {
var target = $(evt.target);
if ($('div#hello').parents(target).length) {
alert('Your clicked element is having div#hello as parent');
}
}
$(document).bind('click', fun);
-->
</script>
</html>
I expect only when Child-Of-Hello being clicked, $('div#hello').parents(target).length will return >0.
However, it just happen whenever I click on anywhere.
Is there something wrong with my code?
If you are only interested in the direct parent, and not other ancestors, you can just use parent(), and give it the selector, as in target.parent('div#hello').
Example: http://jsfiddle.net/6BX9n/
function fun(evt) {
var target = $(evt.target);
if (target.parent('div#hello').length) {
alert('Your clicked element is having div#hello as parent');
}
}
Or if you want to check to see if there are any ancestors that match, then use .parents().
Example: http://jsfiddle.net/6BX9n/1/
function fun(evt) {
var target = $(evt.target);
if (target.parents('div#hello').length) {
alert('Your clicked element is having div#hello as parent');
}
}
.has() seems to be designed for this purpose. Since it returns a jQuery object, you have to test for .length as well:
if ($('div#hello').has(target).length) {
alert('Target is a child of #hello');
}
Vanilla 1-liner for IE8+:
parent !== child && parent.contains(child);
Here, how it works:
function contains(parent, child) {
return parent !== child && parent.contains(child);
}
var parentEl = document.querySelector('#parent'),
childEl = document.querySelector('#child')
if (contains(parentEl, childEl)) {
document.querySelector('#result').innerText = 'I confirm, that child is within parent el';
}
if (!contains(childEl, parentEl)) {
document.querySelector('#result').innerText += ' and parent is not within child';
}
<div id="parent">
<div>
<table>
<tr>
<td><span id="child"></span></td>
</tr>
</table>
</div>
</div>
<div id="result"></div>
If you have an element that does not have a specific selector and you still want to check if it is a descendant of another element, you can use jQuery.contains()
jQuery.contains( container, contained )
Description: Check to see if a DOM element is a descendant of another DOM element.
You can pass the parent element and the element that you want to check to that function and it returns if the latter is a descendant of the first.
Ended up using .closest() instead.
$(document).on("click", function (event) {
if($(event.target).closest(".CustomControllerMainDiv").length == 1)
alert('element is a child of the custom controller')
});
You can get your code to work by just swapping the two terms:
if ($(target).parents('div#hello').length) {
You had the child and parent round the wrong way.
Without jquery
target.matches() with :scope
If you want to see if the target element has a parent which matches some selector use the .matches() method on the target and pass the selector followed by the :scope pseudo class.
The :scope here refers to the target element so you can use the in a :where pseudo class to help you write out a clean selector.
In the following example we will match all target elements which are a decedent of an a, button, or summary element.
const app = document.getElementById("app");
app.addEventListener("click", (event) => {
if (
event.target.matches(
":where(a, button, summary) :scope"
)
) {
console.log("click", event.target.parentNode.tagName);
}
});
<div id="app">
<button>
<span>Click Me</span>
</button>
<a href="#">
<span>Click Me</span>
</a>
<details>
<summary>
<span>Click Me</span>
</summary>
</details>
<span>Click Me</span>
<div>
Note the selector :where(a, button, summary) :scope could also have been written as:
a :scope,
button :scope,
summary :scope
parent.contains()
If you are interested in seeing if the target element is a child of a specific element use .contains() on the potential parent element:
const app = document.getElementById("app");
const button = document.getElementById("button");
app.addEventListener("click", (event) => {
if (button.contains(event.target)) {
console.log("click");
}
});
<div id="app">
<button id="button">
<span>Click Me</span>
</button>
<span>Click Me</span>
<div>
In addition to the other answers, you can use this less-known method to grab elements of a certain parent like so,
$('child', 'parent');
In your case, that would be
if ($(event.target, 'div#hello')[0]) console.log(`${event.target.tagName} is an offspring of div#hello`);
Note the use of commas between the child and parent and their separate quotation marks. If they were surrounded by the same quotes
$('child, parent');
you'd have an object containing both objects, regardless of whether they exist in their document trees.
To know more background info on Aleksandr Makov's answer, checking the below page might be helpful.
https://developer.mozilla.org/en-US/docs/Web/API/Node/contains
Node.contains()
The contains() method of the Node interface returns a boolean value indicating whether a node is a descendant of a given node, that is the node itself, one of its direct children (childNodes), one of the children's direct children, and so on.
It means, the answer is not using a reclusive function.