Earlier I used to show a loader before ajax calls start and remove the loader once the call is completed. Now I have two calls in one single page. In this scenario how should I handle the loader ? If I use the same approach as earlier even though other call is not finished loader would be removed
You can use angular $q service which allows to wait a group of multiple promises to be resolved.
Example :
$q.all( [promise1, promise2] ).then(() => {
// only when both are resolved
// so here you can remove the loader
});
Related
I've recently started migrating from ngrx to ngxs and had a design question of where I should be placing some of my calls.
In NGRX, I would create 3 actions for each interaction with an api. Something like:
GetEntities - to indicate that the initial api call was made
GetEntitiesSuccess - to indicate a successful return of the data
GetEntitiesFail - to indicate a unsuccessful return of the data
I would create an effect to watch for the GetEntities Action that actually called the API and handled the response by either calling the Success/Fail actions with the resultant payload.
In NGXS, do I make the api call from the store itself when the action occurs or is there some other NGXS object that I am supposed to use to handle those API calls and then handle the actions the same way I did in ngrx (by creating multiple actions per call)?
Most of the examples I have seen, and how I have used it is to make the API call from the action handler in the state, then when the API returns patch the state immediately.
Then after the patch call, you can dispatch an action to indicate success/failure if you need to. Something like this:
#Action(GetSomeData)
loadData({ patchState, dispatch}: StateContext<MyDataModel>, {payload}: GetSomeData) {
return this.myDataService.get(payload.id)
.pipe(
tap((data) => {
patchState({ data: data});
// optionally dispatch here
dispatch(new GetDataSuccess());
})
);
}
This q/a might also be useful Ngxs - Actions/state to load data from backend
When my component mount I need to request it content from an API. In the docs:
componentDidMount() is invoked immediately after a component is
mounted. Initialization that requires DOM nodes should go here. If you
need to load data from a remote endpoint, this is a good place to
instantiate the network request.
and it follows:
Calling setState() in this method will trigger an extra rendering (...)
Use this pattern with caution
because it often causes performance issues.
What is the best practice to make a request to an API and, immediately, setState with the response?
The best way to call an API and update the state after you receive the response is in componentDidMount() or componentWillMount().
Which one might depend on what you want to do with your data from your API-call. If you need to access your components DOM then componentDidMount() must be used. That said, neither of these will save you from an additional re-render, unless your data doesn't need to be set to your state, in which case you can just save it to this.
The official documentation even states this, in this section:
componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
Before Rendering to call api:
componentWillMount(){
fetch(api)
.then((response)=>{
this.setState({data:response.data});
})
}
After Rendering to call api:
componentDidMount(){
fetch(api)
.then((response)=>{
this.setState({data:response.data});
})}
Before Rendering to call props data:
componentWillReceiveProps(){
this.setState({data:this.props.data});
}
Whenever you trigger setState your component is going to be re-rendered (regardless the lifecycle event).
Use this pattern with caution...
You can get to an endless loop for example if you trigger setState in componentWillReceiveProps and you are not taking care of future props correctly.
My suggestion is to stick with componentDidMount and set state as soon as your api request is fulfilled:
componentDidMount() {
fetch('api-endpoint')
.then(response => response.json())
.then(result => this.setState({ stateProp: result }))
}
I just have implemented AJAX calls using fetch in react-native.
Implementing queuing of these AJAX calls hasn't been very well implemented.
Can any one help me?
If you want to make parallel requests, you can use the fact that fetch returns a promise to you, and then you can use Promise.all to wait for completion of all promises.
For example:
var urls = ['http://url1.net', 'http://url2.net'];
var requests = [];
urls.forEach((url)=>{
request = fetch(url); // You can also pass options or any other parameters
requests.push(request);
});
// Then, wait for all Promises to finish. They will run in parallel
Promise.all(requests).then((results) => {
// Results will hold an array with the results of each promise.
}).catch((err)=>{
// Promise.all implements a fail-fast mechanism. If a request fails, the catch method will be called immediately
});
I noticed that you added the 'multithreading' tag. It is important to notice that this code won't be doing any threading for you, as JS (generally) runs in only one thread.
I am new to angular and want to use it to send data to my app's backend. In several occasions, I have to make several http post calls that should either all succeed or all fail. This is the scenario that's causing me a headache: given two http post calls, what if one call succeeds, but the other fails? This will lead to inconsistencies in the database. I want to know if there's a way to cancel the succeeding calls if at least one call has failed. Thanks!
Without knowing more about your specific situation I would urge you to use the promise error handling if you are not already doing so. There's only one situation that I know you can cancel a promise that has been sent is by using the timeout option in the $http(look at this SO post), but you can definitely prevent future requests. What happens when you make a $http call is that it returns a promise object(look at $q here). What this does is it returns two methods that you can chain on your $http request called success and failure so it looks like $http.success({...stuff...}).error({...more stuff..}). So if you do have error handling in each of these scenarios and you get a .error, dont make the next call.
You can cancel the next requests in the chain, but the previous ones have already been sent. You need to provide the necessary backend functionality to reverse them.
If every step is dependent on the other and causes changes in your database, it might be better to do the whole process in the backend, triggered by a single "POST" request. I think it is easier to model this process synchronously, and that is easier to do in the server than in the client.
However, if you must do the post requests in the client side, you could define each request step as a separate function, and chain them via then(successCallback, errorCallback) (Nice video example here: https://egghead.io/lessons/angularjs-chained-promises).
In your case, at each step you can check if the previous one failed an take action to reverse it by using the error callback of then:
var firstStep = function(initialData){
return $http.post('/some/url', data).then(function(dataFromServer){
// Do something with the data
return {
dataNeededByNextStep: processedData,
dataNeededToReverseThisStep: moreData
}
});
};
var secondStep = function(dataFromPreviousStep){
return $http.post('/some/other/url', data).then(function(dataFromServer){
// Do something with the data
return {
dataNeededByNextStep: processedData,
dataNeededToReverseThisStep: moreData
}
}, function(){
// On error
reversePreviousStep(dataFromPreviousStep.dataNeededToReverseThisStep);
});
};
var thirdFunction = function(){ ... };
...
firstFunction(initialData).then(secondFunction)
.then(thirdFunction)
...
If any of the steps in the chain fails, it's promise would fail, and next steps will not be executed.
In this PlunkerDemo, I'm trying to broadcast an event from the parent controller to child controller. However doing it directly in the parent controller won't work. The handler doesn't register the event. However doing it based on an ng-click or based on setTimeout, it works. Is it due to the scope life cycle?
http://beta.plnkr.co/edit/ZU0XNK?p=preview
See the comments of the accepted answer. They explain my problem.
Any changes to angular scope must happen within the angular framework, If any changes have to be made outside the framework we have to use the .$apply function.
$apply() is used to execute an expression in angular from outside of
the angular framework.
In your case you are triggering the $broadcast within setTimeout, where the callback gets called outside the angular framework.
So you have two solutions, either use the $timeout service provided by angular or use .$apply function.
I prefer to use the $timeout function.
var ParentCtrl = function($scope, $rootScope, $timeout){
$scope.broadcast = function(){
$rootScope.$broadcast('Sup', 'Here is a parameter');
};
$timeout(function(){
$scope.$broadcast('Sup');
}, 1000);
//this one does not work! Most likely due to scope life cycle
$scope.$broadcast('Sup');
$scope.$on('SupAgain', function(){
console.log('SupAgain got handled!');
});
};
Demo: Fiddle
Using $apply
setTimeout(function(){
$scope.$apply(function(){
$scope.$broadcast('Sup');
});
}, 1000);
A more reliable option can be to use $interval in child controller. So, instead of having significant timeout, there will be polling every small interval.
Also, instead of broadcast, use a service with a flag. Every poll will check if flag is set. When the flag is set by parent controller, the timer will be stopped during next poll. And that can indicate the event happened. The parent controller can also share data with child controller, via service.