I have looked high and low and can't seem to find this anywhere. Does anyone know how to get the value of a row tapped in a listview? This can be anything from the name to the index in the object. Right now I have a function that handles the tap. I need to be able to pass a value to the new page I am loading when it transitions. I thought I could do it here:
$('#taskListTable').delegate('li', 'tap', function () {
console.log('clicked');
//Insert code here to pull a value from either an index or a name and save it
});
I thought maybe it would be good to do it in the hash? I am not sure what the standard practice is here on the web coming from native iOS dev though. Anyone have any pointers? Thanks.
This is how I am populating my listview:
$.each(tasks, function(index, task) {
$taskList.append("<li><a href='taskDetails.html'> <h3>"+task.name+"</h3><p>"+task.description+"</p></a></li>");
});
taskDetails.html needs the index of the task so I can pull the details down from the server. What is the standard practice for doing that?
To get the index of the taped list-item you can do this:
$('#taskListTable').delegate('li', 'tap', function () {
console.log('clicked');
var index = $(this).index();
});
Yup, that's it. Although this assumes that the <li> element are all siblings.
Docs for .index(): http://api.jquery.com/index
If you want to then transition to the new page:
$('#taskListTable').delegate('li', 'tap', function () {
console.log('clicked');
$.mobile.changePage($(this).find('a').attr('href'), {
data : { selectedIndex : $(this).index() }
});
});
This will get the new page and attach the selectedIndex variable as a query string parameter that is set to the index of the tapped list-item.
Also, to be able to prevent the default behavior of clicking on the link in the list-item, I would attach this event handler to the link elements:
$('#taskListTable').delegate('a', 'tap', function (event) {
event.preventDefault();
console.log('link clicked');
$.mobile.changePage($(this).attr('href'), {
data : { selectedIndex : $(this).closest('li').index() }
});
});
The "delegate" method is deprecated on new versions of jQuery.
Consider using this instead:
$('#taskListTable').on('tap', 'a', function (event) {
}
Here is another method of getting an id, especially useful if you have a database enabled app and the id you are searching for is the database's id, not the row index:
When filling the table consider this:
<ul id="taskListTable">
<li id="task400" class="tasks">Task with db id 400</li>
<li id="task295" class="tasks">Task with db id 295</li>
</ul>
$('#taskListTable').on('tap', 'li', function (event) {
variable = $(this).attr('id').substr(4);
}
That will get the database id which you can pass on to your other pages.
To get the name out, you could do:
$(this).find('h3').html()
Alternatively, you can use something in the markup like the id or a data attribute to provide a better handle than the name.
What about this approach?
$taskList.append("<li><a href='taskDetails.html?id=" + task.id + "'></a><h3>" + task.name + "</h3>...</li>");
And then retreive id parameter.
Jasper's solution is good, but if you have any other code in your event handler that edits the DOM, the "this" keyword could be pointed somewhere entirely different by the time it gets used in your code.
I've cracked my head on my keyboard a number of times because my users said "I click on item one, but that always opens the edit screen for the last item in the list." So somehow using 'this' was not the right way to go.
Also, when I tried event.target, event.currentTarget or event.originalTarget, those didn't work either. They all pointed to the jQueryMobile "page" that was visible by the time the code got to run (which wasn't even the same page where the table was located).
The safe and/or intended approach is to:
use event.originalEvent.srcElement instead of 'this'
not use .delegate(), but use .on()
bind the event using $(document).on(), not $('#table').on()
So that would result in:
$(document).on('tap','#taskListTable li',function(event){
//The properties of 'event' relate to $(document), not to '#taskListTable li',
//so avoid .currentTarget, .target etc.
//But fortunately 'event' does have one property that refers to the original
//user event.
var theOriginalTapEvent = event.originalEvent;
var theRealClickedElement = theOriginalTapEvent.srcElement;
//Note that the clicked element could be a sub-element of the li
//whose index you want. So just referencing theRealClickedItem could
//could still be getting you bad results.
var theRelevantListItem = $(theRealClickedElement).parents('li');
//Now you're ready to get the item's index or whatever.
})
Related
So I'm making a small quiz app with object oriented JS using Object.create cloning method. I have an ol, and a function called showVals() that populates it with lis. That seems to be working fine. What I'm having trouble with is: my li click function to give the attr of ".selected' class seems to work intitially, but after I click to proceed and qn2.showVals() is called it is no longer giving the lis a class of selected when clicked.
The data for qn2 is there. Everything looks normal, except for the click function no longer working (giving the lis the class).
$(document).ready(function(){
qn1.showVals();
qn1.setAns(1); // calling question1 answer for now
$('li').click(function(){
$('li').removeAttr("class");
$(this).attr({"class": "selected"});
});
$('.proceed').click(function(e){
e.preventDefault();
if ($('.selected').html() == qn1.ctAns) {
if (confirm("You are correct")){
qn2.showVals();
qn2.setAns(3);
};
};
});
});
var qn1 = {
title:"The Mouth of Sauron",
qn: "How did 'The mouth of Sauron' meet his demise?",
img: "images/mouth-sauron.gif",
ans: ["Shot in the back", "Beheaded", "Drowned in a swamp", "Sacrificed"],
setAns: function(x) {
this.ctAns = this.ans[x]; //setting correct answer
},
showVals: function(){
$('#slide-title').text(this.title);
$('.question-box > p').text(this.qn);
$('#obj-img').attr("src", this.img);
$('ol').html('<li>'+this.ans[0]+'</li>'+'<li>'+this.ans[1]+'</li>'+
'<li>'+this.ans[2]+'</li>'+'<li>'+this.ans[3]+'</li>')
}
}
var qn2 = Object.create(qn1);
qn2.title = "Golemn";
qn2.qn = "What this dude's name?";
qn2.ans= ["Golemn", "Gimli", "Goober", "Poop"]
qn2.img = "images/golemn.gif";
This is likely because your li elements are dynamically added.
You should try using jQuery on(), which allows you to bind an event handler to the parent element which must already exists in your DOM, and then you can specify the child/descendant selector that will call the event handler. This child element may still be non-existent at the time you do the event binding. In such a case, you call on() like:
$('ol').on('click', 'li', function () {...});
where ol already exists.
Alternatively, you could always bind your click handler to your dynamically generated li elements after you have added them to your DOM. Although I think that is more processor-time consuming as I assume you have to do this for all quiz questions you ask your user.
I am currently working on a website and got stuck with the following problem:
On the website I have small dots (images) with the ids "dot0001", "dot0002", "dot0003", etc. . I also have hidden images (visibility:hidden) with the ids "info0001", "info00002", "info0003", etc.
I am looking for a jQuery solution. What I need is a code that allows the following events:
When users move the mouse over "dot0001" the image "info0001" becomes visible and when they leave "dot0001", "info0001" becomes invisible again. Same applies to "dot0002"-"info0002" , "dot0003"-"info0003" etc. So only the info-images with the corresponding 4 digit number become visible.
I gave it endless tries but got nowhere and there is not even a point in pasting my code.
Any help appreciated!
Something like this should work (though untested):
$('[id^="dot"]').on({
mouseenter: function(e) {
var infoId = this.id.replace('dot', 'info');
$('#' + infoId).show();
},
mouseleave: function(e) {
var infoId = this.id.replace('dot', 'info');
$('#' + infoId).hide();
}
});
That uses an attribute-starts-with selector to select all elements with an id beginning with "dot", then binds the event handlers to them. The event handler functions themselves simply replace the "dot" part of the id with "info" to form the correct new one, then show or hide the element as appropriate.
Don't forget to wrap that code in a DOM ready event handler so that it executes once the elements actually exist, otherwise it won't work.
Get all elements which id starts with "dot" and show/hide related "info" on mouseover/out:
$("[id^=dot]").hover(
function(){
$("#info" + this.id.substring(3)).css({"visibility":"visible"});
},
function(){
$("#info" + this.id.substring(3)).css({"visibility":"hidden"});
}
);
http://jsfiddle.net/EGBnR/
I am using a server side technology (JSP) to render my views. Therefore I have a for loop that loops through a list. Now, I want to bind a click listener to a button that is rendered for each item in the list. The code in the click listener needs the item ID, which I don't understand how to pass to the JavaScript code.
I also use requirejs, if that matter to the solution.
Maybe you just don't need to pass the html ID to your javascript. You can use a css class to retrieve your buttons in your DOM. The javascript code depends of what framework you use.
In native javascript, you can retrieve your buttons like this :
var buttons = document.querySelectorAll('button.my_class');
Just replace my_class by what you want.
You can access a button id by doing this :
var button_id = buttons[0].id
If you want to attach the item id to the button, you can use a data attribute. For example :
<button id="my_button" data-id="item_id" />
In the javascript, you can access to data_id like this :
var item_id = buttons[0].getAttribute('data-id');
In most event handlers, this is the DOM node that triggered the event, so something like this works:
button.onclick = function() {
alert(this.id);
}
Here is the live example
If you were using jQuery and requirejs this would be like this:
require(['jQuery'], function ($) {
$('.container_element').on('click', '.button_class', function () {
console.log('You have clicked button with id ', $(this).attr('id'));
})
})
I have a link that looks like this:
<a id="mylink" onclick="deleteHike( 3 );" href="javascript:void(0);">Yes</a>
It is able to call this JavaScript:
window.onload = function()
{
//Get a reference to the link on the page
// with an id of "mylink"
var a = document.getElementById("mylink");
//Set code to run when the link is clicked
// by assigning a function to "onclick"
a.onclick = function( hike_id )
{
// Somecode her
// But when I try to use the hike_id it displays as [object MouseEvent]
}
}
But the value that comes in is [object MouseEvent], not the number that I was expecting. Any idea why this happens and how to fix this? :)
Thanks!
You are trying to assign the function to your link in two different and conflicting ways.
Using the eval-ed function string, onclick = "function(value)", works but is deprecated.
The other way of binding the click handler in the onload event works too, but if you want a particular value to be passed, you'll have to change your script a bit because the value as given in the initial onclick is completely lost when you set the onclick to a new function.
To make your current method work, you don't need an onload handler at all. You just need this:
function deleteHike(hike_id) {
// Some code here
}
To do it the second way, which I recommend, it would look like this:
<a id="mylink" href="javascript:void(0);">Yes</a>
with this script:
function deleteHike(e, hike_id) {
// Some code here
// e refers to the event object which you can do nifty things with like
// - learn the actual clicked element if it was a parent or child of the `this` element
// - stop the event from bubbling up to parent items
// - stop the event from being captured by child items
// (I may have these last two switched)
}
function getCall(fn, param) {
return function(e) {
e = e || window.event;
e.preventDefault(); // this might let you use real URLs instead of void(0)
fn(e, param);
};
}
window.onload = function() {
var a = document.getElementById("mylink");
a.onclick = getCall(deleteHike, 3);
};
The parameter of a DOM event function is the event object (in Firefox and other standards-compliant browsers). It is nothing in IE (thus the need to also grab window.event). I added a little helper function for you that creates a closure around your parameter value. You could do that each time yourself but it would be a pain. The important part is that getCall is a function that returns a function, and it is this returned function that gets called when you click on the element.
Finally, I recommend strongly that instead of all this, you use a library such as jQuery because it solves all sorts of problems for you and you don't have to know crazy JavaScript that takes much expertise to get just right, problems such as:
Having multiple handlers for a single event
Running JavaScript as soon as possible before the onload event fires with the simulated event ready. For example, maybe an image is still downloading but you want to put the focus on a control before the user tries to use the page, you can't do that with onload and it is a really hard problem to solve cross-browser.
Dealing with how the event object is being passed
Figuring out all the different ways that browsers handle things like event propagation and getting the clicked item and so on.
Note: in your click handler you can just use the this event which will have the clicked element in it. This could be really powerful for you, because instead of having to encode which item it was in the JavaScript for each element's onclick event, you can simply bind the same handler to all your items and get its value from the element. This is better because it lets you encode the information about the element only in the element, rather than in the element and the JavaScript.
You should just be able to declare the function like this (no need to assign on window.onload):
function deleteHike(hike_id)
{
// Somecode her
// But when I try to use the hike_id it displays as [object MouseEvent]
}
The first parameter in javascript event is the event itself. If you need a reference back to the "a" tag you could use the this variable because the scope is now the "a" tag.
Here's my new favorite way to solve this problem. I like this approach for its clarity and brevity.
Use this HTML:
<a onclick="deleteHike(event);" hike_id=1>Yes 1</a><br/>
<a onclick="deleteHike(event);" hike_id=2>Yes 2</a><br/>
<a onclick="deleteHike(event);" hike_id=3>Yes 3</a><br/>
With this JavaScript:
function deleteHike(event) {
var element = event.target;
var hike_id = element.getAttribute("hike_id");
// do what you will with hike_id
if (confirm("Delete hike " + hike_id + "?")) {
// do the delete
console.log("item " + hike_id + " deleted");
} else {
// don't do the delete
console.log("user canceled");
}
return;
}
This code works because event is defined in the JavaScript environment when the onclick handler is called.
For a more complete discussion (including why you might want to use "data-hike_id" instead of "hike_id" as the element attribute), see: How to store arbitrary data for some HTML tags.
These are alternate forms of the HTML which have the same effect:
<a onclick="deleteHike(event);" hike_id=4 href="javascript:void(0);">Yes 4</a><br/>
<button onclick="deleteHike(event);" hike_id=5>Yes 5</button><br/>
<span onclick="deleteHike(event);" hike_id=6>Yes 6</span><br/>
When you assign a function to an event on a DOM element like this, the browser will automatically pass the event object (in this case MouseEvent as it's an onclick event) as the first argument.
Try it like this,
a.onclick = function(e, hike_id) { }
The function associated with the selector stops working when I replace it's contents using .html(). Since I cannot post my original code I've created an example to show what I mean...
Jquery
$(document).ready(function () {
$("#pg_display span").click(function () {
var pageno = $(this).attr("id");
alert(pageno);
var data = "<span id='page1'>1</span><span id='page2'> 2</span><span id='page3'> 3</span>";
$("#pg_display").html(data);
});
});
HTML
<div id="pg_display">
<span id="page1">1</span>
<span id="page2">2</span>
<span id="page3">3</span>
</div>
Is there any way to fix this??...Thanks
Not sure I understand you completely, but if you're asking why .click() functions aren't working on spans that are added later, you'll need to use .live(),
$("#someSelector span").live("click", function(){
# do stuff to spans currently existing
# and those that will exist in the future
});
This will add functionality to any element currently on the page, and any element that is later created. It keeps you have having to re-attach handlers when new elements are created.
You have to re-bind the event after you replace the HTML, because the original DOM element will have disappeared. To allow this, you have to create a named function instead of an anonymous function:
function pgClick() {
var pageno = $(this).attr("id");
alert(pageno);
var data="<span id='page1'>1</span><span id='page2'> 2</span><span id='page3'> 3</span>";
$("#pg_display").html(data);
$("#pg_display span").click(pgClick);
}
$(document).ready(function(){
$("#pg_display span").click(pgClick);
});
That's to be expected, since the DOM elements that had your click handler attached have been replaced with new ones.
The easiest remedy is to use 1.3's new "live" events.
In your situation, you can use 'Event delegation' concept and get it to work.
Event delegation uses the fact that an event generated on a element will keep bubbling up to its parent unless there are no more parents. So instead of binding click event to span, you will find the click event on your #pg_display div.
$(document).ready(
function()
{
$("#pg_display").click(
function(ev)
{
//As we are binding click event to the DIV, we need to find out the
//'target' which was clicked.
var target = $(ev.target);
//If it's not span, don't do anything.
if(!target.is('span'))
return;
alert('page #' + ev.target.id);
var data="<span id='page1'>1</span><span id='page2'>2</span><span id='page3'>3</span>";
$("#pg_display").html(data);
}
);
}
);
Working demo: http://jsbin.com/imuye
Code: http://jsbin.com/imuye/edit
The above code has additional advantage that instead of binding 3 event handlers, it only binds one.
Use the $("#pg_display span").live('click', function....) method instead of .click. Live (available in JQuery 1.3.2) will bind to existing and FUTURE matches whereas the click (as well as .bind) function is only being bound to existing objects and not any new ones. You'll also need (maybe?) to separate the data from the function or you will always add new span tags on each click.
http://docs.jquery.com/Events/live#typefn