So I found an awesome solution to get around needing to use Global variables in jQuery here. Everywhere I say namespace, originally I was going to use a Global var.
However I'm not able to send my namespace variable through a param on a simple click function.
I want to do this because I have these variables that need to be saved and used to create modal windows as well as to let the app know what dynamically created buttons control what modal.
So below is an example of my namespace object where I first create the variables
My jQuery namespace object:
$.reg = {
masterRole : " ",
role_ID : " ",
row_Name : " ",
ary_Check_Role : []
};
$(document).ready(function () {
...
As you go through the app the values for those namespace variables get set when you click this button (grabs data from HTML)
Variables are set on my roleBtnClicked function
function roleBtnClicked(event){
$.reg.masterRole = $(this).html(); /* Get role name: Actor */
$.reg.role_ID = $(this).attr('role'); /* Get role-1 */
$.reg.rowName = $(this).attr('row'); /* Get row-role-1 */
$.reg.blueBtn = $(this).attr('blue'); /* Get blue-btn-1 */
Now a modal window pops up, after clicking some checkboxes and pushing data into an array, when you click the done button(below) all the variables need to be saved into the namespace vars again.
My done button click Function, where I'm trying to pass my namespace variables via param vars
$(".doneButton").click(
{
param1: $.reg.masterRole,
param2: $.reg.role_ID,
param3: $.reg.rowName,
param4: $.reg.ary_Check_Role
},
doneBtnClicked);
function doneBtnClicked(event){
alert('$.reg.roleName = '+$.reg.roleName);
alert('event.data.param1 = '+event.data.param1);
masterRole= event.data.param1;
role_ID = event.data.param2;
rowName = event.data.param3;
ary_Check_Role = event.data.param4;
Note the 2 Alerts above in the click function, the first one will display the correct value, however the 2nd one doesn't display anything. Also Having a problem getting the Array to come through as well.
So questions: Should I be doing it this way? How do you pass an Array into a jQuery namespace correctly and then get it passed into a click function param?
First off, you should avoid putting things into the jQuery object. Use closures for that.
Second: You should use HTML data-... attributes and jQuery data() to attach custom properties to HTML elements. Avoid using non-standard properties.
Third: You can use separate named function definitions for event handlers, but it makes most sense when you actually re-use those functions for different elements across your code (you don't seem to do that). Using anonymous functions that you pass directly to .click(), for example, results in more understandable code.
// use this shorthand instead of $(document).ready(function () { ... });
$(function () {
// variable reg will be available to all functions
// defined within this outer function. This is called a closure.
var reg = {
masterRole : " ",
role_ID : " ",
row_Name : " ",
ary_Check_Role : []
};
$(".roleButton").click(function (event) {
// modify state
reg.masterRole = $(this).html(); /* Get role name: Actor */
reg.role_ID = $(this).data('role'); /* Get role-1 */
reg.rowName = $(this).data('row'); /* Get row-role-1 */
reg.blueBtn = $(this).data('blue'); /* Get blue-btn-1 */
// note that this requires markup like this:
// <button data-role="foo" data-row="bar" data-blue="baz">
// ...
});
$(".doneButton").click(function (event) {
// debug output
alert(JSON.stringify(reg, 2, 2));
});
});
Use multiple $(function () { ... }); blocks to separate things that should be separate.
Don't forget to always use var for every variable you declare. Variables declared without var will be global - and you don't want global variables.
Related
I use Jquery in my angular project.I try to access the value of this.selectedUrl but when it jumps into the Jquery ready function it gives UNDEFINED.How to do it?
this.selectedUrl = this.router.url
console.log("this.selectedUrl",this.selectedUrl) // gives value i.e /home
$(document).ready(function () {
console.log("this.selectedUrl",this.selectedUrl) // gives undefiend
if(this.selectedUrl=="/home"){
console.log("this.selectedUrlIf",this.selectedUrl)
}
});
First is angular does not need jquery to handle any functionalities. Still , in this case you are getting undefined because using of function key word with $(document). Inside $(document).ready(function () this will get a complete new scope and it does not know what is selectedUrl. You can explore arrow function
this takes a completely different value inside ready function unless you bind this to the function
For example:
this.selectedUrl = this.router.url
console.log("this.selectedUrl",this.selectedUrl) // gives value i.e /home
$(document).ready(function () {
console.log("this.selectedUrl",this.selectedUrl) // this is now available
if(this.selectedUrl=="/home"){
console.log("this.selectedUrlIf",this.selectedUrl)
}
}.bind(this));
or use the ES6 arrow functions which take this from the parent scope
this.selectedUrl = this.router.url
console.log("this.selectedUrl",this.selectedUrl) // gives value i.e /home
$(document).ready(()=>{
console.log("this.selectedUrl",this.selectedUrl) // this is now available
if(this.selectedUrl=="/home"){
console.log("this.selectedUrlIf",this.selectedUrl)
}
});
a third option is to store this to another variable and refer to that variable instead. For example:
var that = this; // store to variable
this.selectedUrl = this.router.url
console.log("this.selectedUrl",this.selectedUrl) // gives value i.e /home
$(document).ready(function () {
console.log("this.selectedUrl",that.selectedUrl) // this is now available via that variable
if(that.selectedUrl=="/home"){
console.log("this.selectedUrlIf",that.selectedUrl)
}
});
Explanation: this is a unique variable from the rest (in Object-Oriented Programming). It gets re-assigned to different values (with same name this) based on which function scope it is used. So to keep this to refer to a specific instance inside another function you need to follow one of the approaches above.
I have 2 JS files - one with the functions I would like to access and the other that I'd like to call the function with.
(function($) {
var Place = function() {
var Location = function(id, duration, check) {
//Should access this function
}
}
})(jQuery);
I'm trying to access it with:
Place.Location(markerId, 600);
But all I'm getting is that it's not defined. Simple issue but can't quite figure this one out.
As it's a jQuery plugin, maybe there's a way I can access it via another method?
$.fn.place = function(params) {
var len = this.length;
return this.each(function(index) {
var me = $(this),
key = 'place' + (len > 1 ? '-' + ++index : ''),
instance = (new Place).init(me, params);
});
};
The way you are defining Location, it is a private variable inside the function Place. If you want to access it as an attribute of Place, you should replace var Location = ... with this.Location = ...
It's going out of scope. Because you wrapped your Place object in function($) {}, now anything outside that wrapper will no longer have access to variables inside the wrapper. If $ stands for jQuery, it should be a global anyways and you can take the wrapper out.
The solution is a combination of the other two answers.
You define Place as a variable in the (anonymous) function. It can't be used outside the scope of that function. (This function doesn't use jQuery, either, so the wrapper is unnecessary).
Place is a function. It executes code that sets local variable Location to a function, but doesn't export that function, so Location() is inaccessible outside the Place function.
You probably mean to make Place an object (instead of a function), and give it a Location method. Here's one way to write it:
var Place = {
Location: function(id, duration, check) {
// do something with id, duration, & check
}
};
// execute
Place.Location(someId, someDuration, someCheck);
(It doesn't look like you've posted all your code, like the Place.init() method, but there are plenty of ways to write this so that it works correctly; this should solve your immediate problem.)
I am building a small app which is part of a sales-enquiry process. It has 'pages' which the visitor progresses through. I have laid out these pages as part of a large object literal. In the following code, branch-select is one of those pages. As you can see, the init() function sets a sibling value by using this to refer to the parent branch-select. However, the save() function is called from a click event, so instead of using this, it seems I have to laboriously write out the full object reference each time to set values? Please see the code & comments below to illustrate the problem:
// This is part of a larger object called "stepData"
"previous page": {
// ...
}
"branch-select": {
ref: "Select Type",
visited: false,
init: function(){
this.visited = true; // Here I can use "this" to set other values in the parent object
// ....
},
next: "",
save: function(){
branchKey = $(this).attr('data-value'); // this function is invoked from a click event, so "this" refers to the DOM element that was clicked. Therefore throughout the rest of the function if I want to set values on the parent object, I have to write out the full object reference each time...
switch(branchKey){
case "Lodges":
stepData['branch-select'].ref = "Lodges";
stepData['branch-select'].values[0].a = "Lodges";
stepData['branch-select'].next = "lodge-2"; // Do I really have to write out stepData['branch-select'] each time?
break;
case "Caravans":
stepData['branch-select'].ref = "Caravans";
stepData['branch-select'].values[0].a = "Caravans";
stepData['branch-select'].next = "van-2";
break;
}
stepData[stepData['branch-select'].next].init();
}
},
"next page": {
// ...
}
In the interests of DRY (Don't repeat yourself) code, I was wondering if there is any neat solution to this?
EDIT:
Webkit's answer presents a new problem; the clicked DOM element (.branch-select) is dynamically introduced, so to bind the click event, I have to use:
$("#template-holder").on('click', ".branch-select", stepData['branch-select'].save);
(template-holder is the parent element which is always present). How would I integrate the call() method into the above code?
Another way to have "this" reference your object when handling an event is using 'call'.
for example:
var setData = {
save: function(){
// 'this' shall be setData!
var _bs = this['branch-select'];
_bs.ref = "Lodges"...
}
}
then:
$(".someElement").on('click', function() {
setData.save.call(setData)
});
**updated (I'm pretty sure this should work just the same):
$("#template-holder").on('click', ".branch-select", function() {
stepData['branch-select'].save.call(setData)
});
I am trying to use enquire.js to trigger a reload of my bxslider when the screen size is small, to show fewer images.
I have registered a screen width as below.
enquire.register("screen and (max-width:900px)", {
match: this.ChangeSliderDown,
unmatch:this.ChangeSliderUp
});
Now as part of the transition i need to do a calculation based on a variable that is associated with the Prototype of the current class.
ChildCarousel.prototype = {
...
ChangeSliderUp: function()
{
var maxSlides = (this.ourCarouselCollection.length < 3) ? 1 : 3;
...
}
}
in all my other functions referring to this allows me to access variables such as the ourCarouselCollection in the instance of enguire js i get the object that is a result of the register call.
why is this happening and is it possible to change it?
adding the bind(this method solved the problem
enquire.register("screen and (max-width:900px)", {
match: this.ChangeSliderDown.bind(this),
unmatch:this.ChangeSliderUp.bind(this)
});
The value of this has nothing to do with scope, it is resolved within an execution context and is set by the call or with bind. Also, it is convention that only functions that are intended to be called as constructors have names that start with a capital letter (so ChangeSliderUp should be changeSliderUp).
The ChangeSliderUp method is expecting to be called with this referencing an instance of ChildCarousel as its this. When you assign a reference to the function like:
match: this.ChangeSliderDown
then the function will be called without this being set to the instance and will default to the global object or be undefined in strict mode.
You can use bind per Bluephlame's answer, or use a closure something like:
// Assuming that this referenes an instance of ChildCarousel
// where this code is running
var carousel = this;
enquire.register("screen and (max-width:900px)", {
match: function() {carousel.ChangeSliderDown();},
unmatch: function() {carousel.ChangeSliderUp();}
});
but I can't test that. It should ensure that the function is called as a method of an instance, hence setting this to the instance.
Here is the problem:
I have a very complex plugin that does lots of different initialization and binding when it is executed.
I want to be able to run the same plugin multiple times on the same element, giving it different options. After it runs once on the element, certain initialization does not need to be done again on subsequent executions on that element.
Currently the plugin code is inside of a closure and it doesnt know anything about other times the same plugin has run on the element.
Is there a pattern that people follow when they want inter-communication?
I am thinking of something like this:
$.plugin = {
globalRefs = [];
}
$.fn.plugin = function() {
var that = {};
$.fn.plugin.id ++; //each execution gets its unique id
var privateFn = function() { ... };
that.privateFn = privateFn; //expose all useful inner functions to that.
$.plugin.globalRefs[$.fn.plugin.id] = that; //make that global
}
$.fn.plugin.id = 0;
You talk about "other plugins", but it's not clear what you mean by that; what other plugins? What do they need to "know" about each other?
If you just want to maintain state, why not just use the jQuery data() mechanism to store whatever you need right on the target DOM elements? That would let your plugin find out about previous invocations, and it would also allow these mysterious "other plugins" to use that stored data too.
// ...
$(theElement).data('pluginName', { 'fabulous': 'data' });
The data that you store with this mechanism can be anything you like:
$(theElement).data('pluginName', {
'aNumber': 23.5,
'anArray': ['hello', 'world'],
'aFunction': function(arg) {
alert("wow a function! Here is the argument: " + arg);
}
'anObject': {
'more': 'stuff'
}
});