Object prototype doesn't recognize function - javascript

I have 3 functions on an object prototype:
Job.prototype.postData = function(url) {
this.getFormData();
var formdata = new FormData();
formdata.append("position", this.position);
formdata.append("team", this.team);
formdata.append("details", this.details);
$.post(url, formdata, function(response) {
alert(response.message);
window.location.href = '/';
});
};
Job.prototype.createNew = function() {
var newUrl = API_URL + "/add_listing";
this.postData(newUrl)
};
Job.prototype.update = function() {
var updateUrl = API_URL + "/edit_listing" + "?id=" + this.id;
this.postData(updateUrl)
};
I'm attaching the last two as event handling callbacks:
$('#list-button').on('click',job.createNew);
$('#list-button').on('click',job.update);
Both of those give a TypeError:
oop.js:38 Uncaught TypeError: this.postData is not a function

The problem is simply that the this context gets lost the way you're binding the event handler.
Either explicitly bind the context, or call the function in a way that preserves the context:
$('#list-button').on('click', function () { job.createNew(); });
$('#list-button').on('click', job.createNew.bind(job));
See How does the "this" keyword work?.

Related

Javascript. Passing an instance of an object as an argument, inside a new operator

So I'm trying to refactor a function that goes something like this:
if (typeof init_common_load_more != "function") {
init_common_load_more = function (id) {
fdxm.js_manager.on("fdx_loadmore_js", function () {
component_wrapper = document.getElementById(id);
const loader = new fdxLoadMore({
posts_counter:
component_wrapper.querySelector(".posts_counter"),
load_more_posts_url: function (instance) {
let post_list_obj = instance.getObject("posts_list"),
load_options = {
controller:
post_list_obj.dataset["load_more_controller"],
//...other options
};
let url = "/api/posts/load_more_posts";
for (option in load_options) {
url += "/" + option + "/" + load_options[option];
}
return url;
},
});
// do things wiht the loader
});
};
}
This somehow works. The problem arises when I try to make the "load_more_posts_url" function a separate function:
if (typeof init_common_load_more != "function") {
init_common_load_more = function (id) {
fdxm.js_manager.on("fdx_loadmore_js", function () {
component_wrapper = document.getElementById(id);
const loader = new fdxLoadMore({
posts_counter:
component_wrapper.querySelector(".posts_counter"),
load_more_posts_url: get_load_more_url(this),
});
});
};
// do things wiht the loader
function get_load_more_url(instance) {
let post_list_obj = instance.getObject("posts_list"),
load_options = {
controller: post_list_obj.dataset["load_more_controller"],
//...other options
};
let url = "/api/posts/load_more_posts";
for (option in load_options) {
url += "/" + option + "/" + load_options[option];
}
return url;
}
}
I passed "this" as a parameter, because sometimes writing random words makes the code work. But not this time: when I console log "instance" I'm getting some kind of default callback object instead of the new fdxLoadMore object.
How can I reference the new fdxLoadMore, in the same way it is referenced on the first version of the code, but using a separate, named function?

method with parameter in unknown js function issues

I'm trying to protect a part of my js code wrapping my code with an Unknown function.
I have edit my function to change
function banana(url) {}
to method
banana: function(url){ },
when I try to call my function banana in another function i try to use
this.banana(url);
but i have this error:
TypeError: this.banana is not a function
Full code:
(function (){
var url_test = "./add_user.php?opt=get_user&token=<?php echo $token; ?>";
if (typeof $.customfnc == 'undefined')
$.customfnc = {}
$.customfnc.get = {
setup: function (){
var url = "google.ca";
this.banana(url);
},
banana: function (url){
console.log("my url: " + url);
};
};
};
// on ready render data
$(document).ready(function() {
$.customfnc.get.setup();
});
})(jQuery);
thanks for your help!
The issue here is that the scope of 'this' is not exactly what you might think it is.
The way I have handled this particular issue in the past is to add
var self = this;
Outside of the object that is attempting to self reference. This may impact how you have set up youre .get() object though.
$.customfnc.get = function(){
var self = this;
self.setup = function (){
//....
self.banana(URL)
}
self.banana = function(url){
//...
}
}

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.

Javascript Scope and this.Variable

So I have some javascript with the following (pseudo) structure. How do I set the this.last_updated variable of the parent function from the showUpdates function, without specifically referencing the name assignment (my_main_function).
var my_main_function = new main()
function main() {
this.last_updated;
function showUpdates(data){
//set this.last_updated=
// do Stuff
}
this.updateMain(){
$.ajax({
url:"/my_url/"
type:"POST",
datatype:"json",
data: {'last_updated':this.last_updated },
success : function(data) { showUpdates(data)},
error : function(xhr,errmsg,err) {
alert(xhr.status + ": " + xhr.responseText); },
});
}
}
Updated the code base one the comments:
There are two way of creating objects.
If you need to create the object multiple time you will do it like this:
var YourDefintinon = function() {
};
YourDefintinon.prototype.foo = function() {
};
obj1 = new YourDefintinon();
obj2 = new YourDefintinon();
obj1.foo();
If you only need it once in your code you can just do it like that:
var obj = {
};
obj.foo = function() {
};
foo();
So your would need the main only once your code would look like this:
Using Function.prototype.bind (and its polyfill for older browsers) to bind the showUpdates to the obj.
var main = {
last_updated : null
};
function showUpdates(data){
this.last_updated = data.update_time;
}
main.updateMain = function () {
//<< bind showUpdates to `this` and save the bound function in the local variabel showUpdates
var showUpdates = showUpdates.bind(this);
$.ajax({
url:"/my_url/"
type:"POST",
datatype:"json",
data: {'last_updated':last_updated },
success : showUpdates, //<< uses the showUpdates variable not the function
error : function(xhr,errmsg,err) {
alert(xhr.status + ": " + xhr.responseText);
},
});
};
As you don't want to make showUpdates accessible to others you could wrap the whole block into a function that is immediatly called:
var main = (function() {
var main = {
last_updated : null
};
function showUpdates(data){
this.last_updated = data.update_time;
}
main.updateMain = function () {
var showUpdates = showUpdates.bind(this);
$.ajax({
url:"/my_url/"
type:"POST",
datatype:"json",
data: {'last_updated':last_updated },
success : showUpdates,
error : function(xhr,errmsg,err) {
alert(xhr.status + ": " + xhr.responseText);
},
});
};
return main;
}());

function call with this keyword is undefined

I am calling local (class) function via this pointer, but get an error 'Uncaught TypeError: undefined is not a function'. Probem occur on line
this.createtimetable(); at loadtimetable function.
My JS (relevant) is :
this.createtimetable = function () {
this.inside_timetable = [];
for (var d = new Date(in_week_start); d <= new Date(in_week_end); d.setDate(d.getDate() + 1)) {
console.log(new Date(d));
daysOfYear.push(new Date(d));
}
}
this.loadtimetable = function (in_guide_id, in_week_start, in_week_end) {
this.guide_id = in_guide_id;
this.week_start = in_week_start;
this.week_end = in_week_end;
$.post("./j.php", {
guide_id : in_guide_id,
week_start : in_week_start,
week_end : in_week_end
})
.done(function (data) {
var res_arr = jQuery.parseJSON(data);
if (res_arr.code == 0) {
this.excursions_base = res_arr.answer;
alertify.success("Data extracted");
this.createtimetable();
} else {
alertify.error("Some problem occured." + data);
}
}).fail(function () {
alertify.alert("Error. Please, refresh page, or try later. We are sorry. Write or call us with your question!");
});
}
Calling by name (i.e. createtimetable() ) also fail. Thank you for ideas!
Your code is executed in a callback, and this no longer points to your object. You should either use a closure, aliasing this to something like self, or explicitly bind this
this.createtimetable = function () {
this.inside_timetable = [];
for (var d = new Date(in_week_start); d <= new Date(in_week_end); d.setDate(d.getDate() + 1)) {
console.log(new Date(d));
daysOfYear.push(new Date(d));
}
}
this.loadtimetable = function (in_guide_id, in_week_start, in_week_end) {
this.guide_id = in_guide_id;
this.week_start = in_week_start;
this.week_end = in_week_end;
$.post("./j.php", {
guide_id: in_guide_id,
week_start: in_week_start,
week_end: in_week_end
})
.done(function (data) {
var res_arr = jQuery.parseJSON(data);
if (res_arr.code == 0) {
this.excursions_base = res_arr.answer;
alertify.success("Data extracted");
this.createtimetable();
} else {
alertify.error("Some problem occured." + data);
}
}.bind(this)).fail(function () {
alertify.alert("Error. Please, refresh page, or try later. We are sorry. Write or call us with your question!");
}.bind(this));
}
Store reference of $(this)outside of post function call ans use it in done callback function, here this doesn't refers to your object.
this.loadtimetable = function(in_guide_id, in_week_start, in_week_end)
{
var self = this; //store reference of this
$.post( "./j.php", {})
.done(function( data ) {
self.createtimetable(); //Here instead of this use your variable
});
}
EDIT
If you are open to use $.ajax() instead of $.post(). You can use the context option.
This object will be made the context of all Ajax-related callbacks. By default, the context is an object that represents the ajax settings used in the call ($.ajaxSettings merged with the settings passed to $.ajax). (...)
$.ajax({
context: this
});

Categories