In Object refer to itself anonymous function key Javascript - 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;
},

Related

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.

Passing variable into object method javascript

trying to get my head around objects, methods, closures, etc... in Javascript.
Can't see why this isn't working, some fundamental flaw in my thinking I guess. I'm expecting the val variable to be passed through to the addNote() function but it isn't. I thought that any variables declared outside of a function are available to that function, as long as they're not within another function. Is that not correct?
if(typeof(Storage) !== "undefined") {
console.log(localStorage);
var $input = $('#input'),
$submit = $('#submit'),
$list = $('#list'),
val = $input.val();
var noteApp = {
addNote : function(val) {
var item = val.wrap('<li />');
item.appendTo($list);
clearField();
},
clearField : function() {
$input.val = '';
},
delNote : function(note) {
}
};
$submit.on('click', function(){
noteApp.addNote();
});
} else {
}
I'm trying to learn how the pros manage to get their code so clean, concise and modular. I figured a note app would be a perfect start, shame I got stuck at the first hurdle...
Cheers.
There are several issues with the code in the question
defining an argument named val and not passing an argument to the function
when calling clearField() inside the object literal it's this.clearField()
You're only getting the value once, not on every click
val is a string, it has no wrap method
$input.val = ''; is not valid jQuery
I would clean it up like this
var noteApp = {
init: function() {
if (this.hasStorage) {
this.elements().events();
}
},
elements: function() {
this.input = $('#input');
this.submit = $('#submit');
this.list = $('#list');
return this;
},
events: function() {
var self = this;
this.submit.on('click', function(){
self.addNote();
});
},
hasStorage: (function() {
return typeof(Storage) !== "undefined";
})(),
addNote: function() {
this.list.append('<li>' + this.input.val() + '</li>');
this.clearField();
return this;
},
clearField: function() {
this.input.val('');
},
delNote : function(note) {
}
}
FIDDLE
Remember to call the init method
$(function() { noteApp.init(); });
In your call to addNote(), you don't pass any argument for the val, so it will be undefined:
noteApp.addNote();
// ^^ nothing
Pass the input (seems you want the jQuery object not the string value because of your val.wrap call):
noteApp.addNote($input);
When you declare the val in the function, it is scoped to that function and will only be populated if the function call passes a value for that argument. Even if you have another variable in an upper scope with the same name val, they are still differentiated. Any reference to val in the function will refer to the local val not the upper scope.

Scope Error in Javascript. Calling a method within a different method of that object

I've got a variable timekeep.
var timeKeep;
and I define it thusly:
timeKeep = Class.create({
initialize: function() {
this.initObservers();
},
initObservers: function() {
$$('input').each( function(el) {
el.observe('keypress', function(ev) {
// the key code for 'enter/return' is 13
if(ev.keyCode === 13){
timeKeep.submit();
// Uncaught TypeError: Object function klass() {
// this.initialize.apply(this, arguments);
// } has no method 'submit'
}
});
});
},
submit: function() {
alert('Submitted!');
}
})
The error I am getting is commented out below the line that it occurs. It's got something to do with calling a timeKeep method within a different scope I think?
Is there a problem calling timeKeep.method() inside a foreach statement?
Problem is with you OOP style. Use a closure so you call the current instance of your class.
initObservers: function () {
var that = this;
$$('input')
.each(function (el) {
el.observe('keypress', function (ev) {
// the key code for 'enter/return' is 13
if (ev.keyCode === 13) {
that.submit();
}
});
});
},
You could also look at bind
initObservers: function() {
var submit = this.submit.bind(this);
$$('input')
.each(function (el) {
el.observe('keypress', function (ev) {
// the key code for 'enter/return' is 13
if (ev.keyCode === 13) {
submit();
}
});
});
},
You are assuming that Class.create returns an instance of an object of the type you are defining, but no, it returns a constructor function for creating instances of the class you are defining.
You can add the new keyword to the assignment and then you will have in timeKeep what you want to:
timeKeep = new Class.create({
...
})()
As suggested - using Function#bind() will solve your problem but there is a cleaner way so that you can continue to use this inside the class scope.
Also look into the invoke() method as this is a perfect opportunity to use it. $$() returns a list of elements and if you want to perform the same function on all of the elements invoke() will handle iterating over the list.
timeKeep = Class.create({
initialize: function() {
this.initObservers();
},
initObservers: function() {
$$('input').invoke('observe','keypress',function(ev) {
// the key code for 'enter/return' is 13
if(ev.keyCode === 13){
timeKeep.submit();
// Uncaught TypeError: Object function klass() {
// this.initialize.apply(this, arguments);
// } has no method 'submit'
}
//Add the bind method to the closure to bind 'this' inside that function scope
//to 'this' of the class
//the binding will allow you to call this.submit() instead of timeKeep.submit
//as well as access any of the class properties and methods inside this closure
}.bind(this));
} ,
submit: function() {
alert('Submitted!');
}
});
PrototypeJS documentation on observers http://api.prototypejs.org/dom/Event/observe/ - look at the heading Using an Instance Method as a Handler

Expose knockout ViewMode from function to another function

I have next situation...
For some reasons I need to bind knockout ViewModel inside function and call it on specific terms.
this is my code:
if (... some conditions ...) {
var polugodiste = $("#polugodiste").val();
ApplyBindingsIzostanak(polugodiste);
$('#flip-min').change(function () {
IzostanakViewModel.selectedPolugodiste(parseInt($(this).val()));
IzostanakViewModel.GetIzostanci();
});
}
and function:
function ApplyBindingsIzostanak(polugodiste)
{
var Izostanak = function (cas, tekst) {
this.Cas = cas;
this.Tekst = tekst;
};
var IzostanakViewModel = {
selectedStatus: ko.observable(),
selectedPolugodiste: ko.observable(polugodiste),
ucenikIzostanakList: ko.observableArray([]),
GetIzostanci: function () {
.. do some code ...
}
};
ko.applyBindings(IzostanakViewModel);
}
Binding is working, but I get error when I try calling IzostanakViewModel inside my if, it says IzostanakViewModel is not defined.
Can I and how expose IzostanakViewModel from function and use it inside if statement?
NOTE*
I could try something like this:
add this code to ApplyBindingsIzostanak():
window.foo = function() {
IzostanakViewMode.GetIzostanci();
}
and then call it from if statement, but maybe there is better solution...
IzostanakViewModel is a variable within the ApplyBindingsIzostanak() function. Why don't you just return it so you have a reference to it?
function ApplyBindingsIzostanak(polugodiste)
// ...
return IzostanakViewModel;
}
var IzostanakViewModel = ApplyBindingsIzostanak(polugodiste);
$('#flip-min').change(function () {
IzostanakViewModel.selectedPolugodiste(parseInt($(this).val()));
IzostanakViewModel.GetIzostanci();
});

Can event handler defined within JavaScript object literal access itself?

I know I could do this with closures (var self = this) if object was a function:
click here
<script type="text/javascript">
var object = {
y : 1,
handle_click : function (e) {
alert('handling click');
//want to access y here
return false;
},
load : function () {
document.getElementById('x').onclick = this.handle_click;
}
};
object.load();
</script>
The simplest way to bind the call to handle_click to the object it is defined in would be something like this:
var self=this;
document.getElementById('x').onclick =
function(e) { return self.handle_click(e) };
If you need to pass in parameters or want to make the code look cleaner (for instance, if you're setting up a lot of similar event handlers), you could use a currying technique to achieve the same:
bind : function(fn)
{
var self = this;
// copy arguments into local array
var args = Array.prototype.slice.call(arguments, 0);
// returned function replaces first argument with event arg,
// calls fn with composite arguments
return function(e) { args[0] = e; return fn.apply(self, args); };
},
...
document.getElementById('x').onclick = this.bind(this.handle_click,
"this parameter is passed to handle_click()",
"as is this one");
So, the event handler part wires up just fine (I tested it myself) but, as your comment indicates, you have no access to the "y" property of the object you just defined.
This works:
var object = {
y : 1,
handle_click : function (e) {
alert('handling click');
//want to access y here
alert(this.y);
return false;
},
load : function () {
var that = this;
document.getElementById('x').onclick = function(e) {
that.handle_click(e); // pass-through the event object
};
}
};
object.load();
There are other ways of doing this too, but this works.
I see how to do it with Jason's latest one. Any way to do it without the anonymous function?
We can directly pass an object with a handler method thanks to AddEventListener, and you will have access to its attributes:
http://www.thecssninja.com/javascript/handleevent
Hope this will help those who, like me, will look for this topic some years after!

Categories