I'm having an issue with my jQuery noConflict. The page that I'm trying to put the jQuery on has a drop-down navigation that already uses the noConflict() rule. Can I use more then one noConlfict on a page for different animations? I will have 3 different jQuery functions running simultaneously on one page. Separately they work fine, but once added together on a page they stop working. Below is one of the jQuery's that needs to run. Can someone help me add the noConflict() rule to it?
$(function() {
var current = 1;
var iterate = function(){
var i = parseInt(current+1);
var lis = $('#rotmenu').children('li').size();
if(i>lis) i = 1;
display($('#rotmenu li:nth-child('+i+')'));
}
display($('#rotmenu li:first'));
var slidetime = setInterval(iterate,5000);
$('#rotmenu li').bind('click',function(e){
clearTimeout(slidetime);
display($(this));
e.preventDefault();
});
function display(elem){
var $this = elem;
var repeat = false;
if(current == parseInt($this.index() + 1))
repeat = true;
if(!repeat)
$this.parent().find('li:nth-child('+current+') a').stop(true,true).animate({'marginRight':'-20px'},300,function(){
$(this).animate({'opacity':'0.7'},700);
});
current = parseInt($this.index() + 1);
var elem = $('a',$this);
elem.stop(true,true).animate({'marginRight':'0px','opacity':'1.0'},300);
var info_elem = elem.next();
$('#rot1 .heading').animate({'left':'-420px'}, 500,'easeOutCirc',function(){
$('h1',$(this)).html(info_elem.find('.info_heading').html());
$(this).animate({'left':'0px'},400,'easeInOutQuad');
});
$('#rot1 .description').animate({'bottom':'-270px'},500,'easeOutCirc',function(){
$('p',$(this)).html(info_elem.find('.info_description').html());
$(this).animate({'bottom':'0px'},400,'easeInOutQuad');
})
$('#rot1').prepend(
$('<img/>',{
style : 'opacity:0',
className : 'bg'
}).load(
function(){
$(this).animate({'opacity':'1'},600);
$('#rot1 img:first').next().animate({'opacity':'0'},700,function(){
$(this).remove();
});
}
).attr('src', info_elem.find('.info_image').html())
);
}
});
As #adaneo already commented, you always should wrap you code into the jQuery method but after that you even should call noConflict with the first parameter true:
$.noConflict(true);
This removes your jQuery completely from the jQuery and $ variable and returns a jQuery object. You can use that return value to use it in your code by giving it to your object or method as parameter:
function MyFunction($) {
$(doSomeThing);
}
MyFunction($.noConflict(true));
Related
I've already posted a question about jQuery toggle method here
But the problem is that even with the migrate plugin it does not work.
I want to write a script that will switch between five classes (0 -> 1 -> 2 -> 3 -> 4 -> 5).
Here is the part of the JS code I use:
$('div.priority#priority'+id).on('click', function() {
$(this).removeClass('priority').addClass('priority-low');
});
$('div.priority-low#priority'+id).on('click' ,function() {
$(this).removeClass('priority-low').addClass('priority-medium');
});
$('div.priority-medium#priority'+id).on('click', function() {
$(this).removeClass('priority-medium').addClass('priority-normal');
});
$('div.priority-normal#priority'+id).on('click', function() {
$(this).removeClass('priority-normal').addClass('priority-high');
});
$('div.priority-high'+id).on('click', function() {
$(this).removeClass('priority-high').addClass('priority-emergency');
});
$('div.priority-emergency'+id).on('click', function() {
$(this).removeClass('priority-emergency').addClass('priority-low');
});
This is not the first version of the code - I already tried some other things, like:
$('div.priority#priority'+id).toggle(function() {
$(this).attr('class', 'priority-low');
}, function() {
$(this).attr('class', 'priority-medium');
}, function() {
...)
But this time it only toggles between the first one and the last one elements.
This is where my project is: strasbourgmeetings.org/todo
The thing is that your code will hook your handlers to the elements with those classes when your code runs. The same handlers remain attached when you change the classes on the elements.
You can use a single handler and then check which class the element has when the click occurs:
$('div#priority'+id).on('click', function() {
var $this = $(this);
if ($this.hasClass('priority')) {
$this.removeClass('priority').addClass('priority-low');
}
else if (this.hasClass('priority-low')) {
$this.removeClass('priority-low').addClass('priority-medium');
}
else /* ...and so on... */
});
You can also do it with a map:
var nextPriorities = {
"priority": "priority-low",
"priority-low": "priority-medium",
//...and so on...
"priority-emergency": "priority"
};
$('div#priority'+id).on('click', function() {
var $this = $(this),
match = /\bpriority(?:-\w+)?\b/.exec(this.className),
current = match && match[0],
next = nextPriorities[current];
if (current) {
$this.removeClass(current).addClass(next || 'priority');
}
});
[edit: working demo]
Assuming you have 'priority' as the default class already on the element at the initialization phase, this will cycle through the others:
$('div#priority' + id)
.data('classes.cycle', [
'priority',
'priority-low',
'priority-medium',
'priority-normal',
'priority-high',
'priority-emergency'
])
.data('classes.current', 0)
.on('click', function () {
var $this = $(this),
cycle = $this.data('classes.cycle'),
current = $this.data('classes.current');
$this
.removeClass(cycle[current % cycle.length])
.data('classes.current', ++current)
.addClass(cycle[current % cycle.length]);
});
I have tried myself to do this with the sole help of toggleClass() and didn't succeeded.
Try my method that declares an array with your five classes and toggles dynamically through
them.Do adapt to your own names.
//variable for the classes array
var classes=["one","two","three","four","five"];
//add a counter data to your divs to have a counter for the array
$('div#priority').data("counter",0);
$(document).on('click','div#priority',function(){
var $this=$(this);
//the current counter that is stored
var count=$this.data("counter");
//remove the previous class if is there
if(($this).hasClass(classes[count-1])){
$(this).removeClass(classes[count-1]));
}
//check if we've reached the end of the array so to restart from the first class.
//Note:remove the comment on return statement if you want to see the default class applied.
if(count===classes.length){
$this.data("counter",0);
//return;//with return the next line is out of reach so class[0] wont be added
}
$(this).addClass(classes[count++]);
//udpate the counter data
$this.data("counter",count);
});
//If you use toggleClass() instead of addClass() you will toggle off your other classes.Hope is a good answer.
I've the following snip of a code:
var about = "about.html";
function loadPage(target){
$("#dashboard").load(target);
}
$(".nav li").click(function(){
loadPage($(this).attr("class"));
});
So when I click on a button like <li class="about">, target is = about.
But in that way, $("#dashboard").load(target); doesn't load the variable about which is the html-file which I want to load.
So how is it possible to call the variable in this way?
You seem to miss the .html part. Try with
$("#dashboard").load(target+'.html');
But, supposing you have only one class on your li element, you'd better use this.className rather than $(this).attr("class").
EDIT :
if you want to use your about variable, you may do this :
$("#dashboard").load(window[target]);
But it would thus be cleaner to have a map :
var pages = {
'about': 'about.html',
'home': 'welcome.jsp'
}
function loadPage(target){
$("#dashboard").load(pages[target]);
}
$(".nav li").click(function(){
loadPage(this.className);
});
A stupid answer : create a <a> tag, and set its href attribute to the correct value.
Otherwise :
A standard way to store key: values pairs in javascript is to use a plain object :
var urls = {};
urls['about'] = 'mysuperduperurlforabout.html';
function loadPage(target) {
var url = urls[target];
//maybe check if url is defined ?
$('#dashboard').load(url);
}
$(".nav li").click(function(){
loadPage($(this).attr("class") + ".html");
});
or
$("#dashboard").load(target+".html");
You can call the variables like this (if that's what you asked):
var test = 'we are here';
var x = 'test';
console.log(window[x]);
It's similar to the $$ in PHP. The output will be:
we are here in the console window.
You could put the "about" as an object or array reference similar to:
var pageReferences = [];
pageReferences["about"] = "about.html";
var otherReference = {
"about": "about.html"
};
function loadPage(target) {
alert(pageReferences[target]);
alert(otherReference[target]);
$("#dashboard").load(target);
}
$(".nav li").click(function () {
loadPage($(this).attr("class"));
});
Both of these alerts will alert "about.html" referencing the appropriate objects.
EDIT: IF you wished to populate the object based on markup you could do:
var otherReference = {};
$(document).ready(function () {
$('.nav').find('li').each(function () {
var me = $(this).attr('class');
otherReference[me] = me + ".html";
});
});
You could even store the extension in an additional attribute:
var otherReference = {};
$(document).ready(function () {
$('.nav').find('li').each(function () {
var me = $(this).attr('class');
otherReference[me] = me + "." + $(this).attr("extension");
});
});
Better would be to simply put the page reference in a data element:
<li class="myli" data-pagetoload="about.html">Howdy</li>
$(".nav li").click(function () {
loadPage($(this).data("pagetoload"));
});
I am a jQuery (and general programming) learner and rather than using a plug-in I am trying to build my own Image slider/cycle, both to keep the code small, and to aid in learning.
My function cycles through the li items adding a '.show' class, then after a delay removes the class and adds to the next slide. This seems to work fine.
I have been struggling for a few days to add navigation which will either move previous or next and stop the timer.
As it stands, if I click the navigation immediately as the script starts the navigation will work as expected, but once the automatic function to show another slide has started the navigation will jump multiple steps and I have no idea why this is. I imaging somehow jQuery is caching the previous divs which have had a '.show' class perhaps?
I have simplified my code and presentation to illustrate this working up in a CodePen: codepen.io/MattyBalaam/pen/vuhyJ
Here is the complete script:
function gallery(galleryContainer) {
$.fn.nextOrFirst = function(selector) {
var next = this.next(selector);
return (next.length) ? next : this.prevAll(selector).last();
};
$.fn.prevOrLast = function(selector) {
var prev = this.prev(selector);
return (prev.length) ? prev : this.nextAll(selector).last();
};
galleryContainer.parent().prepend('<div class="previous">previous</div><div class="next">next</div>');
var crossFade = function (){
var slideTimeout;
function slideWait() {
galleryContainer.find('.show').removeClass('show').nextOrFirst().addClass('show');
slideTimeout = setTimeout(crossFade, 800);
}
function checkForClicks() {
$('div.previous').on('click', function(){
galleryContainer.find('.show').removeClass('show').prevOrLast().addClass('show');
window.clearTimeout(slideTimeout);
});
$('div.next').on('click', function(){
galleryContainer.find('.show').removeClass('show').nextOrFirst().addClass('show');
window.clearTimeout(slideTimeout);
});
}
checkForClicks();
slideWait();
};
galleryContainer.children(':first-child').addClass('show');
setTimeout(crossFade, 800);
}
gallery($('ul'));
The problem is, that you are calling function checkForClicks multiple times (in each animation iteration) and the event listener is added to buttons multiple times, so on each click you move forwards/backwards not just once, but once for each animation step, that was already displayed. Move the checkForClicks outside the crossFade function and it will be ok.
see the code:
http://codepen.io/anon/pen/ptkea
working code:
function gallery(galleryContainer) {
$.fn.nextOrFirst = function(selector) {
var next = this.next(selector);
return (next.length) ? next : this.prevAll(selector).last();
};
$.fn.prevOrLast = function(selector) {
var prev = this.prev(selector);
return (prev.length) ? prev : this.nextAll(selector).last();
};
galleryContainer.parent().prepend('<div class="previous">previous</div><div class="next">next</div>');
var slideTimeout;
var crossFade = function (){
function slideWait() {
galleryContainer.find('.show').removeClass('show').nextOrFirst().addClass('show');
slideTimeout = setTimeout(crossFade, 800);
}
slideWait();
};
galleryContainer.children(':first-child').addClass('show');
setTimeout(crossFade, 800);
function initButtonEvents() {
$('div.previous').on('click', function(){
galleryContainer.find('.show').removeClass('show').prevOrLast().addClass('show');
window.clearTimeout(slideTimeout);
});
$('div.next').on('click', function(){
galleryContainer.find('.show').removeClass('show').nextOrFirst().addClass('show');
window.clearTimeout(slideTimeout);
});
}
initButtonEvents();
}
gallery($('ul'));
see my script:
http://codepen.io/anon/pen/asvGc
If you declare the var's outside the functions it works fine.
I've a problem with my application regarding jQuery. I tried a code example ( https://web.archive.org/web/20210513220745/http://aspnet.4guysfromrolla.com/articles/120810-1.aspx ) to use a Header CheckBox to check/uncheck all rows inside a GridView. The sample code works with jQuery v1.4.4 but doesn't work with the latest jQuery release v1.9.0.
Here's the code.
<script type="text/javascript">
var allCheckBoxSelector = '#<%=gvFileList.ClientID%> input[id*="chkAll"]:checkbox';
var checkBoxSelector = '#<%=gvFileList.ClientID%> input[id*="chkSelected"]:checkbox';
function ToggleCheckUncheckAllOptionAsNeeded() {
var totalCheckboxes = $(checkBoxSelector),
checkedCheckboxes = totalCheckboxes.filter(":checked"),
noCheckboxesAreChecked = (checkedCheckboxes.length === 0),
allCheckboxesAreChecked = (totalCheckboxes.length === checkedCheckboxes.length);
$(allCheckBoxSelector).attr('checked', allCheckboxesAreChecked);
}
$(document).ready(function () {
$(allCheckBoxSelector).live('click', function () {
$(checkBoxSelector).attr('checked', $(this).is(':checked'));
ToggleCheckUncheckAllOptionAsNeeded();
});
$(checkBoxSelector).live('click', ToggleCheckUncheckAllOptionAsNeeded);
ToggleCheckUncheckAllOptionAsNeeded();
});
</script>
With jQuery v1.4.4 everything works perfect. Using jQuery v1.9.0 every page load I get a "Object doesn't support this property or method: .live" error. If I use the syntax:
$(allCheckBoxSelector).click(function () {...
instead of the one above, I avoid the error but the Header Checkbox works only once. If I click it again nothing appens.
I also tried the .on syntax:
$(allCheckBoxSelector).on('click', function () {...
but it doesn't work too.
I'd like to know if that issue is due to a change or a bug in jQuery v1.9.0.
jQuery live should now be replaced by on. If the code worked before it should just work after you change live by on.
I got to the bottom of the problem: had to use .prop instead of .attr. I made some small modifications in the code too.
Here's a working demo on JS Bin: http://jsbin.com/egopar/4/edit
Here's the working code for jQuery 1.9:
$(document).ready(function () {
var allCheckBoxSelector = $('#chkAll');
var checkBoxSelector = $('input:checkbox:not(#chkAll)');
function ToggleCheckUncheckAllOptionAsNeeded() {
var totalCheckboxes = $(checkBoxSelector),
checkedCheckboxes = totalCheckboxes.filter(":checked"),
noCheckboxesAreChecked = (checkedCheckboxes.length === 0),
allCheckboxesAreChecked = (totalCheckboxes.length === checkedCheckboxes.length);
//console.log(allCheckboxesAreChecked);
$(allCheckBoxSelector).prop('checked', allCheckboxesAreChecked);
}
$(allCheckBoxSelector).on('click', function () {
$(checkBoxSelector).prop('checked', $(this).is(':checked'));
ToggleCheckUncheckAllOptionAsNeeded();
});
$(checkBoxSelector).on('click', function () {
ToggleCheckUncheckAllOptionAsNeeded();
});
});
If you are not using jQuery anywhere else in your page, you can use a very simple javascript to do this. There are many ways to do this, but this works for me and can be attached to buttons, links, etc. checkid is the client id and select being true or false.
function checktoggle(checkid,select){
var check=document.getElementById(checkid);
var numinput=check.getElementsByTagName('input');
for (i=0; i<numinput.length; i++){
numinput[i].checked=select;
}
}
Solved!
Thanks to Leniel Macaferi suggestions I used .on and .prop methods instead of .live and .attr but I make a different implementation of the script that finally works with jQuery v1.9.0 on my application.
<script type="text/javascript">
var allCheckBoxSelector = '#<%=gvFileList.ClientID%> input[id*="chkAll"]:checkbox';
var checkBoxSelector = '#<%=gvFileList.ClientID%> input[id*="chkSelected"]:checkbox';
function ToggleCheckUncheckAllOptionAsNeeded()
{
var totalCheckboxes = $(checkBoxSelector),
checkedCheckboxes = totalCheckboxes.filter(":checked"),
noCheckboxesAreChecked = (checkedCheckboxes.length === 0),
allCheckboxesAreChecked = (totalCheckboxes.length === checkedCheckboxes.length);
$(allCheckBoxSelector).prop('checked', allCheckboxesAreChecked);
}
$(document).ready(function()
{
$(allCheckBoxSelector).on('click', function()
{
$(checkBoxSelector).prop('checked', $(this).is(':checked'));
ToggleCheckUncheckAllOptionAsNeeded();
});
$(checkBoxSelector).on('click', ToggleCheckUncheckAllOptionAsNeeded);
ToggleCheckUncheckAllOptionAsNeeded();
});
</script>
I have a problem with my variable scope in a simple slider script that I´ve written (I don't want to use a readymade solution because of low-bandwidth). The slider script is called on statically loaded pages (http) as well as on content loaded through AJAX. On the statically loaded page (so no AJAX) the script seems to work perfect. However when called through AJAX the methods called can't find the elements of the DOM, which halts the necessay animation that is needed for the slider.
All the events are handled through even delegation (using jQuery's on() function), this however provided no solution. I'm quite sure it has something to do with the structure and variable scope of the script, but am unable to determine how to change the structure. So I'm looking for a solution that works in both situations (called normal or through AJAX).
I tried to declare the needed variables in every function, this however resulted in some akward bugs, like the multiplication of the intervals I set for the animation, because of the function scope. Hope somebody can help me in the right direction.
// Slider function
(function (window, undefined) {
var console = window.console || undefined, // Prevent a JSLint complaint
doc = window.document,
Slider = window.Slider = window.Slider || {},
$doc = $(doc),
sliderContainer = doc.getElementById('slider_container'),
$sliderContainer = $(sliderContainer),
$sliderContainerWidth = $sliderContainer.width(),
slider = doc.getElementById('slider'),
$slider = $(slider),
$sliderChildren = $slider.children(),
$slideCount = $sliderChildren.size(),
$sliderWidth = $sliderContainerWidth * $slideCount;
$sliderControl = $(doc.getElementById('slider_control')),
$prevButton = $(doc.getElementById('prev')),
$nextButton = $(doc.getElementById('next')),
speed = 2000,
interval,
intervalSpeed = 5000,
throttle = true,
throttleSpeed = 2000;
if (sliderContainer == null) return; // If slider is not found on page return
// Set widths according to the container and amount of children
Slider.setSliderWidth = function () {
$slider.width($sliderWidth);
$sliderChildren.width($sliderContainerWidth);
};
// Does the animation
Slider.move = function (dir) {
// Makes use of variables such as $sliderContainer, $sliderContainer width, etc.
};
// On ajax call
$doc.on('ajaxComplete', document, function () {
Slider.setSliderWidth();
});
// On doc ready
$(document).ready(function () {
Slider.setSliderWidth();
interval = window.setInterval('Slider.move("right")', intervalSpeed);
});
// Handler for previous button
$doc.on('click', '#prev', function (e) {
e.preventDefault();
Slider.move('left');
});
// Handler for next button
$doc.on('click', '#next', function (e) {
e.preventDefault();
Slider.move('right');
});
// Handler for clearing the interval on hover and showing next and pervious button
$doc.on('hover', '#slider_container', function (e) {
if (e.type === 'mouseenter') {
window.clearInterval(interval);
$sliderControl.children().fadeIn(400);
}
});
// Handler for resuming the interval and fading out the controls
$doc.on('hover', '#slider_control', function (e) {
if (e.type !== 'mouseenter') {
interval = window.setInterval('Slider.move("right")', intervalSpeed);
$sliderControl.children().fadeOut(400);
}
});
})(window);
The HTML example structure:
<div id="slider_control">
<a id="next" href="#next"></a>
<a id="prev" href="#prev"></a>
</div>
<div id="slider_container">
<ul id="slider">
<li style="background-color:#f00;">1</li>
<li style="background-color:#282">2</li>
<li style="background-color:#ff0">3</li>
</ul>
</div>
I notice you have
Slider.setSliderWidth = function() {
$slider.width($sliderWidth);
$sliderChildren.width($sliderContainerWidth);
};
which is called on ajax complete.
Does you ajax update the DOM giving a new DOM element that you could get to by doc.getElementById('slider')? Then your var slider and jquery var $slider are likely pointing to things that no longer exist (even if there is a dom element with slider as the id). To rectify, whenever the ajax is invoked that replaces that element, reinitialize slider and $slider to point to the new jquery wrapped element using the same initialization you have.
slider = doc.getElementById('slider');
$slider = $(slider);
Edit:
I'm not sure where you're going with the variable scope issue, but take a look at this example.
<pre>
<script>
(function(){
var a = "something";
function x (){
a += "else";
}
function y() {
a = "donut";
}
function print (){
document.write(a +"\n");
}
print ();
x();
print ();
y();
print ();
x();
print ();
})();
document.write(typeof(a) + "\n");
</script>
</pre>
It outputs into the pre tag
something
somethingelse
donut
donutelse
undefined
This isn't all that different from what you're already doing. As long as a is not a parameter of a method and is not declared with var in a nested scope, all references to a in code defined within your function(window,undefined){ ...} method will refer to that a, given that a is defined locally by var to that method. Make sense?
To begin, surely you can replace all the getElementById using a jQuery approach. i.e. replace $(doc.getElementById('next')) with $('#next')
I think that when you use on it doesn't search the element for the selector as you are assuming. So you would have to use:
$doc.on('click', '#slider_control #prev',function(e){
e.preventDefault();
Slider.move('left');
});
Wait, what gets loaded through Ajax? The slider-html code? In that case, the Slider has already been 'created' and a lot of your variables will point to nowhere (because these DOM elements did not existed when the variables were initialized). And they will never do so either.