I have this function in an angular service that I want to call multiple times throughout my app.
Version 1
getNearbyRestaurants: function(){
$http.get(url)
.success(function(data){
console.log("works here")
// do stuff with the data
})
.error(function(){
console.log("got an error");
// do stuff with the error
});
}
Version 2
getNearbyRestaurants: function(lat, lng){
var latLng = "ll=" + lat + "," + lng
return $http.get(url + latLng)
}
The first time I call this function all is well, but any subsequent calls won't do anything. I make it into the function just fine, but the $http service doesn't actually make a call to the url and neither the success nor the error functions get called. I'm not entirely sure what's wrong here. It should work everytime. Am I missing some basic understanding of the $http service?
So I resolved this issue. What was happening was I was calling the function from outside of Angular (from the google maps event callback). So all I needed to do was wrap the function call in $rootScope.$apply and everything worked perfect.
Related
I am trying to load a GeoJSON file and to draw some graphics using it as a basis with D3 v5.
The problem is that the browser is skipping over everything included inside the d3.json() call. I tried inserting breakpoints to test but the browser skips over them and I cannot figure out why.
Code snippet below.
d3.json("/trip_animate/tripData.geojson", function(data) {
console.log("It just works"); // This never logs to console.
//...all the rest
}
The code continues on from the initial console.log(), but I omitted all of it since I suspect the issue is with the d3.json call itself.
The signature of d3.json has changed from D3 v4 to v5. It has been moved from the now deprecated module d3-request to the new d3-fetch module. As of v5 D3 uses the Fetch API in favor of the older XMLHttpRequest and has in turn adopted the use of Promises to handle those asynchronous requests.
The second argument to d3.json() no longer is the callback handling the request but an optional RequestInit object. d3.json() will now return a Promise you can handle in its .then() method.
Your code thus becomes:
d3.json("/trip_animate/tripData.geojson")
.then(function(data){
// Code from your callback goes here...
});
Error handling of the call has also changed with the introduction of the Fetch API. Versions prior to v5 used the first parameter of the callback passed to d3.json() to handle errors:
d3.json(url, function(error, data) {
if (error) throw error;
// Normal handling beyond this point.
});
Since D3 v5 the promise returned by d3.json() will be rejected if an error is encountered. Hence, vanilla JS methods of handling those rejections can be applied:
Pass a rejection handler as the second argument to .then(onFulfilled, onRejected).
Use .catch(onRejected) to add a rejection handler to the promise.
Applying the second solution your code thus becomes
d3.json("/trip_animate/tripData.geojson")
.then(function(data) {
// Code from your callback goes here...
})
.catch(function(error) {
// Do some error handling.
});
Since none of the answers helped, I had to find the solution on my own that works. I am using v4 and have to stick with it. The problem was (in my case) that d3.json worked the first time, but did not work the second or third time (with a HTML dropdown).
The idea is to use the initial function, and then simply to use a second function with
let data = await d3.json("URL");
instead of
d3.json("URL", function(data) {
Therefore, the general pattern becomes:
async function drawWordcloudGraph() {
let data = await d3.json("URL");
...
}
function initialFunction() {
d3.json("URL", function (data) {
...
});
}
initialFunction();
I have tried several approaches, and only this worked. Not sure if it can be simplified, please test on your own.
I have a requirement that I need to create a service in Angular 1 and load data with an API call which can be accessed in controllers. I earlier tried by making a API call with $http service and assigning the data to the variable / object. I then injected the service and assigned the variable / object to the controller scope variable / object.
What I observed in the controller event loop is not same as service event loop and controller scope variable / object remains undefined. Later I got a solution to work by returning a promise from the service, and calling the promise in the controller, however I'm new to promises and not able to fully absorb that when I called a promise, I had to pass the function as argument which I think is a callback for the $http API call, but I'm uncertain how it's working under the hood. Can someone explain it?
//service code
this.getuserimages = function(uname) {
console.log("Username in UserImage Service: " + uname);
var promise = $http.get('/api/images/' + uname).then(function(response) {
this.userimages = response.data;
return this.userimages;
});
return promise;
}
// controller code
var userimagespromise = userImageService.getuserimages($routeParams.username);
userimagespromise.then(function(data) {
$scope.userimages = data;
Your code is a Promise chain.
I rewrited your code in a way that this chain is more clear, but the meaning is exactly the same:
$http.get('/api/images/' + uname)
.then(function(response) {
this.userimages = response.data;
return this.userimages;
})
.then(function(images) {
$scope.userimages = images;
});
You can read this flow in this way:
Please get me user images
And then, we they will be available (=> returned from the get and passed to the then function), save them in a variable and return them to the next element of the chain
And then, we they will be available (=> return from the previous promise), set them in the $scope
Please note that the entire flow is asynchronous because every Promise is "an object representing the eventual completion or failure of an asynchronous operation".
You can find more information in the Promise documentation.
I am trying to load a GeoJSON file and to draw some graphics using it as a basis with D3 v5.
The problem is that the browser is skipping over everything included inside the d3.json() call. I tried inserting breakpoints to test but the browser skips over them and I cannot figure out why.
Code snippet below.
d3.json("/trip_animate/tripData.geojson", function(data) {
console.log("It just works"); // This never logs to console.
//...all the rest
}
The code continues on from the initial console.log(), but I omitted all of it since I suspect the issue is with the d3.json call itself.
The signature of d3.json has changed from D3 v4 to v5. It has been moved from the now deprecated module d3-request to the new d3-fetch module. As of v5 D3 uses the Fetch API in favor of the older XMLHttpRequest and has in turn adopted the use of Promises to handle those asynchronous requests.
The second argument to d3.json() no longer is the callback handling the request but an optional RequestInit object. d3.json() will now return a Promise you can handle in its .then() method.
Your code thus becomes:
d3.json("/trip_animate/tripData.geojson")
.then(function(data){
// Code from your callback goes here...
});
Error handling of the call has also changed with the introduction of the Fetch API. Versions prior to v5 used the first parameter of the callback passed to d3.json() to handle errors:
d3.json(url, function(error, data) {
if (error) throw error;
// Normal handling beyond this point.
});
Since D3 v5 the promise returned by d3.json() will be rejected if an error is encountered. Hence, vanilla JS methods of handling those rejections can be applied:
Pass a rejection handler as the second argument to .then(onFulfilled, onRejected).
Use .catch(onRejected) to add a rejection handler to the promise.
Applying the second solution your code thus becomes
d3.json("/trip_animate/tripData.geojson")
.then(function(data) {
// Code from your callback goes here...
})
.catch(function(error) {
// Do some error handling.
});
Since none of the answers helped, I had to find the solution on my own that works. I am using v4 and have to stick with it. The problem was (in my case) that d3.json worked the first time, but did not work the second or third time (with a HTML dropdown).
The idea is to use the initial function, and then simply to use a second function with
let data = await d3.json("URL");
instead of
d3.json("URL", function(data) {
Therefore, the general pattern becomes:
async function drawWordcloudGraph() {
let data = await d3.json("URL");
...
}
function initialFunction() {
d3.json("URL", function (data) {
...
});
}
initialFunction();
I have tried several approaches, and only this worked. Not sure if it can be simplified, please test on your own.
Gist:
I spy on get method of my rest service:
spyOn(restService, 'get').and.callFake(function () {
return deferred.promise;
});
The method I am trying to test is myService.getFormData() that returns a chained promise:
function getFormData() {
var getPromise = this.restService.get(endPoint, params, true);
var processedDataPromise = then(successHandle, failHandler);
return processedDataPromise;
}
Back to Jasmine spec, I invoke getFormData function and make assertions:
var processedDataPromise = myService.getFormData();
processedDataPromise.then(function(data) {
expect(data).not.toBeNull();
});
deferred.resolve(testFormData);
$rootScope.$digest();
The Problem:
The above derivative promise (processedDataPromise) does indeed get resolved. However the 'data' passed to it is undefined. Is it anything to do with $digest cycles not doing its job in Jasmine?
Why does Jasmine not pass any data to the above derived promise.?
Further Note: The processedDataPromise is a completely new promise than the get returned promise.
It is a promise for processedData which as we can see is returned by successHandle (Definition not shown) once its parent getPromise gets resolved.
In UI everything works like a Charm.
Sorry for posting the question. The derivative promise indeed got the resolved data I was referring to. The problem was that I was incorrectly accessing the JSON data inside of successHandle.
As a result the 'successHandle' returned null and the the processedDataPromise got back undefined response.
Stupid mistake, very hard to find, but the best part is the learning and understanding of JS Promises.
I'm trying to create a amd module that runs a d3 request (d3.json() in this case) and returns the data from the request. I can't seem to figure out how to make the module wait for the request to finish before it returns the data. As a result I keep getting undefined in my main program when I try to access the data.
define(['app/args'], function(args){
d3.json("resources/waterData.php?stn=" + args.stationID, function (error, data) {
var dataToReturn = {};
//Do some stuff with data
return dataToReturn;
});
});
That is the basic structure of what I'm trying to do. I think the main issue is that the 2nd argument in d3.json is a callback for when the data is loaded, so when I try to return the data, it isn't getting outside the module. I haven't been able to figure out how to get the data from the callback to return it outside the module.
The real issue is that the d3.json function is asynchronous, so you can't just return the processed data from the outside function directly. One way you can work around this is by returning a promise rather than the data itself. You can use the d3.json callback to resolve the promise, and then other modules which depend on the data can register their own callbacks which will run once that promise has been resolved.
For example, if you use jQuery's $.Deferred() you can do the following:
define(['app/args', 'jquery'], function(args, $){
// CREATE DEFERRED OBJECT
var deferred = $.Deferred();
d3.json("resources/waterData.php?stn=" + args.stationID, function (error, data) {
var dataToReturn = {};
//Do some stuff with data
// RESOLVE NOW THAT THE DATA IS READY
deferred.resolve(dataToReturn);
});
// RETURN THE PROMISE
return deferred.promise();
});
Then when you want to use the data, you can require the above module, and register a listener that will fire once the data is ready:
require(['nameOfYourModuleAbove'], function(deferred) {
deferred.done(function(data) {
// DO SOMETHING WITH YOUR DATA
});
})