I am trying to save the results of a Socrata Query Language or SoQL query into a variable that I can use elsewhere. I think I understand that because of the async nature of ajax, I can't count on the value being available outside of the $.ajax().done() block, but I can't understand how to get the value out of the block.
let gasAve;
let settings = {
"async": true,
"crossDomain": true,
"url": "https://data.colorado.gov/resource/xyh2-p9cg.json?%24select=avg(allgradesgasprice)&%24where=date%20between%20'2017-01-01T12%3A00%3A00'%20and%20'2017-12-31T11%3A59%3A59'",
"method": "GET",
}
$.ajax(settings).done(function (response) {
console.log(response); // logs [Object {avg_allgradesgasprice="2.4292307692307692"}]
let [{"avg_allgradesgasprice":gasAve}] = response; // destructure the object
console.log(gasAve); // Within the block, I get the value 2.429....
});
console.log(gasAve); // Outside of the block I get undefined.
Couple gotachas here.
First is with the destructuring you're attempting. Within the scope of the anonymous function where you are processing the response, the let redeclares gasAve. This is separate from the original declaration, and the value thus was never assigned to your first declaration of gasAve. Getting rid if the let in your destructure operation will assign the value correctly within the scope you are expecting.
Second, the function that processes your response is executing asynchronously i.e. after the ajax call is made and the response is received. The console.log outside the anonymous declaration executes before the value is assigned chronologically. The easy way to avoid this problem is to do all your work within the context of a the response processing function or from a function that is called from it. Something like this:
let gasAve;
let settings = {
"async": true,
"crossDomain": true,
"url": "https://data.colorado.gov/resource/xyh2-p9cg.json?%24%24app_token=gNqVzSHJ7pWovzVu8pRHdiMHe&%24select=avg(allgradesgasprice)&%24where=date%20between%20'2017-01-01T12%3A00%3A00'%20and%20'2017-12-31T11%3A59%3A59'",
"method": "GET",
}
$.ajax(settings).done(function (response) {
console.log(response); // logs [Object {avg_allgradesgasprice="2.4292307692307692"}]
[{"avg_allgradesgasprice":gasAve}] = response; // destructure the object
console.log(gasAve); // Within the block, I get the value 2.429....
displayStuff();
});
function displayStuff() {
console.log(gasAve)
}
Related
I had an assignment where I need to have a http POST method which takes int start and int end parameters, then searches database and returns all Cities with population property between the mentioned parameters. Note: I have to use my custom routing for the method.
CitiesController:
[Route("api/cities/search")]
public IHttpActionResult PostSearch(int min, int max)
{
var list = db.Cities
.Where(c => c.Population > min && c.Population < max)
.OrderBy(c => c.Population);
return Ok(list);
}
This is the part in script.js where im calling .ajax POST method.
$("#searchForm").submit(function (e) {
e.preventDefault();
if (token) {
headers.Authorization = "Bearer " + token;
};
var min = $("#searchField1").val();
var max = $("#searchField2").val();
var url = host + "api/cities/search";
var sendData = {
"Min": min,
"Max": max
};
$.ajax({
type: "POST",
url: url,
data: sendData
}).done(fillDataSearch)
.fail(function (data, status) {
alert("!");
});
});
Once i click the submit button in this #searchForm, i get 405 STATUS CODE - Method not allowed Here's what it returns:
<Error>
<Message>The request is invalid.</Message>
<MessageDetail>The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Http.IHttpActionResult Get(Int32)' in 'Finalni_Kraci.Controllers.CitiesController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.</MessageDetail>
</Error>
Based on this, he's targeting GET method with parameter int id (which i do have), but i do not know why.
I tried debugging, everything seems okay until he skips to .fail part of $.ajax. I tried testing this with postman, if i put values in parameteres it works, but if i try to pass values through body
{
"Min": 50000,
"Max": 300000
}
i get 405 Status code again with message: The requested resource does not support http method 'POST'.
I am not really sure what is the correct way to do it. So far i tried what i provided but i am losing idea of what i am doing wrong. Let me know if i need to provide anything else.
This was a silly mistake, i had to use filter object as a parameter for my server's POST method, not two integers.
This is solved.
I keep getting this Vue error: "ReferenceError: response is not defined" but when I check in the console, the data is all there.
I intend to use the data from the response to make pagination. Thanks in advance.
Methods
getAllUserData(){
let $this=this;
axios.get('api/members/getAllMembersData').then(response=>this.members=response.data.data);
$this.makePagination(response.meta,response.links);
},
makePagination(meta,links){
let pagination={
current_page:meta.current_page,
last_page:meta.last_page,
next_page_url:links.next,
prev_page_url:links.prev
}
this.pagination = pagination;
}
axios.get() is an async function. The code that follows this function will not be executed after the ajax request completes, but long before that. Because of this, the variable response does not exist yet.
All code that has to be executed when the ajax call completes has to be put in the .then() function of the call.
getAllUserData(){
axios.get('api/members/getAllMembersData').then(response => {
this.members = response.data.data;
this.makePagination(response.data.meta, response.data.links);
});
},
Your response is still inside the axios get method, therefore the makePagination function has to be called inside axios method as well (inside .then())
getAllUserData(){
let $this=this;
axios.get('api/members/getAllMembersData').then(response=>
this.members=response.data.data
$this.makePagination(response.data.meta,response.data.links);
},
makePagination(meta,links){
let pagination={
current_page:meta.current_page,
last_page:meta.last_page,
next_page_url:links.next,
prev_page_url:links.prev
}
this.pagination = pagination;
}
I do have a kendo datasource which populates a kendo template.
var remoteTemplate = kendo.template($("#remotetemplate").html(), {
useWithBlock: false });
var remoteDatasource = new kendo.data.DataSource({
transport: {
read: {
url: 'Home/RemoteData',
}
},
change: function () {
$("#remotemovies tbody").html(kendo.render(remoteTemplate, this.view()));
}
});
A GET request is made to Home/RemoteData when we call the read method remoteDatasource.read()
One more read , another request is made to Home/RemoteData
I know this is not good , but I am trying to understand this :-)
remoteDatasource.read()
So far good , however once more time I call the read() , GET request is
not happening. Why is that? remoteDatasource.read()
No Get request here no matter how many times I call after this
Also I noticed the same behaviour with fetch() method.
Can someone explain me why is this behaviour? also what is the difference between read and fetch.
The read() method is supposed to request the remote service every time.
The fetch() method only requests the remote service the first time.
Your particular read() may not be requesting the remote service because it is caching. Can you try your request as a POST or set the configuration in transport.read.cache to false?
http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-transport.read.cache
It seems to optimize the behavior Kendo is limiting the number of calls to two if you call datasource.read() in successive lines. Which is fair as there is no need in practical scenario to have such a code.
Here are the two types of code i have written.
Scenario 1 : Calling the datasource.read() in response to a button click.
$("#remoteRequestBtn").click(function () {
var remoteTemplate = kendo.template($("#remotetemplate").html(), { useWithBlock: false });
var remoteDatasource = new kendo.data.DataSource({
transport: {
read: {
cache: false,
url: 'Home/RemoteData',
}
},
change: function () {
$("#remotemovies tbody").html(kendo.render(remoteTemplate, this.view()));
}
});
remoteDatasource.read();
});
Result : A Get request is called to the web api , whenever i click the button.
Scenario 2 : Calling multiple datasource.read() in response to a button click.
$("#remoteRequestBtn").click(function () {
var remoteTemplate = kendo.template($("#remotetemplate").html(), { useWithBlock: false });
var remoteDatasource = new kendo.data.DataSource({
transport: {
read: {
cache: true,
url: 'Home/RemoteData',
}
},
change: function () {
$("#remotemovies tbody").html(kendo.render(remoteTemplate, this.view()));
}
});
remoteDatasource.read();
remoteDatasource.read();
remoteDatasource.read();
remoteDatasource.read();
});
Note : I am calling the read method 4 times , Now if you ask me if this is a valid scenario :-) It is not :-)
Result : In this case i get only two GET requests (For the first and second read() , Rest of the reads are ignored )
As of now i would like to treat this as an optimization from the Kendo-UI side , unless someone comeback and correct it.
Special Thanks to JFlok & CodingWithSpike for giving right directions.
Does your change callback or any other Javascript throw an exception? Try removing your change handler function. I've seen issues in the past where if an uncaught exception is thrown while the DataSource is trying to process the server response, then the DataSource is left in a state where it thinks the previous request is still running (because it never finished due to the error) and won't do another request.
I have the following code, where I have a myBool (a boolean) in my Data Browser initially set to false,
however sometime while I'm still viewing my page I have code set to turn it to true.
How can I make a real time update that will automatically hide my #div when myBool turns to true?
var myBool = currentUser.get("myBool");
if(myBool) {
$('#div').hide();
}
I did some research and found that the Parse.Cloud.afterSave() function may be useful, but I don't see how it will update the content automatically?
Hope I've been clear!
Thanks.
Edit:
Possibly something like this in my main.js?
Parse.Cloud.afterSave("setBool", function() {
var query = new Parse.Query(Parse.Installation);
query.equalTo('myBool', true);
Parse.Push.send({
where: query,
}, {
success: function() {
$('#div').hide();
},
error: function(error) {
$('#div').show();
}
});
});
Your problem with your afterSave function is that your calling it for a function rather than a class.
AfterSave is called after an object from a certain class is saved. If your bool
Parse.Cloud.afterSave(Parse.Installation, function(request) {
// Send push here, use request to target correct user
});
Additionally your push listener should be the one modifying the divs, not the CloudCode.
I'm having difficulty accessing requestJSON on a jQuery $.ajax object outside of the success callback. If I do:
var ajax_request = $.ajax({
dataType: 'json',
contentType: 'application/json'
});
console.log(ajax_request.responseJSON);
// this results in `undefined`
How can I access the responseJSON without adding a .success() callback? If I inspect ajax_request in Firebug, I can see the responseJSON property, and the data I expect, but I can't access it via:
ajax_request.responseJSON
More specifically, I'm building an SPA using Sammy and Knockout. In some routes, I need to be able to get JSON from cache, and if it doesn't exist, get the value from a service call and then set it into cache:
var cached_json = storage.fetch('cached_json', function() {
// make service call
return $.getJSON(url);
});
event_context.render('template.tpl', {'json': cached_json}).appendTo('#my-target');
But, of course, calling storage.fetch doesn't cause the rest of the code to pause until $.getJSON is complete. This is the part I can't quite figure out how to structure.
here's how i would implement it
responseJSON = "";
$.get("myurl.php",function(jdata){
responseJSON = jdata;
},"json");
i like to see the ajax method at a glace, but in your case you can do the same by
....
success : function(jdata){ responseJSON = jdata; }
....
PS: i believe that initializing the blank responseJSON is not required since any variable without var is in global scope, but it would help for clarity
I ended up solving this by creating a deferred object that gets or creates the value I need:
function get_or_create_cache(storage, key, service_endpoint) {
return $.Deferred(function(deferred) {
var c = storage.get(key);
if (c === null || c === undefined) {
$.when(jsonp_service_request(service_endpoint)).done(function(json) {
storage.set(key, json);
deferred.resolve(json);
});
}
else {
deferred.resolve(c);
}
}).promise();
}
In this function, storage refers to a Sammy.Storage instance. jsonp_service_request is a local function that returns a jsonp response, taking into account the location.hostname for local development, where I'm pointing to local.json files, or a remote environment, where I'm calling into an actual API. jsonp_service_request returns an $.ajax function.
Then in my Sammy route, I can do:
this.get('#/', function(event_context) {
$.when(get_or_create_cache(storage, 'my-cache-key', 'service-endpoint'))
.then(function(json) {
event_context.render('my-template.template', {'value-name': json})
.appendTo('#my-target');
});
});