Global Variable with $(this) - javascript

I am trying to make the coding a lot easier for me and so I assigned a global.
var parent = $(this).parent().parent().parent();
var parentModule = $(this).parent().parent().parent().parent();
And I use these through out my code to make $(this) a lot easier and save on all the parents. Though $(this) would technically be universal being within that certain event (click,hover, and so forth)
Is there a way of actually doing this as I believe it is not possible like the way I write it.
maybe a function or something?
var parent, parentModule = null;
function getParents(e){
parent = $(e.currentTarget).closest(".module");
parentModule = $(e.currentTarget).closest(".module").parent();
}
$(close).on('click',function (e) {
getParents(e);
if (parentModule.hasClass('open')) {
var a = ReadCookie('ToHide');
if (a.split(",").length === 0) {
KillCookie('ToHide');
var b = "#"+parent.attr("id") + " #"+parentModule.attr("id");
SetCookie('ToHide', b, 100);
} else {
var d = a + "," + "#"+ parent.attr("id") + " #"+parentModule.attr("id");
KillCookie('ToHide');
SetCookie('ToHide',d, 100);
}
if(animate===true){
parentModule.fadeOut(function(){
checkIfVisible();
});

If you want to set the values of those global variables using a function, try this:
var parent, parentModule = null;
function getParents(e){
parent = $(e.currentTarget).closest(".yourParentSelector");
parentModule = $(e.currentTarget).closest(".yourParentModuleSelector");
}
$("button").click(function(e){
getParents(e);
//do whatever you want with parent and parentModule variables
});
Use closest() instead of parent()
Here's the FIDDLE

Related

Pass HTML element to JavaScript function

I am passed 3 html elements as parameters to JS function. JS function is in separate file. I have problem to bind 'click' event with _confBtn object (which is parameter). My complete JS file:
window.HAS = window.HAS || {};
HAS.MyApp = HAS.MyApp || {};
(function (_this, $, undefined) {
var _sessionTimeOut = false;
var _startCountDown = false;
var _counterTime;
var _countDownTime;
var _dialogWrap;
var _confBtn;
var _counter;
_this.init = function (showDialogTime, logofCountDownTime, dialogWrap, counter, confirmationButton) {
_counterTime = 5;
_countDownTime = 0;
_dialogWrap = $('#' + dialogWrap);
_confBtn = $('#' + confirmationButton);
_counter = $('#' + counter);
alert(_confBtn.text());
createSessionTimeOut();
$(document).bind("mousemove keypress mousedown mouseup", resetTimeOut);
}
_confBtn.on('click', function () {
window.clearInterval(_startCountDown);
_dialogWrap.css('visibility', 'hidden');
createSessionTimeOut();
$(document).bind("mousemove keypress mousedown mouseup", resetTimeOut);
});
function createSessionTimeOut() {
_sessionTimeOut = window.setTimeout(function () {
_dialogWrap.removeAttr("style");
_counter.text(_counterTime);
$(document).unbind("mousemove keypress mousedown mouseup");
startCountDown();
}, 2000);
}
function startCountDown() {
_startCountDown = window.setInterval(function () {
if (_counterTime >= 0) {
_counter.text(_counterTime--);
}
_countDownTime++;
if (_countDownTime >= 4) {
logOutUser();
return;
}
}, 1000);
}
function resetTimeOut() {
window.clearTimeout(_sessionTimeOut);
_sessionTimeOut = false;
createSessionTimeOut();
}
function logOutUser() {
$.ajax({
url: '/MyApp/Account/LogOut',
type: 'GET',
success: function () {
document.location.href = '/MyApp/Account/Login';
}
})
}
}(window.HAS.MyApp.SessionTimeOut = window.HAS.MyApp.SessionTimeOut || {}, jQuery));
I call in separate page like in following:
SessionTimeOut.init('5', '5', 'dialog-wrap', 'confirm-button', 'counter');
I have issue with _confBtn when I try to call click event. Browser show that is undefined.
Please help.
It would probably better to do something more dynamic like this:
function SomeFunction (element1,element2) {
var e1 = $("#"+element1),
e2 = $("#"+element2);
// Do something with variables e1 and e2
}
and you would call like this:
//html:
<div id="one"><div>
<div id="two"><div>
//javasctript:
SomeFunction('one','two');
No, you are mixing a function declaration with a function call somehow. You can't provide function arguments when defining a function. This however will work fine:
function someFunction($element1, $element2) {
//Do something with the elements
}
someFunction($("#element1"), $("#element2"));
Note that $element1 and $element2 are just variable names, and the leading $ doesn't have anything to do with jQuery. It is just a common convention to identify variables referencing jQuery selections.
You can of course do it, just by using the normal jQuery way of including multiple selectors. Your code is slightly incorrect because you are actually only defining the function without calling it, and you are not supposed to pass arguments/variables into the function when defining it.
Unless you have the intention to distinguish between two groups of elements, I would refrain from declaring elements individually as you have used in your question, because sometimes you will never know the length of the selected items.
function someFunction($ele) {
// jQuery objects will be accessible as $ele
}
// Call the function
someFunction($('#selector1, #selector2'));
However, if the former is the case, you can always do so:
function someFunction($ele1, $ele2) {
// jQuery objects will be accessible as $ele1 and $ele2 respectively
// Example: $ele1.hide();
// $ele2.show();
}
// Call the function
someFunction($('#selector1'), $('#selector2'));
For example, you can refer to this proof-of-concept JSfiddle: http://jsfiddle.net/teddyrised/ozrfLwwt/
function someFunction($ele) {
// jQuery objects will be accessible as $ele
$ele.css({
'background-color': '#c8d9ff'
});
}
// Call the function
someFunction($('#selector1, #selector2'));
If you want to pass some elements to function you can use jQuery constructor to standardize arguments
function SomeFunction (element1,element2) {
element1 = $(element1);
element2 = $(element2);
// and you have 2 jQuery objects...
}
// and now you can pass selector as well as jQuery object.
SomeFunction($('div.a'),'#b');
You can pass paramters as much as you want this way. I use jQuery in this code and created a simple function.
var item=$("#item-id");
var item1=$("#item1-id");
makeReadOnly(item,item1);
function makeReadOnly(){
for(var i=0;i<arguments.length;i++){
$(arguments[i]).attr("readonly", true);
}
}

How to make properties and functions private in JavaScript?

I developed this short script but I'm wondering what is the best way to make $ul, $el and some functions e.g. select private. At the moment these are part of public interface but I would like to hide these. Wrap into another function returning DropDown object maybe? What would be the proper way to do this? Code below:
namespace = {};
namespace.DropDown = function(el) {
this.$el = $(el)
this.$trigger = this.$el.find(".trigger");
this.$ul = this.$el.find("ul");
this.$li = this.$ul.find("li");
this.$trigger.text(this.$ul.find(".selected").text());
this.$trigger.on("click", $.proxy(this.open, this));
}
namespace.DropDown.prototype.open = function(e) {
e.stopImmediatePropagation();
this.$ul.addClass("open");
// position selected element in the middle
var scrollUp,
panelCenter = this.$ul.scrollTop() + (this.$ul.innerHeight() / 2),
selectedPositionTop = this.$ul.scrollTop() + this.$ul.find(".selected").position().top;
if (selectedPositionTop > panelCenter) {
scrollUp = selectedPositionTop - panelCenter;
this.$ul[0].scrollTop = this.$ul[0].scrollTop + scrollUp;
} else {
scrollUp = panelCenter - selectedPositionTop;
this.$ul[0].scrollTop = this.$ul[0].scrollTop - scrollUp;
}
// position elements whole container (list container)
var triggerTop = this.$trigger.offset().top + (parseInt(this.$trigger.css("padding-top")) || 0) + (parseInt(this.$trigger.css("border-top") || 0)),
t = Math.abs(triggerTop - this.$ul.find(".selected").offset().top);
this.$ul.css("top", -t + "px");
this.$li.one("click", $.proxy(this.select, this));
$(document).one("click", $.proxy(this.close, this));
}
namespace.DropDown.prototype.close = function() {
this.$li.off("click");
this.$ul.removeClass("open");
this.$ul.css("top", "0px");
}
namespace.DropDown.prototype.select = function(e) {
$(document).off("click");
e.stopImmediatePropagation();
this.$li.removeClass("selected");
$(e.target).addClass("selected");
this.$trigger.text(this.$ul.find(".selected").text());
this.close(e);
}
$(function() {
new namespace.DropDown($(".dropdown")[0]);
new namespace.DropDown($(".dropdown")[1]);
new namespace.DropDown($(".dropdown")[2]);
});
EDIT:
I managed to wrap it into another function so I could get the properties and functions e.g. $ul, select off the protootype and make private via closure. It does work and I am able to keep guts of the object private but is this the best way to got? it seems overly complicated to me. Also I'm sure I'm not the first to come up with this and so is there a name for this pattern? Modified code below:
namespace = {};
namespace.DropDown = function(el) {
var $el = $(el),
$trigger = $el.find(".trigger"),
$ul = $el.find("ul"),
$li = $ul.find("li");
DropDown = function() {
$trigger.text($ul.find(".selected").text());
$trigger.on("click", $.proxy(this.open, this));
}
function select(e) {
$(document).off("click");
e.stopImmediatePropagation();
$li.removeClass("selected");
$(e.target).addClass("selected");
$trigger.text($ul.find(".selected").text());
this.close(e);
}
DropDown.prototype.open = function(e) {
e.stopImmediatePropagation();
$ul.addClass("open");
// position selected element in the middle
var scrollUp,
panelCenter = $ul.scrollTop() + ($ul.innerHeight() / 2),
selectedPositionTop = $ul.scrollTop() + $ul.find(".selected").position().top; //- $ul.find(".selected").outerHeight();
if (selectedPositionTop > panelCenter) {
scrollUp = selectedPositionTop - panelCenter;
$ul[0].scrollTop = $ul[0].scrollTop + scrollUp;
} else {
scrollUp = panelCenter - selectedPositionTop;
$ul[0].scrollTop = $ul[0].scrollTop - scrollUp;
}
// position elements whole container (list container)
var triggerTop = $trigger.offset().top + (parseInt($trigger.css("padding-top")) || 0) + (parseInt($trigger.css("border-top") || 0)),
t = Math.abs(triggerTop - $ul.find(".selected").offset().top);
$ul.css("top", -t + "px");
$li.one("click", $.proxy(select, this));
//$ul[0].scrollTop = this.scrollPos;
$(document).one("click", $.proxy(this.close, this));
}
DropDown.prototype.close = function() {
$li.off("click");
$ul.removeClass("open");
$ul.css("top", "0px");
}
return new DropDown();
};
$(function() {
new namespace.DropDown($(".dropdown")[0]);
new namespace.DropDown($(".dropdown")[1]);
new namespace.DropDown($(".dropdown")[2]);
});
EDIT 2:
I should have mentioed that I want to keep the methods on prototype rather than directly on the object itself via this.functionname. I want to avoid method duplication as this will happen if these are attached to this directly. For this simple reason this question is not duplicate.
You can create private methods and variables via closures, however another approach which may be simpler and create more fluid / cleaner reading code could be to designate private/public via convention. For example:
this._privateVariable = true;
this.publicVariable = true;
using underscores for private, no underscore for public etc.. /edited thanks HMR
This is the general form for making public and private attributes
var MyClass = (function(){
var myclass = function(){}
var privateMethod = function(){ return 1; }
myclass.prototype.publicMethod = function(){ return privateMethod() + 1; }
return myclass;
})();
Properties that are put on myclass, or on myclass.prototype, will public. However, variables that are declared with var will not be publicly available, though other methods will still have access to them. In the above example, publicMethod is the only publicly available method, but it is able to call privateMethod, because they were defined in the same scope.
like this also:
function SampleClass() {
// private
var _type = 'aClass';
// private
var _dothis = function (action) {
return 'i did this ' + action;
};
return {
// public
type: _type,
// public
dothis: function (action) {
return _dothis(action);
}
};
}

Javascript creating function to share variables between other functions

I have a couple click functions with jQuery that share the same variables, so I created a function to return those variables.
While this works, I'm wondering whether programmatically speaking this is the right or most efficient way to do this:
function clickVars($me){
var $curStep = $('.cust-step-cur'),
$nextStep = $curStep.next('.cust-step'),
nextStepLen = $nextStep.length,
$list = $('.cust-list'),
$btnCheck = $('.cust-btn.checklist'),
hasChecklist = $me.hasClass('checklist');
return {
curStep: $curStep,
nextStep: $nextStep,
nextStepLen: nextStepLen,
list: $list,
btnCheck: $btnCheck,
hasChecklist: hasChecklist
};
}
// Checklist Click
$('.option-list a').on('click',function(){
var $me = $(this),
myVars = clickVars($me);
currentStepOut(myVars.curStep);
myVars.curStep.removeClass('cust-step-cur');
currentStepIn(myVars.nextStep, myVars.list, myVars.btnCheck);
});
// Navigation
$('.cust-btn').on('click',function(){
if(animReady === false)
return false;
var $me = $(this),
myVars = clickVars($me);
if(myVars.hasChecklist && myVars.list.hasClass('cust-step-cur'))
return false;
currentStepOut(myVars.curStep);
myVars.curStep.removeClass('cust-step-cur');
if(myVars.nextStepLen === 0 || $me.hasClass('checklist')) {
myVars.nextStep = myVars.list;
}
animReady = false;
currentStepIn(myVars.nextStep, myVars.list, myVars.btnCheck);
});
Is this a standard way of generated shared variables between multiple functions?
In AS3 it's good practice to do:
// Variable definitions
var enabled:Boolean = false;
public function myFunction(){
enabled = true;
}
So in JavaScript I've been doing:
// Variable defintions
var a,b,c,d,e = 0;
function alterVariables(){
a = 1;
b = 2;
}
You have to understand you are not sharing variables between functions. Moreover, each time you click those elements, clickVars function is called again and again, even if you click only one element multiple times. So this code is very bad expirience. Check this:
// Defined ones
var nodes = {
$elements : $('.elements'),
$otherElements : $('.otherElements'),
}
// In case you have multiple .selector elements in your DOM
$('.selector').each(function() {
// Defined ones for each element
var $element = $(this), isList = $element.hasClass('.list');
$element.bind('click', function(){
nodes.$elements.addClass('clicked');
});
});
$('.anotherSelector').each(function() {
// Yep, here is some duplicate code. But there won't be any
// performance improvement if you create special method for
// such small piece of code
var $element = $(this), isList = $element.hasClass('.list');
$element.bind('click', function(){
nodes.$elements.addClass('clicked');
});
});

Javascript namespace issue, how do i get this value within this function call

im just not sure how to get the desired value within this function Thanks!
temp = exotics[i].split(',');
if ($.inArray(temp[0], tblProbables) != -1) {
item = $("<li><a id='" + temp[0] + "'" + "href='#' >" + temp[1] + "</a></li>");
item.click(function () { GetProbable(temp[0]); });
}
temp[0] is blank because it doesn't exist within that function space.... so how can i setup the click event so that it calls the function with the proper param?
I have a feeling you're reusing the temp variable somehow.
If so, you can just create a new variable scope in a function that returns a function that references the proper scoped variable.
function createHandler( temp ) {
return function () { GetProbable(temp); };
}
item.click( createHandler(temp[0]) );
Store the value in a temporary variable:
....
var temp0 = temp[0];
item.click(function () { GetProbable(temp0); });
If the the temp0 varible changes multiple times (e.g. in a loop), create a closure:
(function(temp0){ //Inside this function, it doesn't matter if `temp` changes
item.click(function () { GetProbable(temp0); });
})(temp[0]);

Jquery .each() Scope Problem (bug?)

For some reason my call to nested jQuery.each() functions are losing scope for some variables, but not others. In the code below, the Client.KNE reference works, but ClientDiv does not, even though prior to that each, both are defined, populated variables...
By switching Client and ClientDiv to global variables, it works, but I feel like I should not have to create global variables here...
Doesn't Work:
jQuery.each(Messages.Additions, function (clientIndex) {
var Client = Messages.Additions[clientIndex];
var ClientDiv = $("#clientTitle_" + Client.ClientID);
if (ClientDiv.length == 0) {
$("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
} else {
jQuery.each(Client.KNE, function (kneIndex) {
var KNE = Client.KNE[kneIndex]; // Works
var KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE); // DOES NOT WORK
Does Work:
jQuery.each(Messages.Additions, function (clientIndex) {
Client = Messages.Additions[clientIndex];
ClientDiv = $("#clientTitle_" + Client.ClientID);
if (ClientDiv.length == 0) {
$("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
} else {
jQuery.each(Client.KNE, function (kneIndex) {
KNE = Client.KNE[kneIndex]; // Works
KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE); // Works
Anyone know what I'm doing wrong in the first version? Or is this a bug? Why does the one variable work but the other doesn't...
From here: Jquery $().each method obscures 'this' keyword it looks like I could pass the variables into the function call, but should I have to?
Tried the above link, and it is not working:
jQuery.each(Messages.Additions, function (clientIndex) {
var Client = Messages.Additions[clientIndex];
var ClientDiv = $("#clientTitle_" + Client.ClientID);
if (ClientDiv.length == 0) {
$("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
} else {
jQuery.each(Client.KNE, function (kneIndex, Client, ClientDiv) {
var KNE = Client.KNE[kneIndex];
var KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE); //Does not work - ClientDiv undefined
Similar questions without satisfactory answer:
Scope of jQuery each() function?
SOLUTION
$.each(Messages.Additions, function () {
var $Client = this;
var $ClientDiv = $("#clientTitle_" + $Client.ClientID);
if (!$ClientDiv.length) {
$("#ClientTemplate").tmpl($Client).appendTo("#ClientContainer");
} else {
$.each($Client.KNE, function () {
var $KNE = this;
var $KNEDiv = $ClientDiv.find("#kneTitle_" + jq($KNE.KNE));
// SWITCHED TO $ PREFIX
You can try this using this keyword which points to the current item in the loop. Instead of checking for if (ClientDiv == null) you should check for if (ClientDiv.length > 0) because jQuery returns am empty object if it do not finds the element so that check will fail.
var additions;
jQuery.each(Messages.Additions, function () {
var $clientDiv = $("#clientTitle_" + this.ClientID);
if ($clientDiv.length == 0) {
$("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
} else {
jQuery.each(Client.KNE, function () {
$clientDiv.find("#kneTitle_" + this.KNE);
});
}
});

Categories

Resources