JS returning function not present - javascript

I have following code.
var handleJson = function(){
var jsonData ='xx';
var eventObject,eventObjectx=[];
that = this;
var convertJsonToObject = function(datax){
//debugger;
try {
that.printList(datax.data);
} catch(e) {
console.log(e);
}
//debugger;
}
return{
getDatafromserver: function(url){
$.ajax({
crossOrigin: true,
url: url,
success:convertJsonToObject
//console.log(jsonData);
});
},
printList:function(eventObject){
$.each(eventObject,function(index,val){
$('#eventlist').append('<li>'+val.event+'</li>');
})
}
}
}
var jsonHandler = new handleJson();
jsonHandler.getDatafromserver(url);
//jsonHandler.printList('eventlist');
});
Although the function printList exist its returning error
TypeError: that.printList is not a function {stack: (...), message:
"that.printList is not a function"}
Can any one help me out?

The value of this as of your that = this line is not in any way related to the object that you return at the end of your handleJson function.
Since you're using new with handleJson, you want to add to the object that this refers to, rather than returning a new, unrelated object:
var handleJson = function() {
var jsonData = 'xx';
var eventObject, eventObjectx = [];
var that = this;
var convertJsonToObject = function(datax) {
//debugger;
try {
that.printList(datax.data);
} catch (e) {
console.log(e);
}
//debugger;
}
this.getDatafromserver = function(url) {
$.ajax({
crossOrigin: true,
url: url,
success: convertJsonToObject
//console.log(jsonData);
});
};
this.printList = function(eventObject) {
$.each(eventObject, function(index, val) {
$('#eventlist').append('<li>' + val.event + '</li>');
})
};
};
var jsonHandler = new handleJson();
jsonHandler.getDatafromserver(url);
//jsonHandler.printList('eventlist');
Here's how new works:
It creates a new object backed by the object that the target function's prototype property refers to; so in your case, a new object backed by handleJson.prototype.
It calls the target function (handleJson) with this referring to that new object.
When the target function returns, if it doesn't return anything, or it returns a primitive value, or it returns null, new takes the object that it created as its result; but if the target function returns a non-null object reference, that overrides that default and new takes that object reference as its result.
In your original code, that last point was coming into play.
Side note: Your code was falling prey to The Horror of Implicit Globals becuse you weren't declaring that. I've added var on it above.
Side note: The overwhelming convention in JavaScript is that a constructor function (a function you're calling via new) starts with a capital letter. They're also usually nouns rather than verbs (other kinds of functions are usually verbs, but not constructor functions, which are named after the thing they construct). So JsonHandler rather than handleJson.

Related

accessing object properties with object method

I am trying to build an application called myApp which has the property regularNameErrors and the Method populateJSON which uses an AJAX call to get a JSON object which is then added to the property declared as one of the arguments to the method.
The function to get the data definitely works because the alert at position 3 gives the correct list of keys. however the alert at 1 returns undefined and the alert at 2 blank.
When I replace the line destination = data with myApp.regularNameErrors = data again it works so I assume that I have misunderstood how to pass object properties to object methods. However I want to use the method populateJSON several times and need to know the correct way to pass it properties.
var myApp = {
init: function () {
myApp.populateJSON(myApp.regularNameErrors, 'data/spelling.json').done(function () {
alert(myApp.regularNameErrors['kingscross']); //1
});
},
regularNameErrors: {}, //Object of spelling mistake:proper key:value pairs
populateJSON: function (destination, source) {
var def = $.Deferred();
$.getJSON(source, function (data) {
destination = data;
alert(Object.keys(myApp.regularNameErrors)); //2
alert(Object.keys(data)); //3
def.resolve();
});
return def.promise();
},
};
With the ability to use the deferred properties of the returned getJSON object the functions can be reduced to a few lines such that it is not necessary to create a new function called populateJSON
var myApp = {
init: function () {
$.getJSON('data/spelling.json').done(function(data) {
myApp.regularNameErrors = data;
});
},
regularNameErrors: {},
};
destination is no "pointer" to the property that you passed into the function, but a variable holding the value which the property evaluated to. When you assign to destination, you just write to the local variable of your populateJSON function.
If you want to be able to declare the destination, you would need to pass a base object (or always use myApp) and a property name:
var myApp = {
init: function () {
myApp.populateJSON('regularNameErrors', 'data/spelling.json', function() {
alert(Object.keys(myApp.regularNameErrors)); //2
alert(myApp.regularNameErrors['kingscross']); //1
});
},
regularNameErrors: {}, //Object of spelling mistake:proper key:value pairs
populateJSON: function (destinationName, source, callback) {
$.getJSON(source, function (data) {
myApp[destinationName] = data;
alert(Object.keys(data)); //3
callback();
});
}
};
However, I see you are using the promise pattern. A promise should not be used as a simple notifier ("now the data has arrived somewhere"), but it should represent the data itself ("now, here's the data") - resolve it with the data instead of storing the data in a global variable/property and resolving with nothing. Actually, the $.ajax does already return such a promise so you don't have to do much for it:
var myApp = {
init: function () {
myApp.regularNameErrors = $.getJSON('data/spelling.json');
myApp.regularNameErrors.done(function(data) {
alert(Object.keys(data)); //3
alert(data['kingscross']); //1
});
}
};

Getter returning the function instead of "return" value

Im trying to use getters and setters for a project in javascript, I'm getting a json from a jquery get and im setting the value with a setter, I can alert the content in the setter function, so I know that everything is okay, but when I try to return a value with a getter, I got the function instead of the value.
My code is
function _bd() {
this.setJson = function(js) {
json = js;
}
this.getJson = function() {
return json;
}
}
bd = new _bd();
$.get("json.php", function(data) {
bd.setJson(data);
},"json");
alert(bd.getJson);
the last alert returns
function () {
return json;
}
also, using prototype does the same result.
I agree with the previous comments. Invoke the getter-function to retrieve the "json" value.
Probably you want to declare the json variable as well (unless you need it globally of some sorts).
Also, you seem to mixing and matching some object construction patterns. The functional pattern, to simulate "private" vars inside a closure (like json), but you also need the prototypical inheritance, so you can attach the getter/setters to this inside the construtor function. Is it possible to stick to one?
E.g.: trapping privates in closure.
function _bd() {
var json;
var that = {};
that.setJson = function(js) {
json = js;
}
that.getJson = function() {
return json;
}
return that;
}
var bd = _bd();
$.get("json.php", function(data) {
bd.setJson(data);
alert(bd.getJson());
},"json");
E.g. OO style, with constructor function.
function BD(){
this._json = null;
}
BD.prototype = {
getJson: function(){
return this._json;
},
setJson: function(json){
this._json = json;
}
};
var bd = new BD();
$.get("json.php", function(data) {
bd.setJson(data);
alert(bd.getJson());
},"json");
There can be good reasons to use a hybrid style, but it helps if you stick with one approach or the other.
As for "real" getters (IMHO, not worth the insane syntax), try:
function BD(){
this._json = null;
}
Object.defineProperty(BD.prototype,"json",{
get: function(){
return this._json;
},
set: function(json){
this._json = json;
}
});
var bd = new BD();
bd.json = {a: "test"};
console.log(bd);
As stated in the comments :
alert( bd.getJson() );
you are getting the string display of the function because you are not invoking the function
before the response come back, you'll get nothing.. probably undefined.
$.getJson
(
success : function() { alert( bd.getJson() ); }
);

Javascript object method issue

I'm trying to create an object called List. This object has a method add which simply pushes a task object onto this tasks array. I also built a load method to load items from a url.
My issue is I can't seem to reference the add method from within the load method, I get the following error:
Uncaught TypeError: Object # has no method 'add'.
How do I reference the add method from within the load method? The code I am using is below.
function List(){
this.tasks = new Array();
this.add = function(taskItem){
this.tasks.push(taskItem);
};
this.load = function(url){
$.getJSON(
url,
function(data){
$.each(data, function(key,val){
var task = new Task({
id:val.pkTaskId,
title:val.fldName,
status:val.fldStatus
});
this.add(task);
});
}
);
}
}
var userList = new List();
userList.load(url)
Try this:
function List(){
this.tasks = []; // prefer [] over new Array()
this.add = function(taskItem){
this.tasks.push(taskItem);
};
this.load = function(url){
var self = this;
$.getJSON(
url,
function (data){
$.each(data, function(key,val){
var task = new Task({
id:val.pkTaskId,
title:val.fldName,
status:val.fldStatus
});
self.add(task);
});
}
);
}
}
The issue is that this is not what you think it is in the Ajax callback. The callback function is not called in the object's context, it is called in the global context (so this will point to the window object).
Saving an object reference (by convention called self) beforehand is necessary.
this will not always point to the object instance a function "belongs to". In fact, a function does not belong to an object in the same way it does in other languages. this maintains the context a function is called in. Any function can be called in any context:
function A() {
this.val = "foo";
this.say = function () { alert( "A: " + this.val ); };
}
function B() {
this.val = "bar";
this.say = function () { alert( "B: " + this.val ); };
}
function test() { alert( "T: " + this.val ); }
var a = new A(), b = new B();
a.say() // alerts "A: foo"
b.say() // alerts "B: bar"
b.say.call(a); // alerts "B: foo"; (.call() switches the context)
test()          // alerts "T: undefined" (val does not exist in window)
test.call(b)    // alerts "T: bar" (Ah!)
Unless you define context implicitly (b.say() implies that this will be b) or explicitly (by using call() or apply()), the context will be the global context - which in a browser is the window object. And that's exactly the case for your Ajax callback.
The context for jQuery Ajax callbacks is an object that represents the options used to make the Ajax request. That is, the options object passed to the call to $.ajax(options), merged with $.ajaxSettings. You can override the context by setting the context option. This means calling $.ajax() instead of $.getJSON().
$.ajax({
context: this,
url: url,
dataType: 'json',
success: callback
});
Use this syntax:
function List() {
this.tasks = new Array();
}
List.prototype.add = function(taskItem) {
this.tasks.push(taskItem);
}
var list = new List();
list.add(…);
Also, try to improve your accept rate, people will be more willing to help you.
To build off of Tomalak's answer, you could move the declaration of "self" to the main object level. This has proven to be pretty useful in the case of using this within nested object functions.
function List(){
var self = this;
self.tasks = new Array();
self.add = function(taskItem){
self.tasks.push(taskItem);
};
self.load = function(url){
$.getJSON(
url,
function(data){
$.each(data, function(key,val){
var task = new Task({
id:val.pkTaskId,
title:val.fldName,
status:val.fldStatus
});
self.add(task);
});
});
}
}
var userList = new List();
userList.load(url);

Assigning scope amongst jQuery.getJSON and a JS.Class

I'm trying to assign some JSON data to a property of a JS.Class instance.
var MyClass = new JS.Class({
initialize: function(uuid) {
this.uuid = uuid;
},
write: function() {
$.getJSON(url+"?callback=?", {}, function(data) {
Assign(data);
});
function Assign(data) { this.content = data; };
}
});
var m = new MyClass("uuid_goes_here");
m.write();
The JSON is received asynchronously, which is why there's a function call within the $.getJSON callback.
The problem I have now is that the this.content within the Assign function is not within the scope of the instance method named write. So whereas this.uuid returns correctly, this.content remains undefined (as you would expect).
Any ideas on how to correct this? I've tried using a global variable as a workaround but the async call doesn't allow for that (plus it's a crappy solution).
Some points to note, in case they matter: I have to use JSONP, so the "?callback=?" has to stay, and I'd like to keep it async.
I would usually go for either czarchaic's version, or replace Accept with a bound method from the object. What you have to bear in mind is that calling Accept() like that (as a function call rather than a method call) will bind this to the global object, i.e. window. I'd try this:
var MyClass = new JS.Class({
initialize: function(uuid) {
this.uuid = uuid;
},
write: function() {
$.getJSON(url+"?callback=?", {}, this.method('setContent'));
},
setContent: function(data) {
this.content = data;
}
});
See http://jsclass.jcoglan.com/binding.html for more info.
You should cache the current instance in the write method and update it after ajax.
write: function() {
var self=this;
$.getJSON(url+"?callback=?", {}, function(data) {
self.data=data;
});
}

Javascript function (type) to store & use data

I really never used a javascript function type or class before, I understand Java and Python, but not javascript. So, I build a class like this:
function FormStore (type) {
this.setup = () =>{
this.store = {};
this.ERR_LINE_PREFIX = '#err_';
this.NO_DISPLAY_CLASS = 'no-display';
this.settings = {
'myID':{'hide':false},
}
}
this.checkVal= () => {
var geoArr = ['id_xx','myID', (...)];
var id;
$.each( geoArr, function(val) {
id = geoArr[val];
console.log(this.store) //-> returns undefined, below line is error
if (!(this.store[id])) {
return false;
}
});
};
var FS = new FormStore();
FS.setup();
The store is filled by components on document.ready. There is a function that looks up if the aligned components (glyph, label, input) have some classes or values and for the specific component fills a dict: {label:false,glyph:false, input:false}. However, for some reason it doesn't matter. Even if I enter some values in to the store right away (in setup) or create them on the fly, in checkVal the store doesn't exist, it's undefined.
Please, anybody, what am I not understanding about javascript type and classes here? I am googling this a lot and trying to find good resources but, "javascipt variable class" (or type) just yields a lot of DOM manipulation.
edit
There is a context problem in checkVal, you are using a non-arrow (and not explicitly bound) callback function and trying to access this inside of it. Change that to an arrow function as well, and the parent context (this) will be preserved:
$.each( geoArr, (val) => {
id = geoArr[val];
console.log(this.store)
if (!(this.store[id])) {
return false;
}
});
And while you are at changing that section, it's not going to work. You will not get access to $.each's return value. You should rely on native array APIs for this task and use Array.every to determine if all geoArr items are in the store (assuming that's your goal):
// returns false if not all geoArr items are in the store
geoArr.every(id => this.store[id])
original
I don't see you calling checkVal() anywhere, but based on the error you are getting it is called prior to setup() (since setup initializes the store). You could solve that problem straight away by moving this.store = {} out of setup (right at the top), e.g.:
function FormStore(type) {
this.store = {};
...
Having said that, I would suggest either defining your methods on the prototype, or utilizing ES6 classes. Here is a simplified version of both:
ES5 class
function FormStore(type) {
// make sure user didn't forget new keyword
if (this === window) {
throw new Error('FormStore must be called with "new" keyword')
}
// initialize state, this is the constructor
this.type = type;
this.store = {};
// any other state the class manages
}
FormStore.prototype = {
setup: function() {
// do setup stuff
// "this" points to instance
console.log('setup', this.type)
},
checkVal: function() {
}
}
var formStore = new FormStore('foo')
console.log(formStore.store) // <-- not undefined
formStore.setup()
ES6 Class
class FormStore {
constructor(type) {
this.type = type;
this.store = {};
}
setup() {
console.log('setup', this.type)
}
checkVal() {
}
}
const formStore = new FormStore('bar')
console.log(formStore.store) // <-- not undefined
formStore.setup()
It has to do with scoping. Your $.each in checkVal has a normal function. Inside the function the scope if this is different. If you want to keep the original scope you could use a fat arrow function like you do when defining the methods.
this.checkVal= () => {
var geoArr = ['id_xx','myID', (...)];
var id;
$.each( geoArr, val => {
id = geoArr[val];
console.log(this.store) //-> returns undefined, below line is error
if (!(this.store[id])) {
return false;
}
});
}
When you run your original code and place a breakpoint on the line with console.log you can see in the inspector that this is set to the Window object and no longer points to your FormStore.
function FormStore () {
this.setup = function(){
this.store = {};
this.ERR_LINE_PREFIX = '#err_';
this.NO_DISPLAY_CLASS = 'no-display';
this.settings = {
'myID':{'hide':false},
}
}
this.checkVal= function(){
var geoArr = ['id_xx','myID'];
var id;
$.each( geoArr, function(val) {
id = geoArr[val];
console.log(this.store) //-> returns undefined, below line is error
if (!(this.store[id])) {
return false;
}
});
}
};
var FS = new FormStore();
FS.setup();
Works absolutely fine, the code you provided had a missing bracket and you were using some broken es6 syntax

Categories

Resources