Pass "this" to a bootbox callback with Backbone - javascript

I'm using Backbone and bootbox.
This is my code inside a view:
confirm : function(result) {
if (result === true) {
var that = this;
this.model.set({completed: '1'}); // Exception here
this.model.save(
null, {
success: function (model, response) {
Backbone.history.navigate("index", true);
},
error: function(model, response) {
that.model.set({completed: '0'});
var responseObj = $.parseJSON(response.responseText);
bootbox.alert(responseObj.message);
}
});
}
},
completeProcess : function(event) {
event.preventDefault();
this.model.set({completed: '1'});
bootbox.confirm("Confirm?", this.confirm );
}
I'm getting this error:
Uncaught TypeError: Cannot call method 'set' of undefined
Is there a way to pass the reference from the view?

As underscore is a dependency of backbone you could use its _.bind feature:
_.bind(function, object, [*arguments])
Bind a function to an object, meaning that whenever the function is
called, the value of this will be the object.
Optionally, pass
arguments to the function to pre-fill them, also known as partial
application.
In your case this could look like this:
completeProcess : function(event) {
event.preventDefault();
this.model.set({completed: '1'});
bootbox.confirm("Confirm?", _.bind(this.confirm, this));
}

Alternatively, you could do something like this to hang on to the original 'this':
var _this = this;
bootbox.confirm({
message: Message ,
callback: function(result) {
console.log(this + " != " + _this);
},

Related

In Object refer to itself anonymous function key Javascript

I have this object:
var crudConfig = function($wizard, $formModal, $deleteModal) {
'use strict';
return {
handleOnShowFormModal : function() {
$formModal.on('show.bs.modal', function(event) {
...................
this.fillForms(data);
....................
});
return this;
},
fillForms : function(data) {
//do stuff
return this;
}
}
}
The problem appears when I call the fillForms with the param.
Uncaught TypeError: this.fillForms is not a function
As the fillForms key is an anonymous function how can I call it from inside the object? On other relative questions I only found how to refer itself if the key has a string value and the I call like this: this.fillForms .
this within the callback references the $formModal element. What you need to do is store this that refer to the object in a variable before the event listener is called and use the variable within the callback to access the object.
Just like this:
handleOnShowFormModal : function() {
var _this = this
$formModal.on('show.bs.modal', function(event) {
_this.fillForms(data);
});
return this;
},

Assign and use javascript object property via AJAX

So I have this Javascript object :
var obj = {
conn : null,
first : function(thisIdentity) {
"use strict";
$(document).on('click', thisIdentity, function(e) {
e.preventDefault();
$.ajax ({
url : some value,
// other parameters
success : function() {
this.conn = new Connection(data.user_id, "127.0.0.1:80");
}
});
},
second : function(thisIdentity) {
"use strict";
$(document).on('click', thisIdentity, function(e) {
e.preventDefault();
$.ajax ({
url : some value,
// other parameters
success : function() {
// using this.conn now results in UNDEFINED
}
});
}
};
Now basically value is assigned to conn variable in AJAX call of first function but when I try to use the same value in second function then it states this.conn is undefined. I just want to know how to assign value to the object's property and keep it preserved for future use? Thanks!
In the ajax success callback the this refers to a different scope than the original object.
Change you code to this:
var obj = {
conn : null,
first : function(thisIdentity) {
"use strict";
var mySelf = this;
$(document).on('click', thisIdentity, function(e) {
e.preventDefault();
$.ajax ({
url : some value,
// other parameters
success : function() {
mySelf.conn = new Connection(data.user_id, "127.0.0.1:80");
}
});
},
second : function(thisIdentity) {
"use strict";
var mySelf = this;
$(document).on('click', thisIdentity, function(e) {
e.preventDefault();
$.ajax ({
url : some value,
// other parameters
success : function() {
// now you can access the connection with mySelf.conn
}
});
}
};
The syntax itself is wrong. You are creating a variable or giving an expression inside an object literal. Remember this is not a function, but instead, it should be:
$.ajax ({
// computation and in success function
conn: new Connection(data.user_id, "127.0.0.1:80")
});
Updated
When you are giving such a way of definition:
success : function() {
this.conn = new Connection(data.user_id, "127.0.0.1:80");
}
Here, the this object refers to the success function and not your object. Read Understanding Scope and Context in JavaScript. Now you need to create a proxy variable for this and use it:
first : function(thisIdentity) {
"use strict";
var myObj = this;
$(document).on('click', thisIdentity, function(e) {
e.preventDefault();
$.ajax ({
url : some value,
// other parameters
success : function() {
myObj.conn = new Connection(data.user_id, "127.0.0.1:80");
}
});
},

backbone marionette pass variable to view method

I have simple situation and can't understand why variable that I pass to function always undefined.
var ProjectItemView = Backbone.Marionette.ItemView.extend({
template: "#ProjectItemTemplate",
initialize: function () {
var id = this.model.get('project_id');
$.getJSON('service/api.php/projects/' + id + '/progress').done(function (data) {
this.renderProgress('4'); //<== pass here
});
},
renderProgress: function (why) {
alert(why); //<== undefined
...
},
...
});
I expect that it equals '4'. In next step I want to pass "data" but now I realize that I can't pass anything.
Since you're invoking renderProgress on the return of $.getJSON you can simply provide the function reference to the done()method of the returned jQuery Promise. Your code would look like this:
var ProjectItemView = Backbone.Marionette.ItemView.extend({
template: "#ProjectItemTemplate",
initialize: function () {
var id = this.model.get('project_id');
$.getJSON('service/api.php/projects/' + id + '/progress')
.done(this.renderProgress);
},
renderProgress: function (data) {
alert(data);
...
},
...
});
If you'll need the view context inside renderProgress (like, for example, to refer to a view property), then provide done() a version of renderProgress that's bound to the view context:
$.getJSON('service/api.php/projects/' + id + '/progress')
.done(_.bind(this.renderProgress, this));
where _.bind is an UnderscoreJS function. Read more about it here.
You loose the context in $.getJSON done callback. Try this:
var ProjectItemView = Backbone.Marionette.ItemView.extend({
template: "#ProjectItemTemplate",
initialize: function () {
var id = this.model.get('project_id');
var _this = this;
$.getJSON('service/api.php/projects/' + id + '/progress').done(function (data) {
_this.renderProgress('4'); //<== pass here
});
},
renderProgress: function (why) {
alert(why); //<== undefined
...
},
...
});
You don't have access to this inside " $.getJSON( " assign this to any variable and then call "renderProgress" method.
var currentObj = this;
$.getJSON('service/api.php/projects/' + id + '/progress').done(function (data) {
currentObj .renderProgress('4'); //<== pass here
});
because in your case this points to current object of that function and not to view object.

ExtJS 4 - async callback to callParent throws exception

I want to prepare some Json Store before processing to callParent(), then it throws an error.
However, me.callParent() works fine outside without async callback.
Ext.define('My.desktop.AppExt', {
extend: 'Ext.ux.desktop.App',
someStore: null,
init: function() {
var me = this;
me.someStore = Ext.create('My.store.SomeStore');
me.someStore.load({
scope: this,
url: 'some/json/url',
callback: function(records, opt, success) {
if (success) {
me.callParent(); // BOOM! ERROR HERE
}
}
});
}
});
ERROR:
Unhandled exception at line 4245, column 17 in //localhost/js/ext-all-debug.js
0x800a138f - JavaScript runtime error:
Unable to get property 'superclass' of undefined or null reference
callParent relies on the context to call the right method, so if you're not actually calling it "directly" from a subclass method, you'll need to invoke it manually:
Ext.define('A', {
foo: function(){
console.log('foo', 'a');
}
});
Ext.define('B', {
extend: 'A',
bar: function(){
this.self.superclass.foo.call(this);
}
});
Ext.onReady(function(){
var o = new B();
o.bar();
});
The best solution for this purpose is to get link to parentMethod like at callParent() function, but without invoking it:
/**
* Returns reference to the parent class method. Works as {#link Ext.Base#callParent}, but doesn't invoke the
* method.
* #return {Function} Parent class method.
*/
getParentMethod: function() {
var method,
superMethod = (method = this.getParentMethod.caller) && (method.$previous ||
((method = method.$owner ? method : method.caller) && method.$owner.superclass[method.$name]));
return superMethod;
},
sampleMethod: function() {
var parentMethod = this.getParentMethod();
var parentArguments = arguments;
someAsyncFunc(function() {
parentMethod.apply(this, parentArguments); // calls parent.sampleMethod(...)
}, this);
}
One of the ways I know is to use extra parameter, that indicates that parent method should be called:
init: function(callParent) {
if (callParent) {
this.callParent();
}
var me = this;
me.someStore = Ext.create('My.store.SomeStore');
me.someStore.load({
scope: this,
url: 'some/json/url',
callback: function(records, opt, success) {
if (success) {
this.init(true);
}
}
});
}
If you use this.self.superclass.init.call(this) it will be ok only until somebody will create child for your class. this.self.superclass points to superclass of instance's class, so it would points to My.desktop.AppExt instead of Ext.ux.desktop.App.
Updated 24.08.2016: Published smarter solution (see another answer by me).

JavaScript/jQuery: Use 'this' Object on Success

I have a somewhat annoying issue when it comes to sending an Ajax request to a server and then returning the data on the success function within an JavaScript object. I've searched for similar questions, but none were really of the same manner as mine.
For example, I have the following code for sending a request within an object:
function SomeObject ( someVar )
{
var someVar = someVar;
}
SomeObject.prototype.sendRequest = function ()
{
$.ajax(
{
url : "somePage.php",
type : "POST",
data :
{
someVar : someVar
},
success : this.parseSuccess
} );
};
SomeObject.prototype.parseSuccess = function ( data )
{
if ( data === "success" )
{
this.proceed(); // Error
}
else
{
alert( "Server failed request." );
this.proceed();
}
};
SomeObject.prototype.proceed = function ()
{
// Do something else
};
I know that this.proceed() will fail because this is not the SomeObject instance.
Still, how can I efficiently refer back to the object after the request is complete?
I found I could do the following to achieve what I want, but it does not feel proper, and I would like a better way to handle the Ajax calls:
SomeObject.prototype.sendRequest = function ()
{
var me = this;
$.ajax(
{
url : "somePage.php",
type : "POST",
data :
{
someVar : someVar
},
success : function ( data )
{
me.parseSuccess( data ); // Will work
}
} );
};
Thanks for any help on the matter.
You could always do this:
success : function ( data )
{
parseSuccess.apply(this, [data]); // or parseSuccess.call(this, data);
}
Basically, with apply(), you can pass in the context of this you want to use inside the function, which in this case is the SomeObject context.
You can use the context option of $.ajax. Specifically, using context: this will set the this value inside parseSuccess to the current this value, which is what you want.
$.ajax({
// ...
context: this,
success: this.parseSuccess
});

Categories