Javascript Class - Cannot set a property - javascript

I have the below code to create a class in javascript.... Now i will only pass the ID of the 'website' and then via an ajax call i will get the rest of the information from the database (JSON ENCODED).
Now my only problem is that when i see whats in the object at the end its only showing the id.
The ajax calls works fine because if i alert this.address after success (ajax) its displaying the result.
What I presume is that I cannot set a property with an ajax request... Can you help?
function website(id) {
this.id = id; //id
$.ajax({ //website_information
type: "GET",
url: '/proc.php?proc=website_name&id=' + this.id + '',
success: function(data){
var tmp = $.parseJSON(data);
this.address = tmp.website_address;
this.name = tmp.website_name;
}
});
}
var obj = new website('20');
obj.alertwebsite();
console.log(obj);

There are two problems here. The first is that $.ajax is asynchronous. That means it returns before the request is complete. The success function is run when the request is complete, but obj.alertwebsite() will be run before.
The second problem is the value of this within an AJAX callback. Within the callback, this is set to an object containing all the settings for the AJAX call. This means you are setting address and name properties on this object. There are two ways around this. The first is that = this as in other answers. The nicer way is to use the context setting in the AJAX call:
function website(id) {
this.id = id; //id
$.ajax({ //website_information
type: "GET",
url: '/proc.php?proc=website_name&id=' + this.id + '',
context: this,
success: function (data) {
var tmp = $.parseJSON(data);
this.address = tmp.website_address;
this.name = tmp.website_name;
}
});
}
This allows you to customise what this means inside the callback. This is documented in the jQuery AJAX documentation.

the this inside the AJAX callback may not be referring to the "object-to-be" that your constructor is making. Instead, we preserve the this from the outside by putting it in another variable, like say that. Then we use that to refer to our object-to-be in the AJAX callback.
function website(id) {
var that = this; //preserve "this"
this.id = id;
$.ajax({
type: "GET",
url: '/proc.php?proc=website_name&id=' + this.id + '',
success: function(data){
var tmp = $.parseJSON(data);
that.address = tmp.website_address; //using "that"
that.name = tmp.website_name; //using "that"
}
});
}
also, you are calling blindly in your obj.alertwebsite() because you don't know if your website info (that.address and that.name) has been loaded or not.

function website(id) {
// you need to save "this"
var self = this;
this.id = id; //id
$.ajax({ //website_information
type: "GET",
url: '/proc.php?proc=website_name&id=' + this.id + '',
//async: false, // optionally, if you want to get it back syncronously, so the console.log after the function call will already have the data
success: function(data){
var tmp = $.parseJSON(data);
// you need to use the saved "this"
self.address = tmp.website_address;
self.name = tmp.website_name;
}
});
}

Related

Javascript functions order

I'm making a jquery library to use an application with the json rpc protocol but I'm stuck with a little problem.
This is the fiddle that shows the code (obviously it can't work): https://jsfiddle.net/L9qkkxLe/3/.
;(function($) {
$.lib = function(options) {
var outputHTML = [],
plugin = this;
var APIcall = function(api_method, api_params) {
request = {};
request.id = Math.floor((Math.random() * 100) + 1);
request.jsonrpc = '2.0';
request.method = api_method;
request.params = (api_params) ? api_params : [];
$.ajax({
type: "POST",
url: "http://localhost:8898/jsonrpc",
data: JSON.stringify(request),
timeout: 3000,
beforeSend: function(xhr) {
xhr.setRequestHeader('Authorization', window.btoa(options.username + ":" + options.password));
},
success: function(data) {
handleData(data, api_method);
},
error: function(jqXHR, textStatus, errorThrown) {
log("Connection time out: can't reach it. Try changing the settings.");
isConnected = "false";
},
dataType: "json"
});
}
var handleData = function(data, method) {
if (method == "getgenres") {
outputHTML = data.result.genres; //I need data.result.genres to return in getgenres function
}
}
var log = function(msg) {
if (options.debug == true) console.log(msg);
}
plugin.getgenres = function() {
APIcall("getgenres");
return outputHTML; //This is sadly empty.
}
};
}(jQuery));
var init = new $.lib();
console.log(init.getgenres());
I need that the getgenres function returns data.result.genres but actually it returns an empty array because getgenres is called for first and only after the handleData function gives to outputHTML the value that I need.
You are performing an asynchronous AJAX request, which means you can't actually get back the data immediately. There are two ways to solve your issue: making it synchronous (easy but ill advised) or using a callback (a little bit more complex but generally accepted):
In your getgenres function, you could accept one more parameter: callback
plugin.getgenres = function(callback) {
/* Dont forget APIcall already took two parameters in, so callback has to be the third in line! */
APIcall("getgenres", false, callback);
}
Now modify your APIcall function to accept your callback:
var APIcall = function(api_method, api_params, callback) { ... }
And call the callback from the successful completion call - instead of having a handler method in between wrapped in a function, you can simply pass the anonymous function. So instead of success: function(data){ handle(data); }, just use:
success: callback
The anonymous function that we will pass to it will receive as its first parameter the data you were passing to the handler. Now you can do the following:
var myGenres = [];
var init = new $.lib();
init.getgenres(function(data){
/* Now your data is actually loaded and available here. */
myGenres = data;
console.log(myGenres);
});
I would like to point out that there are many better ways to handle this, including turning this into a Constructor (More here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) instead of the strange amalgamation of functions and variables you have now, as well as using JS Promises (here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) to make this easier. But the basic gist should be here.
Update (potential implementation)
Because I mentioned that this could be done in a way that I think is clearer to read and use. I do not know all use cases for this, but from the provided example I would change the code to something looking like the following. Please also note I am not an expert on jQuery plugins, so I am avoiding plugging into jQuery and just using it as an easy AJAX call.
function getAjax(){
if(!window.jQuery || !window.$) throw("jQuery is required for this plugin to function.");
this.data = [];
this.request = '';
return this;
}
getAjax.prototype = {
createRequest : function(method, parameters){
this.request = {};
this.request.id = Math.floor((Math.random() * 100) + 1);
this.request.jsonrpc = '2.0';
this.request.method = method;
this.request.params = parameters || [];
return this;
},
callRequest : function(options, callback, error){
var self = this;
// We could also `throw` here as you need to set up a request before calling it.
if(!this.request) return this;
else {
$.ajax({
// We will allow passing a type and url using the options and use sensible defaults.
type: options.type || "POST",
url: options.url || "http://localhost:8898/jsonrpc",
// Here we use the request we made earlier.
data: JSON.stringify(this.request),
timeout: options.timeout || 3000,
beforeSend: function(xhr){
xhr.setRequestHeader(
'Authorization',
window.btoa( options.username + ":" + options.password)
);
},
// We will also store all the made request in this object. That could be useful later, but it's not necessary. After that, we call the callback.
success: function(data){
var store = {request:self.request, data: data};
self.data.push(store);
// Call the callback and bind `this` to it so we can use `this` to access potentially pther data. Also, pass the results as arguments.
callback(data, self.request.id).bind(self);
},
// Error function!
error: error,
dataType: options.dataType || "json"
});
}
return this;
}
}
// Example use
new getAjax().createRequest('getgenres').callRequest({
username: 'myusername',
password: 'mypassword'
}, function(data, id){
// Success! Do with your data what you want.
console.log(data);
}, function(e){
// Error!
alert('An error has occurred: ' + e.statusText);
console.log(e);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
What I do in those occasions is this:
You are supplying a method. So put a reference to the a callback function. In this case plugin.getGenresFinalize. When handleData is called it will fire that callBack function. This way you can pass multiple methods to the api call for different types of data.
plugin.getgenres = function() {
APIcall(this.getgenresFinalize);
}
plugin.getgenresFinalize = function(data) {
console.log(data);
}
var handleData = function(data, method) {
method(data);
}

Returning an object from Web Service to Ajax Request success callback function

Hello Fellow Developers,
I have a SSN textbox that onblur calls a function which does an ajax request to a Web Method to decide if an employee has been previously hired.
The Web Method returns a TermedEmployee Object to the success callback, but I'm unsure how to parse the object.
$('#<%=FormView1.FindControl("SSNField").ClientID%>').blur(hideValue);
hideValue = function (ev) {
var $this = $(this);
$this.data('value', $this.val());
$('#<%=FormView1.FindControl("hiddenSSN").ClientID%>').val($this.val());
var data2Send = '{"SSN": ' + $this.val() + ' }';
$.ajax({
type: "POST",
url: "AuthforHire.aspx/EmployeeisRehire",
data: data2Send,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
var obj = JSON.stringify(result.d);
if (obj.IsTermed) {
$('#%=RadWindowRehire.ContentContainer.FindControl("TextBoxTermID").ClientID%>').val(arg.d);
var wndWidth = 900;
var wndHeight = 500;
var wnd = window.radopen(null, "RadWindowRehire");
}
},
error: function (xhr) {
alert('Form update failed. '); //error occurred
}
});
Below is a minified version of my webMethod, which works correctly
[System.Web.Services.WebMethod]
public static TermedEmployee EmployeeisRehire(string SSN)
{
TermedEmployee termedEmp = new TermedEmployee();
// Db call to get necessary data.
termedEmp.Name = dr["name"];
termedEmp.TermDate = Convert.ToDateTime(dr["TermDate"].ToString());
......
}
So How Can I extract Name, TermDate,StartDate, ReasonforTerm, etc from the object returned to the callback function?
Thank you in advance!
The first line in your success callback is:
var obj = JSON.stringify(result.d);
Which is trying to serialize what ASP.Net will already have serialized for you.
Change this to:
var obj = result.d;
And you will then have access to obj.Name, obj.TermDate and all the other properties by name.

jQuery AJAX issue? Or JS OOP scope issue?

I am trying to create a database handler class in javascript. I would like to call the class by simply using:
var databaseHandler = new DatabaseHandler();
result = databaseHandler.getResult("SELECT * FROM login");
I have created the class and used a callback for the ajax function (so as to wait for the ajax result to be returned). But all I am still receiving "undefined" as my result. If I use console.log(a) inside of the onComplete function, I get an array of the intended results.
(function(window){
//Database class
function DatabaseHandler(){
//Query
this.query = function(query, whenDone){
request = $.ajax({
url: "../optiMizeDashboards/php/DatabaseQuery.php",
type: "POST",
data: {query : query},
dataType: "JSON"
});
request.done(function(output) {
whenDone(output);
});
request.fail(function(jqXHR, textStatus) {
console.log(textStatus);
});
};
//Get result
this.getResult = function(query){
this.query(query, this.onComplete);
};
//Ajax callback
this.onComplete = function(a){
return a;
};
}
//Make available to global scope
window.DatabaseHandler = DatabaseHandler;
}(window))
My question is: Is this something to do with the variable scope, or the way that ajax works? I have read all the answers explaining that ajax is ASYNC and I thought I had handled that by using a callback function "onComplete"
Any help on this topic would be greatly appreciated!
You will not be able to return result immediately from calling getResult because underlying jQuery POST request is Asynchronous, instead you need to be passing a callback function which eventually will receive a result from server.
something like that:
(function(window){
//Database class
function DatabaseHandler(){
//Query
this.query = function(query, whenDone){
request = $.ajax({
url: "../optiMizeDashboards/php/DatabaseQuery.php",
type: "POST",
data: {query : query},
dataType: "JSON"
});
request.done(function(output) {
whenDone(output);
});
request.fail(function(jqXHR, textStatus) {
console.log(textStatus);
});
};
//Get result
this.getResult = function(query, callback){
this.query(query, callback);
};
}
//Make available to global scope
window.DatabaseHandler = DatabaseHandler;
}(window))
// then use it like so
var databaseHandler = new DatabaseHandler();
result = databaseHandler.getResult("SELECT * FROM login", function(data) {
//do something with data
});
PS: exposing direct SQL access to the databse on the client is very dangerous though, and I would not recommend doing that

get a callback function to add to object javascript

I have an issue with a method ive created for an object ive created. one of the methods requires a callback to another method. the problem is i cant add the data to the object that called the method. it keeps coming back as undefined. otherwise when i send the data to the console it is correct. how can i get the data back to the method?
var blogObject = new Object();
var following = [...];
//get posts from those blogs
blogObject.getPosts = function () {
var followersBlogArray = new Array();
for (var i = 0; i < this.following.length;i++){
var followersBlog = new Object();
// get construct blog url
var complete_blog_url = ...;
i call the getAvatar function here sending the current user on the following array with it.
followersBlog.avatar = blogObject.getAvatar(this.following[i]);
that part goes smoothly
followersBlogArray.push(followersBlog);
}
this.followersBlogArray = followersBlogArray;
}
here is the function that gets called with the current user in following array
this function calls an ajax function
blogObject.getAvatar = function (data) {
console.log("get avatar");
var url = "..."
this ajax function does its work and has a callback function of showAvatar
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
this function gets called no problem when getAvatar is called. i cant however get it to add the data to the followersBlog object.
blogObject.showAvatar = function (avatar) {
return avatar
}
everything in here works fine but i cant get the showAvatar function to add to my followersBlog object. ive tried
blogObject.showAvatar = function (avatar) {
this.followersBlog.avatar = avatar;
return avatar
}
that didnt work of course. it shows up as undefined. can anyone help?
so somethings like...
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
complete: function () {
this.avatar = data;
}
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
Welcome to the world of asynchronous programming.
You need to account for the fact that $.ajax() will not return a value immediately, and Javascript engines will not wait for it to complete before moving on to the next line of code.
To fix this, you'll need to refactor your code and provide a callback for your AJAX call, which will call the code that you want to execute upon receiving a response from $.ajax(). This callback should be passed in as the complete argument for $.ajax().
The correct option for setting the JSONP callback is jsonpCallback. The recommendation from the API for .ajax(...) is to set it as a function.
{
// ...
jsonpCallback: function (returnedData) {
blogObject.showAvatar(returnedData);
},
// ...
}

How to create jquery ajax as separate function?

I want to create a separate function to get specific data from Facebook graph JSON.
For example, I have the load() and called getNextFeed() function.
The getNextFeed works correctly. Except that returning value of aString is not successful.
When I pop alert(thisUrl). It said undefined.
Note: I am new to Javascript and Jquery. Please give me more information where I did wrong. Thank you.
function load()
{
$(document).ready(function() {
var token = "AccessToken";
var url = "https://graph.facebook.com/me/home?access_token=" + token;
var thisUrl = getNextFeed(url);
alert(thisUrl); // return undefined
});
function getNextFeed(aUrl)
{
$.ajax({
type: "POST",
url: aUrl,
dataType: "jsonp",
success: function(msg) {
alert(msg.paging.next); // return correctly
var aString = msg.paging.next;
alert(aString); // return correctly
return aString;
}
});
}
The problem is that $.ajax() is an ansynchronous function, means, when called, it returns in the same instance, but an ajax call is done in a separate thread. So your return vaule of $.ajax() is always undefined.
You have to use the ajax callback function to do whatever you need to do: Basically you already did it correctly, just that return aString does not return to your original caller function. So what you can do is to call a function within the callback (success()), or implement the logic directly within the success() function.
Example:
function load()
{
$(document).ready(function() {
var token = "AccessToken";
var url = "https://graph.facebook.com/me/home?access_token=" + token;
getNextFeed(url);
alert('Please wait, loading...');
});
function getNextFeed(aUrl)
{
$.ajax({
type: "POST",
url: aUrl,
dataType: "jsonp",
success: function(msg) {
alert(msg.paging.next); // return correctly
var aString = msg.paging.next;
alert(aString); // return correctly
do_something_with(aString);
}
});
}

Categories