This example is simplified a bit, but in my ASP.NET web page in my c#/jquery code I am using a right hand context menu that displays ‘rightMenu’ when a right mouse is clicked.
$(document).ready(function() {
$(".RH_signoffrow td").contextMenu({
menu: 'rightMenu'
},
function(action, el, pos) {
var mykey = getkeyforitem(el);
mykey = "Details|" + mykey;
alert(
'Action: ' + action + '\n\n' +
'Key is: ' + mykey
);
if(action == "details"){
trigger_details_panel(mykey);
}
});
};
//for any td in the right hand side - get its row key
function getkeyforitem(el){
var mykey = $(el).parent().find('.hiddenrowkey').text();
// alert(
// 'Internal getkeyforitem Call' + '\n\n' +
// 'Key is: ' + mykey
// );
return mykey;
};
The callback of the menu passes back the element that was clicked, and that can be used to pull the keydata out of the current table row. Once I have that keydata, I can use it to call the real function I was after:
trigger_details_panel(mykey).
This works fine if I only want to use the right mouse, but I want to include an image in some of the rows, so that when the image is clicked, it produces the same effect,as the right mouse menu selection.
I am not sure how to accomplish that cleanly.
I can include an image that links to javascript in my page…
<asp:ImageButton ID="imgDetails" runat="server" ToolTip="Show Details"
ImageUrl="./images/details.gif" OnClientClick="showdetailsclicked();return
false;"></asp:ImageButton>
But how can I get it to call the code:
getkeyforitem(el);
Or at least know the element (el) it belongs to? It seems like there should be a way to use the (this) pointer to get at what I want - but I don't see it.
Am I just missing a more straightforward way to accomplish the whole problem?
If you replace the line:
var mykey = $(el).parent().find('.hiddenrowkey').text();
with
var mykey = $(el).parents("tr").find('.hiddenrowkey').text();
Then you can use this function to find the hidden rowkey from any element in the row.
Edit after comment:
You were right about using this. I'd probably do something like:
function showdetailsclicked(){ var rowKey = getkeyforitem(this);}
However, Im not sure if theres some issue with ASP, I doubt it, but you never know... You may have to do something like:
<asp:ImageButton ID="imgDetails" runat="server" ToolTip="Show Details"
ImageUrl="./images/details.gif" OnClientClick="showdetailsclicked(this);return
false;"></asp:ImageButton>
function showdetailsclicked(el){ var rowKey = getkeyforitem(el);}
Hope that helps!
Related
I got a droppable area where user can drop item. And I have a field which counts difference between required and dropped items. Here is example
And line where I display difference after dropping item:
$(this).closest("div.proc")
.find('.dif')
.text('Difference: ' + ( $(this).closest("div.proc").find('.numbr').text() - n) );
The problem is how can I display difference from the beginning. So user can see it even without dropping any item. Thank you
Insert this in your code:
$(".dif").each(function(){
var $e = $(this);
$e.text('Difference: ' + $e.closest("div.proc").find('.numbr').text());
});
in the outermost scope (like just after var itm = [];).
Put your logic in $(document).ready() and display text for each div as below:
$(document).ready(function(){
$('.projLeader label').each(function(){
$(this).find('.dropped').text("Items Dropped :0")
$(this).find('.dif').text("Difference : "+$(this).find('.numbr').text())
})
})
UPDATED DEMO
I using PhoneGap to create a Geolocation App following this excellent tutorial (link). Unfortunatelly, I'm having an issue that I can't figure out. The relevant parts that are giving me a headache are these:
//Section 1
$('#history').on('pageshow', function () {
tracks_recorded = window.localStorage.length;
$("#tracks_recorded").html("<strong>" + tracks_recorded + "</strong> workout(s) recorded");
$("#history_tracklist").empty();
for (i = 0; i < tracks_recorded; i++) {
$("#history_tracklist").append("<li><a href='#track_info' data-ajax='false'>" + window.localStorage.key(i) + "</a></li>");
}
$("#history_tracklist").listview('refresh');
});
//Section 2
$("#history_tracklist li a").on('click', function () {
$("#track_info").attr("track_id", $(this).text());
});
//Section 3
$('#track_info').on('pageshow', function () {
var key = $(this).attr("track_id");
$("#track_info div[data-role=header] h1").text(key);
var data = window.localStorage.getItem(key);
data = JSON.parse(data);
});
Section 1 works just fine, the data is stored, and the list is created without any issues. But then in Section 2 is when everything goes to hell. By clicking on the element, a new attribute (track_id) is supposed to be created, but it doesn't. Therefore, in Section 3, the "var key" won't get a value, and as a consequence, "var data" will be null also. As you can imagine, nothing works from there. What am I doing wrong here? I only included what I considered the relevant code, but if more is needed I'll do so. Thansk!
In section 2, I think you just need to delegate click handling to the "#history_tracklist" container, as follows :
$("#history_tracklist").on('click', "li a", function () {
$("#track_info").attr("track_id", $(this).text());
});
Without delegation you have a rule saying :
when any existing li a element within #history_tracklist is clicked execute my function
With delegation, you have a rule saying :
when any existing or future li a element within #history_tracklist is clicked execute my function
I'm attempting to make a menu bar that can have <li> elements added and removed. So far so good, but when I try and remove them I'm running into issues. I've toyed with this for a couple hours and now I'm wondering if this whole process could just be made easier (maybe an object?).
Anyways, here's the full code (80 lines), with comments to follow along.
var tabs = $('.accountSelectNav');
var titles = [];
var listItems = [];
// when the page loads check if tabs need to be added to the ul (menu bar)
$(document).ready(function(e) {
if ($.cookie('listItems') != null) {
console.log('not null');
//return "listItems" to it's array form.
listItems = JSON.parse($.cookie('listItems'));
$('.accountSelectNav').append(listItems);
}
});
$('.selectTable td:first-child').on('click', function(e) {
$('#home_select').removeClass('navHighlight');
//grab the text value of this cell
title = $(this).text();
$.ajax({
url:'core/functions/getAccountId.php',
type: 'post',
data: {'title' : title}
}).fail (function() {
alert('error');
}).done(function(data) {
accountId = $.trim(data);
// store values in the cookie
$.cookie('account_id', accountId, {expires : 7});
$.cookie('title', title, {expires : 7});
window.location = ('home_table.php');
});
// make sure the value is NOT currently in the array. Then add it
var found = jQuery.inArray(title, titles);
if (found == -1) {
titles.push(title);
addTab();
}
// make sure the value is NOT currently in the array. Then add it
found = jQuery.inArray(title, listItems);
if (found == -1) {
addListItem();
//place <li>'s in cookie so they may be used on multiple pages
$.cookie('listItems', JSON.stringify(listItems));
};
});
$("body").on("click", ".deleteImage", function (e) {
var removeTitle = $(this).closest('li').find('a').text();
var removeItem = $(this).closest('li')[0].outerHTML;
//remove title from "titles" array
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
//remove <li> from "listItems" array
listItems = jQuery.grep(listItems, function (value) {
return value != removeItem;
});
// this shows the <li> is still in the listItemsarray
console.log(listItems);
// put the array back in the cookie
$.cookie('listItems', JSON.stringify(listItems));
removeTab(this);
});
$("body").on("mouseover", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').show();
});
$("body").on("mouseleave", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').hide();
});
function addTab() {
tabs.append('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
};
function removeTab(del) {
$(del).closest('li').remove();
}
function addListItem() {
var s = ('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
listItems.push(s);
}
So you see I have two arrays of equal length that should always be the same length. One stores the title to be displayed in the tab, the other holds the html for the <li> which will be appended to the <ul>. I have no problem removing the title from its array. However removing the <li> from it's array is becoming a rather big hassle. You see when I get the <li> element after its been inflated the html inside does not exactly match what was put in, the browser adds style elements.
Example, the variable "removeItem" represents the html value of the selected <li> I wish to remove. It looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage" style="display: inline;"></li>
yet the value in my array "listItems" looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage"/></li>
So my attempt at removing it from my array always fails because they aren't a perfect match.
Now my question is how do I remove this <li> item? Also is there an easier way to do this whole process and I'm just not seeing it?
Thanks for your time.
EDIT
Fiddle by request here
Easiest way I can explain it.
Click the link to the fiddle.
Click any cell in the "App Name" column
This will add a <li> to the <ul> (menu) above of the table
When you hover over the <li> a picture appears
Click the picture
This should remove the <li>, both from the <ul> and from the array listItems
right now it does not
In the process of making this easier to check, I've taken your JSFiddle and did the following:
removed extra console.log and comments
removed interaction with cookies (since I did not have them in the first place, I figured they wouldn't just the first scenario)
After doing so I reached a point (you can see it here) where the desired functionality just works.
I even went ahead and removed the ajax stuff because that alert was driving me crazy. (here)
Since this works fine, my guess is that your issue lies between the lines that I removed.
Your usage of cookies is as follows:
To load existing tabs and add them back again
To save account_id and title, which is not used back again
To persist the listItems after a new item has been added
I then opened up the console with your version of the fiddle and the execution of javascript stops at $.cookie() with the error undefined is not a function.
This clearly indicates that the issue present in the Fiddle is that jQuery.cookie is not present and so those calls are halting the execution of the rest of your script. This also explains why it just started working when I took them out.
I posted the whole process of how I got there to indicate how I trimmed down the problem to specific parts, which is useful to reduce the problem space. When you're out of options and reach a place when you're lost, it's easier to post a question with less code and the specific part of the problem that you've identified. This will help you in finding the issues that you're facing and StackOverflow to provide proper answers to your questions.
Hope it helps!
Here is the solution I came up with. It should be much easier for people to understand than my original post. Although it's a long read it may be worth it, especially for new developers.
The point of this code is to make a menu bar out of an un-ordered list or <ul>. The menu bar needs to be used on multiple pages. So I'll be using cookies.
I start with this code to get a text value from my table.:
$('.selectTable td:first-child').on('click', function(e) {
// This value will be used later for the name of the tab or `<li>` inside our menu bar or `<ul>`
title = $(this).text();
});
Then I place the value in an array. I do this only if the array does not already have this string inside it. I do not want duplicates:
var found = jQuery.inArray(title, titles);
var titles = [];
if (found == -1) {
titles.push(title);
}
Then I store the array into a cookie, using a library like this:
$.cookie('titles', JSON.stringify(titles));
Now when any page loads that needs this menu bar I run this code to check if there are any values:
$(document).ready(function() {
if ($.cookie('titles') != null) {
titles = JSON.parse($.cookie('titles'));
}
});
Now I need to loop through the array. When I loop through the array I have to do 3 things:
1) Grab the string value.
2) Add the html to my new string so it becomes a list item or <li>.
3) Append the newly created <li> to our <ul>.
Like so:
for(var i = 0; i < titles.length; i++) {
var str = titles[i];
var listItem = '<li class="navHighlight">'
+ '<a href="#">'
+ str
+ '</a>'
+ '<a href="#">'
+ '<img src="images/delete.png" class="deleteImage"/>'
+ '</a>'
+ '</li>';
$('.accountSelectNav').append(listItem);
}
Now, if I want to remove this <li> I click the delete image found inside our <li>. What delete image you say? Look at the html I added again. You will see I add an <img> tag in there.
Now delete like so:
$("body").on("click", ".deleteImage", function (e) {
// grabs the text value of my li, which I want to remove
var removeTitle = $(this).closest('li').find('a').text();
// runs through my titles array and returns an array without the value above
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
});
Then I simply place the new array inside my cookie once again. Like this:
$.cookie('titles', JSON.stringify(titles));
And finally I remove the tab like this:
removeTab(this);
function removeTab(del) {
$(del).closest('li').remove();
}
Yay, I'm done. So now, if anyone has a more elegant way of accomplishing this I'm listening. I have no doubt there's a better way, javascript/jQuery isn't even close to my strong point.
The full code can be found here.
It's a pretty simple trick that I thought should work fine however it doesn't. So I have multiple checkboxes on the page. And whenever they are changed I would like to record any change to the database. So in the view event 'click' on checkbox I have similar to this:
var filter_name = $(e.target).attr("name");
var filter_value = $( "input:checkbox[name=" + filter_name + "]:checked" ).map(function () {
return this.value;
}).get();
console.log("filter_name: " + filter_name); #=> my_method_name
CarInsuranceApp.aciq.set({filter_name: filter_value});
CarInsuranceApp.aciq.save();
And here the results that I receive as a JSON:
"filter_name"=>"extra"
So my question would be how to dynamically pass model attribute name on the set?
use like this.
CarInsuranceApp.aciq.set(filter_name, filter_value);
Here is a possible one line JavaScript`ish solution:
CarInsuranceApp.aciq.attributes[filter_name] = filter_name;
Adi Palaz's Nested Accordion
This seems like it should be simple but I can't seem to figure this out and I have been sitting here slamming my head on my desk after like four hours without a solution.
You will notice in the demo on the page that there are expand all/collapse all buttons that fire a function to open all the accordion panels or close them.
I DON'T want to use those buttons. I want to write my own function and fire the expand all or collapse all function after the user completes a gesture on a DIV somewhere else on the page.
But I can't seem to figure out how to call the same function the author is using on the buttons to properly expand and collapse the accordion panels.
If it helps, I set up a test page to play with:
http://dl.dropbox.com/u/22224/Newfolder/nested_accordion_demo3.html
And here are the two scripts it needs to work:
Nested Accordion Script
Expand.js
Please help! I am desperate and the author is not responding to emails!
I was able to solve the expand/collapse all problem with the following code, hope it will work for you as well.
function expand(id) {
var o = $.extend({}, $.fn.accordion.defaults, null);
var containerID = o.container ? id : '', objID = o.objID ? o.objID : o.obj + o.objClass, Obj = o.container ? containerID + ' ' + objID : id, El = Obj + ' ' + o.el, hTimeout = null;
$(El + ' a.trigger').closest(o.wrapper).find('> ' + o.next).show().closest(o.wrapper).find('a.trigger').addClass('open').data('state', 1);
}
function collapse(id) {
var o = $.extend({}, $.fn.accordion.defaults, null);
var containerID = o.container ? id : '', objID = o.objID ? o.objID : o.obj + o.objClass, Obj = o.container ? containerID + ' ' + objID : id, El = Obj + ' ' + o.el, hTimeout = null;
$(El + ' a.trigger').closest(o.wrapper).find('> ' + o.next).not('.shown').hide().closest(o.wrapper).find('a.open').removeClass('open').data('state', 0);
}
Example:
expand('#accordion1');
collapse('#accordion1');
I'm faced with the exact same problem and would like to know if you ever found an answer?
The work around I plan to use is something like $('.accordion a').click(); to programmatically click each link in the list - not pretty but it seems to work...
Two years later and I have the same desire... use Adi Palaz nested accordion, but have my OWN styled and specific action expand/collapse all buttons. I did finally get it to work the way I wanted even though I am admittedly a novice level jquery programmer. Here's my key learnings:
I started with example nested_accordion_demo5.html with the #acc1
example. I did not use expand.js at all, I never could get it to
work.
I changed the function defaults in my demo5.html to add the obj: "div".
$("#acc1").accordion({
obj: "div",
el: ".h",
head: "h4, h5",
next: "div",
iconTrigger: true
});
Then I added a div with class="accordion" around the whole ul structure and removed the accordion class from the ul.
I made my own two expand/collapse links and put them inside the div but before the ul. Later I got fancy and added styling to make them look like buttons, but first I got it working.
[Expand All] [Collapse All]
Then I added two new separate event handlers to jquery.nestedAccordion.js using snippets from the one that handles the a.trigger events. I placed them immediately after the existing event handler. Here's my new CollapseAll:
$(Obj).delegate('a.CollapseAll', ev, function(ev) {
$( o.obj + o.objClass ).find('a.trigger').each(function() {
var $thislink = $(this), $thisWrapper = $thislink.closest(o.wrapper), $nextEl = $thisWrapper.find('> ' + o.next);
if (($nextEl).length && $thislink.data('state') && (o.collapsible)) {
$thislink.removeClass('open');
$nextEl.filter(':visible')[o.hideMethod](o.hideSpeed, function() {$thislink.data('state', 0);});
}
});
});
Then I made a second event handler that does the ExpandAll.
I know this could likely be much more efficient, but I am thrilled to at least have it working given my skill level!