jquery slider in dropdown menu item causing too many events - jquery-ui

I am using a jQuery slider in a dropdown menu item. When I click on the menu item, a dropdown opens with a slider. User is expected to drag one of the slider handles. From that point onwards, any mouse movement on that page causes a slider event and a callback. This continues until I click someplace else on the page, effectively rolling back the menu dowpdown.
Is this behavior normal? How can I have the slider change events stop once the user has released the slider handle? I have a page that reloads from a database whenever the user changes the slider. This is causing excessive load on the database.
I am using jQuery UI with bootstrap. You can see example at http://jsfiddle.net/Sh5A5/2/
Here is the JS:
islide = 0;
$("#XYZ").text("DDDDDxD");
$("#XYZ").append("<b class=caret></b>");
$("#slider-range").slider({
range: true,
min: 0,
max: 500,
values: [75, 300],
slide: function (event, ui) {
alert("hello #" + ++islide);
$("#XYZ").html("$" + $("#slider-range").slider("values", 0) + " - $" + $("#slider-range").slider("values", 1) + " <b class='caret'></b>");
}
});
and html:
<div class="nav dropdown"> <a id="XYZ" data-toggle="dropdown" class="btn btn-primary" href="#"></a>
<ul class="dropdown-menu">
<li><a href="#">
<p>Range: 0 to Inf</p>
<div id="slider-range"></div>
</a>
</li>
</ul>
</div>
I tried the same without bootstrap. It looks ugly but behaves just the same. Is there a better alternative?
Thanks

What causing this behavior is this line:
alert("hello #" + ++islide);
When alert() is called inside the slide event handler the mouse is never released.
So you have to remove the call to alert() :
http://jsfiddle.net/Rusln/eKjCD/

Related

Grails: g:remotelink and one request only

I am using g:remotelink from Grails' tags to do one ajax request in a dropdown menu:
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<g:remoteLink class="dropdown-toggle" data-toggle="dropdown"
controller="mystuff" action="items" update="itemsListMenu">Items<b class="caret"></b></g:remoteLink>
<ul id="itemsListMenu" class="dropdown-menu">
</ul>
</li>
</ul>
it's working fine but I want to start a request only the first time the dropdown menu is pressed and not every time the menu is open or closed.
I read on the Grails' remotelink docs that it is possible using onSuccess/onLoaded/onComplete/etc functions but I am not sure what is the best way to do it.
Any idea?
UPDATE:
Following john smith suggestion I have added this:
<g:remoteLink id="myButton" onSuccess="jQuery('#myButton').attr('onclick',' ')" ... >
if you want to use the onsuccess event handler with style, and if youre including jquery
here you go
function killLink(element) {
element.attr("onclick"," ");
}
This function will simply remove the onclick ajax handler that grails creates from the tag,
your gsp would look like this
<g:remoteLink class="dropdown-toggle" data-toggle="dropdown"
controller="mystuff" onsuccess="killLink(this)" action="items" update="itemsListMenu">Items<b class="caret"></b></g:remoteLink>
grails remoteLink create a JQuery Ajax request, so with jquery I would do something like this:
// first set loaded to false
var loaded = false;
// if not loaded execute ajax request
if(!loaded){
$.ajax({
type:'POST',
url:"/mystuff/items",
success:function(data){
$("#itemsListMenu").html(data);
}
}).done(function(){
// when done set loaded to true.
loaded = true;
});
}

Jquery menu UI. How to display selection value in specified <li>

I have nested unordered lists to create a Jquery UI menu that expands when you hover over the first menu option. What I want to happen is for a menu selection to be displayed in the place of the first menu option you see once you select it. For some reason using .val or .html isn't working for me. Here is my code.
//this is where I try to take the selection and put it in in the <li> with the id 'input'.
<script>
$(function() {
$( "#menu" ).menu({
select: function( event, ui ) {
var selection = ui.item.text();
$("#input").html() = selection;
}
});
});
</script>
// the options below "Choose Activity" expand when you hover over "Choose Activity".
I want one of the selections
to take the place of "Choose Activity" once it is selected.
<ul id="menu">
<li>
Choose Activity?
<ul>
<li>Run Marathon</li>
<li>Weight lifting</li>
<li>Swimming</li>
<li>Boxing</li>
</ul>
</li>
<li>
//another line item
</li>
</ul>
.html() is a function which either gets/sets the innerHTML of the given element. Since it an function you need to pass the content as an argument to the function call.
It should be $("#input").html(selection); not $("#input").html() = selection;

How do I open a tab from with jQuery UI Tabs from an link outside of the div?

This may be a little difficult to explain, but I'll try my best. I have a product page with two tabs, full description and video. These are done using jQuery UI Tabs.
Above this section of the page I have a product image with thumbnails...but I want one of the thumbnails to be a link to see the video (which of course is contained in the video tab).
If I load the page as site.com/product#video it does load up the correct tab...but when the tab is not active, and I use a link outside of the #tab div, (ex: Video), it doesn't do anything.
How can I get a link to open the tab if it's not contained in the #tab div?
CODE
This code is outside of the tabs, and needs to open the #video tab
Open Video Tab
Tabs Code
<div id="tabs" class="ui-tabs ui-widget ui-widget-content ui-corner-all">
<ul class="product-tabs ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">
<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover">Full Description</li>
<li class="ui-state-default ui-corner-top">Video</li>
</ul>
<div class="product-collateral">
<div class="box-collateral box-description">
<div id="description" class="ui-tabs-panel ui-widget-content ui-corner-bottom">
Content
</div>
<div id="video" class="ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide">
<h2 class="video">Video Content</h2>
</div>
</div>
</div>
</div>
What worked for me was this:
Html
Open Description Tab
Open Video Tab
<div id="tabs">
<ul>
<li>
Full description
</li>
<li>
Video content
</li>
</ul>
<div class="product-collateral">
<div class="box-collateral box-description">
<div id="description">
Content
</div>
<div id="video">
<h2 class="video">Video Content</h2>
</div>
</div>
</div>
</div>
Javascript
$(document).ready(function () {
$('#tabs').tabs();
$('.open-tab').click(function (event) {
var tab = $(this).attr('href');
$('#tabs').tabs('select', tab);
});
});
So what this does is provide a link to both the description and video tabs, which are selected when the link is clicked.
From here we can see that when selecting a particular tab, we can use either a zero-based index or the href fragment which points to the tab we wish to display.
This is why the href attributes of the a elements match up with the Ids of the div elements - when one is clicked its href fragment is then used to set the selected tab.
Update for jQuery UI 1.11
As jQuery UI has evolved, so to has the API for setting the active tab. As of jQuery UI 1.11, the following code will select the active tab:
//Selects by the zero-based index
$('#tabs').tabs("option", "active", index);
Now because we now have to provide a zero-based index, the code I initially provided will no longer work.
What we need now is an index that can actually be used. One approach is:
$('.open-tab').click(function (event) {
var index = $("selector-of-clicked-tab").index();
$('#tabs').tabs("option", "active", index);
});
Another is to use HTML5 data- attributes:
Open Description Tab
Open Video Tab
So you can do this when handling the click of these links:
$('.open-tab').click(function (event) {
$('#tabs').tabs("option", "active", $(this).data("tab-index"));
});
use jQuery:
$( "#tabs" ).tabs({ active: tabNumber });
Remember, that the indexation starts from 0
Using jquery, bind a click event to your link that opens the tab you want.
$('#tabopenlink').click(function() {
$('#tabs').tabs({active: tabidx});
});
I use mini plug-in.
(function($) {
$.fn.tabremote = function(options) {
var settings = $.extend({
panel: "#tabs",
to: "data-to",
}, options );
$this=$(this);
$panel=$(settings.panel);
$this.click(function(){
if($(this).attr("href"))
{var tos=$(this).attr("href");}
else
{var tos=$(this).attr(settings.to);}
to=tos.match(/\d/g);
$panel.tabs({active: to-1});
return false;
});
return this;
}
})(jQuery);
Opens the tab using href or any element.
id panel must contain the number of the panel. Example (1-tabs, tabs-2, ...)
Plugin subtracts 1 and open the panel. Tabs (active, (number of id -1))
Use
$("button.href").tabremote({panel:"#tabs",to:"data-href"});
panel:"#tabs" // container panel
to:"data-href" // attribute name with value
function openTabByLink(link) {
$("#tabs").find("ul li[aria-controls='"+link+"'] a").trigger("click");
}
If you use twitter bootstrap instead of jquery ui, it will be very simple.
Just add data-toggle="tab" and put the link wherever you want in the page:
Open Video Tab
For jQuery UI 1.11
HTML:
<div id="tabs">...</div>
...
Open Video Tab
JS:
$('.open-tab').click(function () {
$("#tabs").tabs('option','active',$('#tabs a.ui-tabs-anchor[href="'+$(this).attr('href')+'"]').index('#tabs a.ui-tabs-anchor'));
});

Returning tab content in two seperate places using Twitter Bootstrap's data-toggle="tab"

I'm activating bootstrap.js tabs by specifying data-toggle="tab" in my navbar:
<li>Look Inside</li>
Then, returning the content of those tabs with:
<div class="tab-content">
<div class="tab-pane active" id="tab1">Content
</div>
</div>
I'm wondering how I can possibly return the same content to two separate places on the page, each in seperate div's. As of now, I add:
... for a second time after the first div had been closed (I have to close it because I have a horizontal navbar in between the top content and the bottom content) and it doesn't return content.
Is there any way I can call "tab-content" something else and still have it maintain twitter bootstrap functionality.
TY
Two ways to do this. One is pure CSS, taking advantage of the fact that the bootstrap dropdown will open any menu. For instance:
myvew.html.haml
%ul.nav.nav-pills
%li.dropdown
%a.dropdown-toggle{"data-toggle" => "dropdown"}
Foo
%b.caret
%ul.dropdown-menu{style: "position: relative; top: -10px;"}
%li Bar1
%ul.dropdown-menu
%li Bar2
What this will do is that when the "Foo" link is clicked, both "Bar1" and "Bar2" are shown.
However, I tend to prefer this approach: register an event listener onto the "Foo" link, and then the event listener toggles .show() or .hide() for the target divs.
$(document).ready(function() {
$('#myclickdiv').click(function() {
$('.mydivs').collapse("show");
});
});

jQuery UI Dialog Buttons Not Responding to click_button or selenium.click in Selenium/Webrat

Has anyone been able to get the jQuery UI Dialog buttons to respond to click_button or selenium.click? I can't seem to be able to get this to work.
Basically, I'm trying to test a form in a jQuery UI Dialog in a Rails app using Cucumber/Webrat/Selenium.
I have a page with many table rows, and each row on click fires off a dialog box with a form. Each form element has a unique id so the markup is valid.
Since the buttons can be created dynamically by the Dialog plugin, I initialize the dialog to add a 'Save' and 'Cancel' button. Interestingly, the plugin inserts a button tag, not an input tag. I also add ids on open as shown below, so the buttons can be targeted by the testing framework.
$('.inventory_dialog').dialog({
autoOpen: false,
modal: true,
buttons: {
'Save': function() {
// ajax submit stuff
},
Cancel: function() {
// cancel stuff
}
},
open: function() {
// add ids to buttons for selenium
var inventory_id = $(this).attr('id').split('_').pop();
$('.ui-dialog-buttonpane')
.find('button:contains("Save")').attr('id', 'inventory_'+inventory_id+'_save_button')
.end()
.find('button:contains("Cancel")').attr('id', 'inventory_'+inventory_id+'_cancel_button');
}
});
The markup looks like:
<div id="inventory_dialog_392827" class="inventory_dialog">
<form action="/suppliers/22/listings/27738/inventory/392827" class="edit_inventory" id="edit_inventory_392827" method="post"><div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div>
<div class="input_block">
<label for="inventory_392827_new_quantity">Quantity</label>
<input id="inventory_392827_new_quantity" name="inventory[new_quantity]" type="text" value="10" />
</div>
<div class="input_block">
<label for="inventory_392827_claim_quantities">Groups of</label>
<input id="inventory_392827_claim_quantities" name="inventory[claim_quantities]" type="text" value="6-8" />
</div>
</form>
</div>
My Cucumber step (presently) looks like:
When /^I click the "(.+)" button in the inventory dialog$/ do |button_name|
debugger
selenium.click "//button[#id='inventory_#{#current_offer.id}_#{button_name.downcase}_button']"
selenium_wait
end
When I run Cucumber and it hits 'debugger', I am able to manually 'selenium.click' in the input fields.
selenium.click "//input[#id='inventory_392827_new_quantity']"
This successfully puts a cursor in that field. However, clicking the button does not work:
selenium.click "//button[#id='inventory_392827_save_button']"
When I type that in the command line debugger, it returns nil (which I believe is success, since there is no exception), but Firefox doesn't do anything. The dialog box stays open in the browser. When I output response.body, that button is present.
I also tried
click_button "inventory_392827_save_button"
but the 'selenium_wait' command times out which means it doesn't see that element.
I'm stuck...
Does the problem go away if you change it to "fireEvent ... click" or to clickAt?
It might be better to locate your button by another location strategy such as XPath or CSS. If you add the HTML of the button(s) then I'll try to give some suggestions.
If your target button has a class of 'submit' for example you could use:
css=input.submit
If the target button has a value of 'Click Me' you could use:
//input[#value='Click Me']
Another suggestion would be to use the id attribute without the unique number, so the following may work for you:
//input[substring(#id, string-length(#id) -11, 12) = '_save_button']
I had a similar problem, and here's how i got it done (using Capybara/Selenium/Factory_Girl).
The jQuery UI Dialog buttons generates this HTML, in my case with two buttons Add and Cancel:
<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix">
<button type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false">
<span class="ui-button-text">Add</span>
</button>
<button type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false">
<span class="ui-button-text">Cancel</span>
</button>
</div>
But the click_button method doesn't work because the actual button name is a span
nested inside the button tag, as you can see above.
So i wrote in the .feature step:
When I press the jquery dialog "Add" button
And i added this to my 'base.rb':
# jQuery Dialog buttons
When /^I press the jquery dialog "([^\"]*)" button$/ do |button_text|
page.find("div.ui-dialog-buttonpane").find('span', :text => button_text).click
end

Resources