I have a CONTACT javascript object. I call CONTACT.load() to read the data for CONTACT.id through $.ajax(). On success, I am able to use the data returned by the ajax() call. Then I save some of the read data in object properties. However, the saved property values are lost. Here is my code:
var CONTACT=
{
id: 1,
referrals_loaded: false,
city: '',
};
CONTACT.load = function(cb)
{
$.ajax({
type: "POST",
url: "contactAjax.php",
data: {
ContactID: this.id,
actionID: 'LOAD_CONTACT_DATA',
},
dataType: "json",
success: function(data) {
success = true;
var address = data['address'];
var addr = address[0];
this.city = addr['city'].trim();
console.log("City (in ajax() ):" +this.city);
var province = addr['province'].trim();
// ...
if (typeof cb==='function') (cb)();
},
error: function () {
alert("Could not load Contact data through LOAD_CONTACT_DATA .");
}
});
console.log("City (after ajax() ):" +this.city);
}
My calling code is like this:
CONTACT.id = 123456;
CONTACT.load('testtest');
function testtest() {
console.log("Contact city is " + CONTACT.city);
CONTACT.city = "London";
console.log("Contact city is " + CONTACT.city);
}
And the console.log O/P is like this:
City (in ajax() ):MARKHAM
Contact city in testtest()
Contact city is London
Notice that when I set the value for CONTACT.city again in testtest(), the object retains the property value. Could someone please explain, why the CONTACT.city becomes empty when testest() is called?
'this' refers to a different object.
CONTACT.load = function(cb)
{
var self = this; // common hack
$.ajax({
type: "POST",
url: "contactAjax.php",
data: {
ContactID: this.id,
actionID: 'LOAD_CONTACT_DATA',
},
dataType: "json",
success: function(data) {
success = true;
var address = data['address'];
var addr = address[0];
self.city = addr['city'].trim(); // <-- assign to correct object
console.log("City (in ajax() ):" +this.city);
var province = addr['province'].trim();
// ...
if (typeof cb==='function') (cb)();
},
error: function () {
alert("Could not load Contact data through LOAD_CONTACT_DATA .");
}
});
console.log("City (after ajax() ):" +this.city);
}
Related
I'm attempting to create a simple weather API that replaces handlebars placeholder variables with user input of a city name linked to an api. It works very strangely, it will display the correct data after the next input is submitted. I.E. I submit "Dayton" and the placeholder data shows up again, then I submit "New York" and Dayton's correct info pops up. If I were to submit a third city, New York would display. Any ideas on why? Here's my code:
var currentWeather = {
cityName: "London",
temperature: 86,
description: 'cloudy'
};
var addCurrentWeather = function(data) {
var weather = {
cityName: data.name,
temperature: data.main.temp,
description: data.weather[0].main
}
};
var renderCurrentWeather = function () {
var weather= currentWeather;
var source = $('#weather-template').html();
var template = Handlebars.compile(source)
var weatherHTML = template(currentWeather);
$('#city').append(weatherHTML);
};
// fetch applying user input to grab data from api
var fetchCurrentWeather = function (query) {
$.ajax({
method: "GET",
url: "https://api.openweathermap.org/data/2.5/weather?q=" + query + "&APPID=MYKEY",
dataType: "json",
success: function (data) {
addCurrentWeather(data);
renderCurrentWeather();
currentWeather = {
cityName: data.name,
temperature: data.main.temp,
description: data.weather[0].main
}
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
}
});
};
$('#search').on('click', function () {
var search = $('#search-query').val();
console.log(search);
fetchCurrentWeather(search);
});
renderCurrentWeather();
I will assume that you expect from your code to do following in the success handler.
Update your global weather object
Use that global object to render your template
That does not happen because your function addCurrentWeather does essentially nothing as it updates a local variable and discards it.
So make sure that this function instead updates the global variable.
var addCurrentWeather = function(data) {
currentWeather = {
cityName: data.name,
temperature: data.main.temp,
description: data.weather[0].main
}
};
and in the success handler you should have then only
addCurrentWeather(data);
renderCurrentWeather();
Reason why it then currently works the way it does is because after you call the render function you later update the global variable directly hence why this data is then used on next api fetch.
As a suggestion, try to avoid using global variables as it is easy to create bugs like this. Instead try to use pure functions as it will also help if you start unit test your code.
In your case have addCurrentWeather function accept data and return a weather object. And similarly have the render method accept weather object instead of reading it from global var.
Something like this
function getCurrentWeather(data) {
return {
cityName: data.name,
temperature: data.main.temp,
description: data.weather[0].main
}
};
function renderCurrentWeather(weather) {
var source = $('#weather-template').html();
var template = Handlebars.compile(source)
var weatherHTML = template(currentWeather);
$('#city').append(weatherHTML);
};
function fetchCurrentWeather(query) {
$.ajax({
method: "GET",
url: "https://api.openweathermap.org/data/2.5/weather?q=" + query + "&APPID=MYKEY",
dataType: "json",
success: function (data) {
const weather = getCurrentWeather(data);
renderCurrentWeather(weather);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
}
});
};
$('#search').on('click', function () {
var search = $('#search-query').val();
console.log(search);
fetchCurrentWeather(search);
});
fetchCurrentWeather('London');
I have to get values from two different URLs and then to merge it. I know it would much better if i'll get all of the data in one URL, but that's how i've got and i need to work with it.
I want to print out the value of a_value, but it's been printed out while b hasn't returned his value. I've read some articles of how to make the functions synchronous but still don't know how to implement it into my code, and don't know what is the best solution for my case. I'm pretty new with JavaScript and still need some help and guiding.
function any_function() {
$.ajax(
{
url : '/url1',
type: "GET",
success:function(data, textStatus, jqXHR)
{
$("#print").html(a(data));
}
});
}
function a(data){
x = 'any value' //`do something with data and insert to this variable`
a_value = x + b(`some id that extracted from data`)
return a_value
}
function b(id){
$.ajax({
url: '/url2',
type: 'GET',
success: function (data, textStatus, jqXHR) {
b_value = c(data, id)
}
});
return b_value
}
function c(data, id){
//do something with `data` and return the value
return c_value
}
function f() {
var request1 = $.ajax({
url : '/url1',
type: 'GET'
});
var request2 = $.ajax({
url: '/url2',
type: 'GET'
});
$.when(request1, request2).done(function(result1, result2){
data1 = result1[0]
data2 = result2[0]
// r1 and r2 are arrays [ data, statusText, jqXHR ]
// Do stuff here with data1 and data2
// If you want to return use a callback or a promise
})
}
This can be done in a synchronous-looking fashion with promises:
$.get(url1)
.then(function(data1){
return $.get(url2)
})
.then(function(data2){
return $.get(url3);
})
.then(function(data3){
// All done
});
You just need to make the second call in the success handler of the first one:
function any_function() {
$.ajax({
url : '/url1',
type: "GET",
success:function(data, textStatus, jqXHR) {
$("#print").html(a(data));
b("someId");
}
});
}
function a(data){
x = 'any value' //`do something with data and insert to this variable`
a_value = x + b(`some id that extracted from data`)
return a_value;
}
function b(id){
$.ajax({
url: '/url2',
type: 'GET',
success: function (data, textStatus, jqXHR) {
b_value = c(data, id);
return b_value;
}
});
}
function c(data, id){
//do something with `data` and return the value
return c_value
}
I have been using knockout.js for a while now, and haven't encountered this problem before. Usually, when I try to push a new js object to an observableArray, it works without an issue, but for some reason, this time around I'm getting this error:
TypeError: self.Students.push is not a function
Here is a snippet of my code:
window.ApiClient = {
ServiceUrl: "/api/students",
Start: function () {
var viewModel = ApiClient.ViewModel(ngon.ClientViewModel);
ko.applyBindings(viewModel);
viewModel.get();
}
};
ApiClient.ViewModel = function(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
this.get = function (id) {
if (id == undefined) {
return ApiClient.Service.get(self.PageSize(), self.PageNumber(), function (data) {
self.Students(data);
});
}
}
this.post = function () {
return ApiClient.Service.post(self.DetailedStudent, function (data) {
self.Students.push(data);
});
}
return this;
}
ApiClient.Service = function () {
var _get = function (pageSize, pageNumber, callback) {
sv.shouldShowLoading = false;
var queryParams = String.format("?pageSize={0}&pageNumber={1}", pageSize, pageNumber);
$.ajax(ApiClient.ServiceUrl + queryParams, {
dataType: "json",
type: "get",
success: callback
});
}
var _post = function (student, callback) {
$.ajax(ApiClient.ServiceUrl, {
data: ko.mapping.toJSON(student),
type: "post",
contentType: "application/json; charset-utf-8",
statusCode: {
201 /*Created*/: callback,
400 /*BadRequest*/: function (jqxhr) {
var validationResult = $.parseJSON(jqxhr.responseText);
alert(jqxhr.responseText);
}
}
});
}
return {
get: _get,
post: _post
};
}();
$(document).ready(function () {
ApiClient.Start();
});
My student object is a very simple C# object that has Id, FirstName, LastName. The get() function works without any issues, it's just the callback function from the post() that cannot push the resulting data. Also, the data being returned back from the server looks correct:
{"Id":"rea","FirstName":"asdf","MiddleName":null,"LastName":"rrr"}
I solved this! It's because the initial viewModel, when being instantiated by the page's view model object had 'null' for its Students property.
knockout.js requires non-null values for all fields that are to be auto mapped.
I'm attempting to get started with google wallet and am generating a jwt token via an ajax request.
When a user hits the purchase button it fires the purchase() function which in turn sends off some data to get the jwt using the get_jwt_token_for_user() function. I've set the ajax request to not be asynchronous to ensure that the jwt is sent to the google payments handler.
However the purchase() function seems to continue before the jwt is returned by the get_jwt_token_for_user() function. The log output shows that the numbers 1 and 2 are printed to console before the jwt is printed to the console from the get_jwt_token_for_user() function.
function get_jwt_token_for_user(the_key)
{
var JwtTokenURL = "/get_jwt_token";
var the_user_name = $('#user_name').val();
var the_user_email = $('#user_email').val();
var the_user_number = $('#user_number').val();
$.ajax({
type: "Get",
url: JwtTokenURL,
data: {user_number : the_user_number, user_name : the_user_name, user_email : the_user_email, the_d_key : the_key},
async: false,
success: function(result) {
var myObject = JSON.parse(result);
console.log(myObject.jwt_token);
return myObject.jwt_token
},
failure: function(fail){ alert(fail); }
});
}
function purchase(the_key)
{
console.log("1");
var jwt_token = get_jwt_token_for_user(the_key);
console.log("2");
if (jwt_token !== "")
{
console.log(jwt_token);
goog.payments.inapp.buy({
parameters: {},
'jwt' : jwt_token,
'success' : successHandler,
'failure' : failureHandler
});
}
}
Any idea what I can do to ensure that the ajax request has returned the data before the purchase() function marches on without the jwt value?
Your get_jwt_token_for_user function doesn't return anything, you need something more like this:
function get_jwt_token_for_user(the_key) {
//...
var myObject;
$.ajax({
//...
success: function(result) {
myObject = JSON.parse(result);
},
//...
});
return myObject ? myObject.jwt_token : '';
}
Returning something from your success callback doesn't cause that value to be returned by $.ajax and JavaScript functions do not return the value of their last expressions, you must include an explicit return if you want your function to return something.
You should also stop using async:false as soon as possible, it is rather user-hostile and it is going away. Your code should look more like this:
function get_jwt_token_for_user(the_key, callback) {
//...
$.ajax({
type: "Get",
url: JwtTokenURL,
data: {user_number : the_user_number, user_name : the_user_name, user_email : the_user_email, the_d_key : the_key},
success: function(result) {
var myObject = JSON.parse(result);
callback(myObject.jwt_token);
},
failure: function(fail){ alert(fail); }
});
}
function purchase(the_key) {
get_jwt_token_for_user(the_key, function(jwt_token) {
if (jwt_token !== "") {
//...
}
});
}
I am using jQuery to save the values of my javascript objects. I need to retreive the ID of inserted object from the database. I know how to do it, if the Save function is within the javascript object (see code below). But how can I set the ID variable, if the Save function is not in the javascript object?
Working:
Person = function() {
var self = this;
self.ID;
self.Name;
self.SurName;
self.Save = function() {
$.ajax({
type: "POST",
url: "Save",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ Name: self.Name, SurnName: self.SurName }),
dataType: "json",
success: function (result) {
var ID = result.d.ID; //this is the ID retreived from database
self.ID = ID; //set the ID, it works, since I can reference to self
}
});
};
}ยจ
So how would I now implement a function (outside the Person class!) like:
SavePerson = function(p) {
$.ajax({
type: "POST",
url: "Save",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ Name: p.Name, SurnName: p.SurName }),
dataType: "json",
success: function (result) {
var ID = result.d.ID; //this is the ID retreived from database
p.ID = ID; //set the ID, it doesn't work, becouse if I call SavePerson repetedly for different objects, a p will not be a correct person.
}
});
};
Just to clarify, you would like the Person object id property to be updated with the recent save? If so the following script would suffice. I have used deferred's to ensure that p.ID is only updated upon completion of the asynchronous request.
$.Person = function() {
var self = this;
self.ID;
self.Name;
self.SurName;
}
$.SavePerson = function() {
var dfd = $.Deferred();
$.ajax({
type: "POST",
url: "Save",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ Name: p.Name, SurnName: p.SurName }),
dataType: "json",
success: dfd.resolve
});
return dfd.promise();
};
var p = new $.Person();
$.SavePerson().then(function(result){
p.ID = result.d.ID;
});
There may be better ways to do this but I'd have my database also return the Name and Surname along with the ID, then search my Person list to find the correct object in the success function.
Perhaps this is what you desire?
I borrowed some code here:
/*** makeClass() ***
* The following allows us to easily create
* Javascript classes. Source of this:
* http://ejohn.org/blog/simple-class-instantiation/
* makeClass - By John Resig (MIT Licensed)
*/
function makeClass() {
return function(args) {
if (this instanceof arguments.callee) {
if (typeof this.init == "function") this.init.apply(this, args.callee ? args : arguments);
} else return new arguments.callee(arguments);
};
});
/* set up ajax */
$.ajaxSetup({
async: false,
type: "POST",
contentType: "application/json",
converters: {
"json jsond": function(msg) {
return msg.hasOwnProperty('d') ? msg.d : msg;
}
},
data: '{}',
dataType: "json",
error: function(jqXHR, status, error) {
alert("An error occurred on the server. Please contact support.");
}
});
/* set up my person class */
var personClass = makeClass();
personClass.prototype.init = function() {
this.ID = '';
this.SurName = '';
this.Name = '';
}
/* create my save function */
personClass.prototype.SavePerson = function(p) {
this.Name = (typeof p === 'undefined') ? this.Name : p.Name;
this.SurName = (typeof p === 'undefined') ? this.SurName : p.SurName;
$.ajax({
url: "Save",
data: JSON.stringify({
Name: this.Name,
SurnName: this.SurName
}),
success: function(result) {
var ID = result.ID; //ID from database
this.ID = ID; //set the ID,
}
});
};
//create two persons
var person1 = personClass();
var person2 = personClass();
//set person1 to be fred
person1.Name = "Fred";
person1.SurName = "Flintstone";
// independent person
var p = {Name: "Barney", SurName: ""};
p.Surname = "Rubble";
//save specific and the independent (as person2)
person1.SavePerson();
person2.SavePerson(p);
//alert the ID of both
alert(person1.ID + ":" + person2.ID);