How to check if object is undefined/null - javascript

This question has come up a lot but I can't make it work.
I have 5 divs, I want to hide the div before the last one who was used. So If the user clicks somewhere in div 1, and then clicks somewhere in div 2, div 1 fades out (all of this after an Ajax call)
Here's my code:
$(document).ready(function() {
$("#[id^='r_form_']").bind("ajax:success", function(evt, data, status, xhr) {
var $form = $(this);
$(this).parent().css("background", "green");
if($lastForm == null) {
var $lastForm = $(this);
};
if(!($lastForm[0] == $form[0])) {
$lastForm.parent().fadeOut(1500);
var $lastForm = $(this);
};
});
});
If the variable $lastForm is undefined, assign the current form where Ajax happenned.
The variable is always undefined. I added an alert('undefined') in the loop, i always get it. why?
I have a feeling it might be because the variable is reset when the Ajax request comes back. But i'm not really an expert and can't seem to find the answer.

I think it's because it's declared in inner scope. move the declaration to outside of the function. each function create a new scope, so it's not saved to the next call:
Code:
$(document).ready(function() {
var $lastForm; //<===================
$("#[id^='r_form_']").bind("ajax:success", function(evt, data, status, xhr) {
var $form = $(this);
$(this).parent().css("background", "green");
if ($lastForm == null) {
$lastForm = $(this);
};
if (!($lastForm[0] == $form[0])) {
$lastForm.parent().fadeOut(1500);
$lastForm = $(this);
};
});
});​
As commented by #minitech the # in the selector: #[id^='r_form_'] looks like it shouldn't be there.

if(typeof e === 'undefined') {
// your code here
}

Related

How can I use variables only once with 'on mouseenter' and 'on mouseleave'?

I have multiple objects with different sizes that I want each to display additional box on mouseenter and hide on mouseleave. I have a jquery script that does it perfectly, my only concern is that I am repeating variables twice and something tells me that this can be done without repeating myself.
Problem is they both are strongly based on $(this) core element, so I can't make variables global. My guess was that I should put them withing the element container function, right before on mouseenter and on mouseleave are called, but syntax wise I have no idea how to do it. But again, I might be terribly wrong on that.
Here's the code:
$(document).ready(function() {
$('.box-options').hide();
var $boxModule = $('div.box');
$boxModule.on({
mouseenter: function() {
var $this = $(this), // repeat
$options = $this.find('div.options'), // repeat
$optionsBox = $this.find('div.options-box'); // repeat
var boxHeight = $this.height(), // repeat
boxWidth = $this.width(), // repeat
optionsBoxHeight = $optionsBox.outerHeight(); // repeat
if ( // statement referring to variables above }
else { // statement referring to variables above };
$options.fadeIn(200).addClass('shadow').css({"height" : boxHeight + optionsBoxHeight});
$optionsBox.delay(100).fadeIn(200).css({"top" : boxHeight}, 200);
},
mouseleave: function() {
var $this = $(this), // repeat
$options = $this.find('div.options'), // repeat
$optionsBox = $this.find('div.options-box'); // repeat
var boxHeight = $this.height(), // repeat
boxWidth = $this.width(), // repeat
optionsBoxHeight = $optionsBox.outerHeight(); // repeat
$optionsBox.hide().css({"top" : boxHeight});
$options.hide().removeClass('shadow').css({"height" : boxHeight}, 200);
}
});
});
Obviously the code contains more lines, but the important part is variables marked as // repeat. Does anyone know how I can re-structure the code to make variables be written only once?
UPDATE: I updated the code to describe logic better. Just to make it clear, on each page there are also multiple objects with identical classes, structure and size, only difference is content (text) within and id number.
Use hover function and for variables declare them before hovering event like you have done for $boxModule.
Calling
$( selector ).hover( handlerIn, handlerOut )
is shorthand for:
$( selector ).mouseenter( handlerIn ).mouseleave( handlerOut );
I think the solution for repetition in that code would be to create an external function to get some of the information from the element passed as an argument.
For example:
function options($element) {
return $element.find('div.options');
}
The same goes for every other property based on $(this).
Then you can just use your options inside your event handler as such: options($this).fadeIn(200)
Hope this helps to clean your code.
You can declare var outside on event like :
$('div.box').each(function(){
var $this = $(this),
$options = $this.find('div.options'),
$optionsBox = $this.find('div.options-box'),
boxHeight = $this.height();
$this.on({
mouseenter: function() {...}
mouseleave: function() {...}
});
});
How about making a function that return an object that you can use in every handler?
var calcVars = function(){
var $this = $(this),
$options = $this.find('div.options'),
$optionsBox = $this.find('div.options-box');
var boxHeight = $this.height(),
boxWidth = $this.width(),
optionsBoxHeight = $optionsBox.outerHeight();
return {
boxHeight: boxHeight,
//every other variable you need outside
}
$boxModule.on({
firstEvent: function() {
var object = calcVars.call(this);
object.calculatedProperty.doSomething();
//other code
},
secondEvent: function() {
var object = calcVars.call(this);
object.anotherCalculatedProperty.doSomething();
//other code
}
})
or you can do:
$boxModule.on("anEvent anotherEvent", function(event) {
/*
var declarations
*/
var $this = $(this),
//etc..
if(event.type == "anEvent"){
doStuff();
else if(event.type == "anotherEvent"){
doOtherStuff();
}
})

Running a form handled by ajax in a loaded ajax page?

Using tutorials found i'm currently loading new pages with this:
$("a.nav-link").click(function (e) {
// cancel the default behaviour
e.preventDefault();
// get the address of the link
var href = $(this).attr('href');
// getting the desired element for working with it later
var $wrap = $('#userright');
$wrap
// removing old data
.html('')
// slide it up
.hide()
// load the remote page
.load(href + ' #userright', function () {
// now slide it down
$wrap.fadeIn();
});
});
This loads the selected pages perfectly, however the pages have forms that themselves use ajax to send the following:
var frm = $('#profileform');
frm.submit(function (ev) {
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
success: function (data) {
alert(data)
}
});
However this is not sending the form as it did before the page itself was called to the parent page via ajax. Am I missing something? Can you not use an ajax call in a page already called by ajax?
I also have other issues, for example I disable the submit button unless there are any changes to the form, using:
var button = $('#profile-submit');
var orig = [];
$.fn.getType = function () {
return this[0].tagName == "INPUT" ? $(this[0]).attr("type").toLowerCase() : this[0].tagName.toLowerCase();
}
$("#profileform :input").each(function () {
var type = $(this).getType();
var tmp = {
'type': type,
'value': $(this).val()
};
if (type == 'radio') {
tmp.checked = $(this).is(':checked');
}
orig[$(this).attr('id')] = tmp;
});
$('#profileform').bind('change keyup', function () {
var disable = true;
$("#profileform :input").each(function () {
var type = $(this).getType();
var id = $(this).attr('id');
if (type == 'text' || type == 'select') {
disable = (orig[id].value == $(this).val());
} else if (type == 'radio') {
disable = (orig[id].checked == $(this).is(':checked'));
}
if (!disable) {
return false; // break out of loop
}
});
button.prop('disabled', disable);});
However this also doesn't work when pulled to the parent page. Any help much appreciated! I'm really new to ajax so please point out any obvious mistakes! Many thanks in advance.
UPDATE
Just an update to what i've found. I've got one form working by using:
$(document).on('mouseenter', '#profile', function() {
However the following:
$(document).on('mouseenter', '#cancelimage', function() {
$('#cancelimage').onclick=function() {
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
} }; });
Is not working. I understand now that I need to make it realise code was there, so I wrapped all of my code in a mouseover for the new div, but certain parts still don't work, so I gave a mouseover to the cancel button on my image form, but when clicked it doesn't do any of the things it's supposed to.
For anyone else who comes across it, if you've got a function name assigned to it, it should pass fine regardless. I was trying to update it, and there was no need. Doh!
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
};
Works just fine.

Wait for all async functions to complete in jQuery

I'm filtering table using jQuery and all is well. This code works nicely:
$("*[id$='EquipmentTypeDropDownList']").change(filterTable);
$("*[id$='StateDropDownList']").change(filterTable);
function filterTable() {
var $equipmentDropDown = $("*[id$='EquipmentTypeDropDownList']");
var $stateDropDown = $("*[id$='StateDropDownList']");
var equipmentFilter = $equipmentDropDown.val();
var stateFilter = $stateDropDown.val();
$("tr.dataRow").each(function () {
var show = true;
var equimpent = $(this).find("td.equipment").text();
var state = $(this).find("td.readyState").text();
if (equipmentFilter != "Any" && equipmentFilter != equimpent) show = false;
if (stateFilter != "Any" && stateFilter != state) show = false;
if (show) {
$(this).fadeIn();
} else {
$(this).fadeOut();
}
});
$("table").promise().done(colorGridRows);
}
function colorGridRows() {
//for table row
$("tr:visible:even").css("background-color", "#DED7D1");
$("tr:visible:odd").css("background-color", "#EEEAE7");
}
colorGridRows function changes background color of even/odd rows for readability
Now, It would be nice if I can replace show/hide calls with fadeIn/fadeOut but I can't because coloring doesn't work (it runs before UI effect completed. If it was just one function parameter - I would just create function for completion and be done with it. But my table has many rows and loop runs through each. How do I wait for ALL to compelete?
EDITED: Code sample updated showing how I try to use promise() but it doesn't work. It fires but I don't get odd/even coloring.
Use the promise object for animations.
$("*[id$='StateDropDownList']").change(function () {
var filtervar = $(this).val();
$('tr td.readyState').each(function () {
if (filtervar == "Any" || $(this).text() == filtervar) {
$(this).parent().fadeIn();
} else {
$(this).parent().fadeOut();
}
}).parent().promise().done(colorGridRows);
//colorGridRows();
});

Keeping variables between function executions (Javascript)

I have a JavaScript function that runs every time one of the many links is clicked. The functions first checks what the id of the link clicked is, then it runs an if stement. depending on the id of the link, different variables are defined.
All this works, but the problem is that some links define one variable while other links define another, I need to keep the variables defined in previous executions of the function defined for other executions of the function.
An example follows:
$(document).ready(function()
{
$(".sidebar a").click(function(event) {
event.preventDefault()
var targetID = $(this).attr("data-target")
$("#" + targetID).attr("src", $(this).attr("href"))
var element = $(this).attr("class")
if (element == "submit") {
var submit = $(this).attr("user")
alert("1")
} else if (element == "view") {
var view = $(this).attr("user")
alert("2")
}
})
window.history.replaceState({}, 'logs', '/file/path?submit=' + submit + '&' + 'view=' + view)
})
Thanks
You can use an outer function which does nothing but declare some variables and return an inner function. The inner function can access the variables from the outer scope which stay the same for every call of the function.
Example
var next = (function() {
var value = 0;
function next() {
return value++;
}
}());
console.log(next());
console.log(next());
console.log(next());
Live demo
http://jsfiddle.net/bikeshedder/UZKtE/
Define the variables in an outer scope:
$(document).ready(function () {
var submit;
var view;
$(".sidebar a").click(function (event) {
event.preventDefault();
var targetID = $(this).attr("data-target");
$("#" + targetID).attr("src", $(this).attr("href"));
var element = $(this).attr("class")
if (element == 'submit') {
submit = $(this).attr("user")
alert("1")
} else if (element == 'view') {
view = $(this).attr("user")
alert("2")
}
});
});
Create var submit and view outside of the function so it has a global scope.
You can store arbitrary data on a matched element with JQuery's .data() function.
Example:
$(this).data("submit", $(this).attr("user")); // set a value
var submit = $(this).data("submit"); // retrieve a value
This places the data in the context of JQuery's knowledge of the element, so it can be shared between function calls and even between different events.

jQuery pass $this to function parameter

I have:
<img id="leftBubble" class="bubbles" src="left.png" />
<img id="rightBubble" class="bubbles" src="right.png" />
And a hover event like so:
$(".bubbles").each(function(){
$(this).hover(function() {
pause($(this));
}, function() {
play(4000, $(this));
});
});
My pause() function does not seem to be working
function pause(pauseMe) {
if (pauseMe == $("#leftBubble")) {
clearTimeout(timer1); //this is never reached
} else if (pauseMe == $("#rightBubble")) {
clearTimeout(timer2); //nor this
}
}
Any idea to make the hover event pass $this as the parameter for the pause function?
Each time you call $, it returns a different result set object, even if the result contents are the same. The check you have to do is:
if (pauseMe.is("#leftBubble")) {
Try like below,
function pause(pauseMe) {
if (pauseMe == "leftBubble") {
clearTimeout(timer1);
} else if (pauseMe == "rightBubble") {
clearTimeout(timer2);
}
}
and in the caller,
$(".bubbles").each(function(){
$(this).hover(function() {
pause(this.id);
}, function() {
play(4000, $(this));
});
});
In javascript, this is redefined each time you enter a new function definition. If you want to access the outside this, you need to keep a reference to it in a variable (I used the self) variable.
$(".bubbles").each(function(){
var self = this;
$(this).hover(function() {
pause($(self));
}, function() {
play(4000, $(self));
});
});
I don't know if your comparison between jQuery objects will work though. Maybe you can compare the DOM elements: pauseMe[0] == $("#leftBubble")[0], or, as mentioned, the ids.
When you call $( ... ) it generates new object that not the same that was genereted when you call $( ... ) last time, with same parametrs.
Anyway, you can't compare objects with == in javascript. It returns true only if it liks on same object.
a = {b:1}
c = {b:1}
d = c
a == b // false
d == c // true

Categories

Resources