Playing around with jQuery objects and variables - javascript

$('div#Settings ul li').click(function () {
var url, template;
var self = $(this);
if (!$(self).hasClass('selected')) {
var ContextMenu = CreateContext($(self));
var id = $(self).attr('id');
etc...
function CreateContext(item) {
var ContextMenu = $('div#ContextMenu');
if (!$(ContextMenu).length) {
$('<div id="ContextMenu"></div>').appendTo('body');
CreateContext(item);
}
$(ContextMenu).slideUp(150, 'swing', function () {
$(ContextMenu).insertAfter(item);
});
$(item).addClass('selected').siblings().removeClass('selected');
return $(ContextMenu);
}
On the first call to CreateContext(item) I cannot use the variable ContextMenu later in the .click code. However, if CreateContext is called twice, everything works fine. I am getting an undefined variable when i console.log(ContextMenu) the first time. The second time it gets the object correctly. How can I fix this? Thanks.

That's because div#ContextMenu doesn't exist the first time you call CreateContext. In fact your function detects that condition and then creates it. But, after creating it, you don't populate the value of ContextMenu inside your function so the rest of the function doesn't work properly.
Here's what I would suggest:
function CreateContext(item) {
var ContextMenu = $('#ContextMenu');
if (!ContextMenu.length) {
ContextMenu = $('<div id="ContextMenu"></div>');
ContextMenu.appendTo('body');
}
ContextMenu.slideUp(150, 'swing', function () {
ContextMenu.insertAfter(item);
});
$(item).addClass('selected').siblings().removeClass('selected');
return ContextMenu;
}
Note, once ContextMenu is a jQuery object, you don't have to surround it with $() after that as it's already a jQuery object.

Try taking the jQuery indicator out of your function. Since you've declared the variable as a jQuery object, I don't believe you need to identify it as a jQuery object AGAIN in your function.

Related

How to trigger ready event on JQuery chosen plugin?

I am trying to bind an liszt:ready event of my list, to be invoked once that the list has been initialized by chosen.
I follow the steps that here are describing without any success.
This is my code:
var initPreferredCollaboratorChosen = function () {
$("#preferredCollaboratorChosenId").chosen({width: "95%"}).trigger("chosen:ready");
};
var initListener = function () {
$("preferredCollaboratorChosenId").on("chosen:ready", function(){
alert("Hey, I am ready!");
});
initPreferredCollaboratorChosen()
};
I try with "liszt:ready" instead "chosen:ready" as well.
Can anyone that has work with this plugin tell me how make it?.
Regards.

Calling a function from an html document will not generate an alert

Hi all thanks for taking a look.
I am trying to call a javascript function when I click on the update button.
Here is the javascript
var text2Array = function() {
// takes the value from the text area and loads it to the array variable.
alert("test");
}
and the html
<button id="update" onclick="text2Array()">Update</button>
if you would like to see all the code check out this jsfiddle
http://jsfiddle.net/runningman24/wAPNU/24/
I have tried to make the function global, no luck, I can get the alert to work from the html, but for some reason it won't call the function???
You have an error in the declaration of the pswdBld function in your JavaScript.
...
var pswdBld() = function() {
---^^---
...
This is causing a syntax error and avoiding the load of your JavaScript file.
See the corrected version.
Also, you may consider binding the event and not inlining it.
<button id="update">Update</button>
var on = function(e, types, fn) {
if (e.addEventListener) {
e.addEventListener(types, fn, false);
} else {
e.attachEvent('on' + types, fn);
}
};
on(document.getElementById("update"), "click", text2Array);​
See it live.
In your fiddle, in the drop-down in the top left, change "onLoad" to "no wrap (head)"
Then change
var text2Array = function()
var pswdBld() = function()
to
function text2Array()
function pswdBld()
and it will alert as expected.
You have a syntax error in the line below..
var pswdBld() = function
^--- Remove this
supposed to be
var pswdBld = function
Also make sure you are calling this script just at the end of the body tag..
Because you are using Function Expressions and not Function Declaration
var pwsdBld = function() // Function Expression
function pwsdBld() // Function Declaration
Check Fiddle

How to attach Event Listeners to only newly created elements?

When I fire a function I want it to apply listeners just to elements I pass, particular this jQuery element.
addEventListeners(this);
function addEventListeners(el) {
$(el).mouseenter(function() {
$(this).stop(true,true).switchClass("", "HIGHLIGHT", 400, "easeInOutQuad");
});
$(el).mouseleave(function() {
$(this).stop(true,true).switchClass("HIGHLIGHT", "", 400, "easeInOutQuad");
});
}
It fires from AJAX result:
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(this);
});
How to code it good? This code is not passing variables from addEventListeners(this); to function.
in the ajax callback function "this" will be the ajax object i think and no longer an element so you need to save "this" in a variable before the ajax starts.
that = this;
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(that);
});
Judging from the context of the rest of your success handler, I assume returned is the DOM element you're attempting to bind your handlers to. Assuming this is the case:
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(data[0]);
// change this ^^^^
// pass the DOM element here, or
// change the addEventListeners function to take a jquery element
});
this in that context is not what you expect it to be. Try this:
var self = this;
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(self);
});

jQuery: Call a function twice

I'm trying to run a function twice. Once when the page loads, and then again on click. Not sure what I'm doing wrong. Here is my code:
$('div').each(function truncate() {
$(this).addClass('closed').children().slice(0,2).show().find('.truncate').show();
});
$('.truncate').click(function() {
if ($(this).parent().hasClass('closed')) {
$(this).parent().removeClass('closed').addClass('open').children().show();
}
else if ($(this).parent().hasClass('open')) {
$(this).parent().removeClass('open').addClass('closed');
$('div').truncate();
$(this).show();
}
});
The problem is on line 13 where I call the truncate(); function a second time. Any idea why it's not working?
Edit jsFiddle here: http://jsfiddle.net/g6PLu/
That's a named function literal.
The name is only visible within the scope of the function.
Therefore, truncate doesn't exist outside of the handler.
Instead, create a normal function and pass it to each():
function truncate() { ...}
$('div').each(truncate);
What's the error message do you get?
You should create function and then call it as per requirement
Define the function
function truncate(){
$('div').each(function(){
});
}
Then call the function
truncate();
Another approach is to establish, then trigger, a custom event :
$('div').on('truncate', function() {
$(this).......;
}).trigger('truncate');
Then, wherever else you need the same action, trigger the event again.
To truncate all divs :
$('div').trigger('truncate');
Similarly you can truncate just one particular div :
$('div#myDiv').trigger('truncate');
The only prerequisite is that the custom event handler has been attached, so ...
$('p').trigger('truncate');
would do nothing because a truncate handler has not been established for p elements.
I know there's already an accepted answer, but I think the best solution would be a plugin http://jsfiddle.net/g6PLu/13/ It seems to be in the spirit of what the OP wants (to be able to call $('div').truncate). And makes for much cleaner code
(function($) {
$.fn.truncate = function() {
this.addClass('closed').children(":not('.truncate')").hide().slice(0,2).show();
};
$.fn.untruncate = function() {
this.removeClass('closed').children().show();
};
})(jQuery);
$('div').truncate();
$('.truncate').click(function() {
var $parent = $(this).parent();
if ($parent.hasClass('closed')) {
$parent.untruncate();
} else {
$parent.truncate();
}
});

Javascript different variable scope on AJAX call

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.

Categories