want to access variable from function to render function in backbone - javascript

getGeoLevelDetails: function(id) {
window.gid = id;
}
I want to access window.gid in renderGeoLevelDetails function
renderGeoLevelDetails: function(response, obj){
var id = this.getGeoLevelDetails.gid;
console.log(id);
}
It isshowing me output as
Uncaught TypeError: Cannot read property 'gid' of undefined

There are a few errors in your approach.
First you are defining a global variable assigned to the DOM window object, this inside a function which i don't really know where it's declared. But this is not really important at this phase.
Second you want to obtain the value assigned to the global variable by calling the above function, which does not return anything.
You have a few options here: either assign the value to the global variable (which is a very bad practice, this should be avoided in any case).
The better approach would be to simply return id:
getGeoLevelDetails: function(id) {
return id;
}
Later you can obtain this id by calling in the renderGeoLevelDetails function.
renderGeoLevelDetails: function(response, obj) {
var id = this.getGeoLevelDetails();
}
Please note this is working only if you are calling the this.getGeoLevelDetails function from the same scope, because this is an instance of the same object.
There is another big error in your code regarding this line:
this.getGeoLevelDetails.gid;
First your are not invoking as a function but as an instance variable, expecting to return a globally declared object. This is the reason you are getting:
Uncaught TypeError: Cannot read property 'gid' of undefined
TL;DR
To sum up, if you wish to transfer a value from a model to a view you can access this by calling the model inside the view, or if you wish to obtain a value inside the same view you can use the approach presented above.
If none of the above solutions are fitted for your needs there is another method you can approach: to extend the Backbone object, then declare an object variable which receive the desired value. This way you will eliminate the global pollution issue:
Example:
Backbone.Details = _.extend({}, Backbone.Router);
Backbone.Details.geoLevel = id;
This variable: Backbone.Details.geoLevel then will be accessible from anywhere in your application.

Related

Why private function can't access member variable within Javascript object?

I'm having issues understanding scoping/access of fields defined with a JavaScript object.
Consider the following sample JavaScript object definition:
function SampleObject(controlName) {
var _controlName = controlName;
this.Display1 = function() {
console.log(_controlName);
}
this.Display2 = function() {
Display3();
}
Display3 = function () {
console.log(_controlName);
}
}
Now consider running the above object with the following example:
var a = new SampleObject("Bob");
var b = new SampleObject("Fred");
a.Display1(); //==> Displays "Bob"
b.Display1(); //==> Displays "Fred"
a.Display2(); //==> Displays "Fred"
b.Display2(); //==> Displays "Fred"
What I'm having difficulty understanding is how to access object fields (properties) from within private functions defined within my object.
Within my example, I am confused as to why _controlName has the value "Fred" when it is displayed via Display2() for both objects a and b.
I suspect that is either an issue with how _controlName and/or Display3() is defined or I am unclear how scoping would work in this instance. Can someone please share some light on this?
Thanks,JohnB
In some other languages such as Java (where I hail from), when you are inside a method on an object, the this is implicit. In Javascript, this is NOT the case.
When you are assigning to this.Display1 and this.Display2, you are creating properties with those names on the object pointed at by this. Because of new, this is a different object each time.
However, what's happening when you assign to Display3 is that you are assigning to a global variable. If it doesn't exist, it is created for you. When you call new SampleObject("Fred"); the function which originally logged "Bob" is now gone, replaced by one which prints "Fred".
If you add 'use strict'; to the top of your SampleObject function, which suppresses this "implicit global" behavior, you get a reference error when you try to assign to the never-declared variable Display3.
Here's the explanation.
In the first call, new SampleObject("Bob"); the global variable Display3 gets set to a function that console-logs the value Bob.
In the second call, new SampleObject("Fred"); the global variable Display3 gets set to a function that console-logs the value Fred.
Now your Display1 is actually a method. Every object you create gets its own Display1 property. So Bob's Display1 logs Bob and Fred's logs Fred.
But because the Display2 methods each call the global Display3 method, they will all log what the function in the last assignment fo Display3 says to log, and that will always be Fred.

Can you get the object of a method?

I'm just wondering if I can make some of my helper functions(for stuff like benching, logging and caching) a bit neater. Right now I'm doing this
function doSomethingToMethodsObject(object, methodname) {
//do things to object and object[methodname]
}
so I can use it like this
var myObject = function() {
this.myString = "hello";
this.myMethod = function() { return this.myString; }.bind(this);
doSomethingToMethodsObject(this, "myMethod");
}
but it would be better if I could call it like this
doSomethingToMethodsObject(this.myMethod);
and then break down the function reference to this and "myMethod" inside doSomethingToMethodsObject.
So is there a way to figure out what objects a function belongs to?
So is there a way to figure out what objects a function belongs to?
A function does not belong to only a single object. There can be lots of references to that same function on lots of different objects. So, no you can't specifically figure out what object a function belongs to by purely looking at the function.
In fact, why you pass this.myMethod as an argument, there is no connection whatsoever to the this part that is passed. It just gets a reference to the function and passes that.
You can use .bind() to pass a bound reference to the function, but that only lets you call the method in the context of the right object - it doesn't allow you to separate out the object from the method. If you need both object and method separately in your function, then you will need to find some way to make them both separately accessible inside the function - the most obvious way to do that is just pass them both as arguments.
Depending upon the specific context (which you don't really share very much of), sometimes you can use parent scoped variables like var self = this; to maintain a reference to this that can be accessed by child functions, but I'm not sure that applies to what you're doing.
Here are some options:
doSomethingToMethodsObject(this, this.myMethod);
doSomethingToMethodsObject({obj: this, method: this.myMethod});
When you use this.myMethod, JS creates a reference whose base is this and whose referenced name is "myMethod".
However, when you use it as an argument, JS resolves the reference into the property value. Therefore, in doSomethingToMethodsObject, it's too late to get the base.
The only way to obtain the base of this.myMethod is when myMethod is an accessor property with a getter which redirects to the underlying object value. Then you can use this inside the getter, and store it in a property of the underlying value.
For example:
var obj = {
_myMethod: function(arg) { /* Underlying function */
return {thisArg: this, arg: arg};
},
get myMethod() { /* Stores reference parts and redirects */
return Object.assign(this._myMethod, {
refBase: this,
refName: "_myMethod"
});
}
};
function doSomethingToMethodsObject(value) {
return value.call(
value.refBase,
value === value.refBase[value.refName]
);
}
obj.myMethod(123); // {thisArg: obj, arg: 123}
doSomethingToMethodsObject(obj.myMethod); // {thisArg: obj, arg: true}

Can't use own property in JavaScript Object's function

I'm trying to understand the following code:
var x = {
editBox: _editBox,
comboBox: _comboBox,
getExchangeRate: function() {
var r = parseFloat(_editBox.val());
return isNaN(r) ? null : r;
}
}
My question is about the use of _editBox in getExchangeRate().
I'm creating a JavaScript object, which has two value properties and a function property. But why can't the function use editBox? It's undefined if I try.
And how can it use _editBox? It could be much later when the function gets called. I understand there is some work being done under the hood to make it available, but how do I know it will still be valid? Wouldn't it make more sense if I could use editBox instead?
Having come from other languages, that's certainly what seems more logical.
But why can't the function use editBox? It's undefined if I try.
It is a property of the object, not an in-scope variable.
this.editBox will probably work (assuming are you calling getExchangeRate in the right context (i.e. x.getExchangeRate()).
And how can it use _editBox?
Because the variable is in scope.
It could be much later when the function gets called.
That doesn't really matter
how do I know it will still be valid?
You control when and if it gets overwritten.
Because there is no variable such as editBox, but there is _editBox. I think you are looking for
this.editBox.val()
If you call the function as x.getExchangeRate(), then this inside the function will refer to x and you can access its property editBox. See the MDN documentation for more information about this.
Having come from other languages, that's certainly what seems more logical.
JavaScript is not like Java where instance members are automatically in scope of the methods. There is no implicit connection between a function and the object it is a property value of. That's because functions are first-class objects, they don't "belong" to anyone. And JS has lexical scope.
Consider this example:
var name = 'bar';
function foo() {
console.log(name);
}
var obj = {
name: 'baz',
prop: foo
};
As you can see, we defined foo "independently" from obj. obj.name doesn't magically become name inside the function if it is called as obj.prop().

JavaScript /jQuery variable scope causing errors

I have a really simple snippet of code and a really (probably) simple change I need to make.
I can't access a variable that I need to in my jQuery script:
var Objects; // Used to store stuff
enable_reordering();
function enable_reordering()
{
$('a.move-object').click(function(){
Objects.moveMe = $(this);
$('#image-title').text( $(Objects.moveMe).attr('data-child-title') );
return false;
});
}
When I try to change the value of Objects.moveMe to anything, my browser moans that Objects is not set. (Error: Objects is undefined).
How can I make it so that I can use variables in and out of functions throughout my entire script?
Update:
The error is caused by the line
$('#image-title').text( $(Objects.moveMe).attr('data-child-title') );
where I first try and use the variable.
try: http://jsbin.com/ocodoz/
var a;
alert(a);
a === undefined But declared in the current scope..
Your Object have to be set to an object
var Objects = {};
It's not a scope issue. The problem is that, as the error says, Objects is undefined. It looks like you want to set a property of it, so initialize it as an object literal:
var Objects = {};
Currently, what you are trying to do is effectively:
undefined.moveMe = $(this);
When you declare a variable, its value is undefined until you assign some other value to it. By assigning an empty object literal to it, you can then set properties of that object.

Still confused about JavaScript's 'this'

I've been reading through quite a few articles on the 'this' keyword when using JavaScript objects and I'm still somewhat confused. I'm quite happy writing object orientated Javascript and I get around the 'this' issue by referring the full object path but I don't like the fact I still find 'this' confusing.
I found a good answer here which helped me but I'm still not 100% sure. So, onto the example. The following script is linked from test.html with <script src="js/test.js"></script>
if (!nick) {
var nick = {};
}
nick.name= function(){
var helloA = 'Hello A';
console.log('1.',this, this.helloA);
var init = function(){
var helloB = 'Hello B';
console.log('2.',this, this.helloB);
}
return {
init: init
}
}();
nick.name.init();
What kind of expected to see was
1. Object {} nick.name, 'Hello A'
2. Object {} init, 'Hello B'
But what I get is this?
1. Window test.html, undefined
2. Object {} init, undefined
I think I understand some of what's happening there but I would mind if someone out there explains it to me.
Also, I'm not entirely sure why the first 'console.log' is being called at all? If I remove the call to the init function //nick.name.init() firebug still outputs 1. Window test.html, undefined. Why is that? Why does nick.name() get called by the window object when the html page loads?
Many thanks
Also, I'm not entirely sure why the first 'console.log' is being called at all?
nick.name = function(){
// ...
}();
Here you define a function, call it immediately (hence ()) and assign its return value ({init: init}) to nick.name
So the execution is:
Create a variable called nick if there isn't one with a non-falsey value already
Create an anonymous function that…
Creates a variable called helloA in its own scope
Outputs data using console.log containing "1" (as is), this (the window because the function is executing in the global context instead of as a method), and this.helloA (window.helloA, which doesn't exist.
Defines a function called init
Returns an object which gets assigned to nick.name
Then you call nick.name.init() which executes the init function in the context of name.
This defines helloB
Then it console.logs with "2" (as is), this (name), and this.helloB (nick.name.helloB - which doesn't exist)
So the first output you get is from console.log('1.',this, this.helloA);
I think your main problem is that you are confusing this.foo (properties on the object on which a method is being called) with variable scope (variables available to a function)
It's much simpler if you think about this as a function, not as a variable. Essentially, this is a function which returns current "execution context", that is, the object the current function was "applied" to. For example, consider the following
function t() { console.log(this)}
this will return very different results depending upon how you call it
t() // print window
bar = { func: t }
bar.func() // print bar
foo = { x: 123 }
t.apply(foo) // print foo
this is defined on a per-function basis when the function call is made. When you call a function as o.f(), this will be o within the function, and when you call it as f(), this will be the global object (for browsers, this is the window).
You wrote nick.name = function(){...}(); and the right-hand part is of the form f(), hence the Window.
var foo = bar; defines a local variable. It may not be accessed as this.foo (well, except when you're at global scope, but that's silly). To define a member, you usually write this.foo = bar; instead.
This is what your code does:
It creates an object and assigns to the variable nick.
It creates an anonymous function.
It calls the function (in the window scope).
It assigns the return value (an object containing the init property) to the name property of the object.
It gets the value from the init property, which is a method delegate, and calls the method.
The anonymous function does this:
It declares a local variable named helloA and assigns a string to it. (Creating a local variable doesn't add it as a property to the current object.)
It logs this (window) and the helloA property (which doesn't exist).
It creates an anonymous function and assignes to the local variable init.
It creates an object with the property init and the value from the local variable init.
The anonymous function assigned to the init property does this:
It declares a local variable named helloB and assigns a string to it. (Creating a local variable doesn't add it as a property to the current object.)
It logs this (the object from the name property, not the nick variable), and the helloB property (which doesn't exist).

Categories