As my app initializes, the call to the api happens:
.run(function($ionicPlatform, $http, $localstorage, $model) {
$http.get($model.apiurl).success(function(data) {
$localstorage.setObject('data', data);
// reload template here!
});
})
When the api call has succeeded and the localstorage object is set, I want to reload my template (tab-categories.html) so the data can be displayed. How do I do this, ngRoute, stateProvider, ... ?
You might be missing the point of angular if you ask this question. If your template has values which are bound to a model, then changing those values will automatically update the view on the next digest. It is possible that your asynchronous code (the request) does not trigger a digest, in which case you will have to do it manually. There are many ways to do that: digest and apply
One simple way is to inject $timeout, and do a zero duration timeout (no time argument) with the sensitive code in the body of the function you pass in
Edit: so to answer your question more directly, you should be storing your data somewhere in your application when the call succeeds, and then rely on the angularjs digest loop to update your view. That's one of angulars big work saving features.
Use $route.reload(); method to reload entire page after your successful Transaction, be sure to add dependency injection '$route' in your Controller.
Related
I have a download function, which has a promise called onProgress(which returns download percentage), I want to go to some other view and come back. Even though controller's scope is with proper data the page is not getting refreshed with new data.
Even with this vague description it sounds like the onProgress() function is not in "angular world". Therefore, any changes to $scope that you make in the promise callback will not be noticed by angular until the next digest cycle.
The solution is easy: inside the onProgress() promise callback, wrap your changes to $scope in $apply:
onProgress().then(function(percent)
{
$scope.$apply(function() {
// your changes to $scope here, so that angular notices them
}
}
I am building a single page app using angular and .net backend.
Aside from the individual restful resources that the controllers call, I also have a System Resource which provides the app with system wide information that is used/needed by most of my controllers.
I call the system service and store the data in the rootScope when the user first logs on.
However if for some reason the user refreshes the page which will lose the rootScope then the system data is lost and no longer available to the controller.
I have managed to get the System Service to trigger if a page reload happens BUT the problem is that in many cases the services running from the controller happen BEFORE the system service call which means that the data is not always available when the controller runs.
Whats the correct way to handle this in angular? Is there a way to make my controllers dependent on a certain rootScope state which if necessary will cause my system service API to be called before the controller makes its own service calls?
Thanks
One approach could be creating a factory/service which is injected to and called by every controller needing this information. This way you don't have to mess with $rootScope.
The request to get information should be cached so that you don't have to fire off a get everytime you switch controller. If you want to persist the information even after a page refresh you could use localstorage to store your data.
Example factory:
angular.module('appName')
.factory('Settings', ['$http', function ($http) {
function getData() {
var url = 'url/to/endpoint';
return $http.get(url, {cache: true});
}
return {
promise: getData()
};
}]);
By returning a promise from the factory we ensure that the getData() call is only run once. While in this particular instance it makes almost no difference (since it is returning an inner promise already), it is a pattern to follow for best practice.
This pattern also means that getData() is called on first use regardless of if the consuming controller accesses the promise. This allows for data to be exposed easily (data binding) without the need to use the promise in some use cases.
Used in controller:
angular.module('appName')
.controller('VeryNiceCtrl', ['$scope','Settings', function ($scope, Settings) {
Settings.promise.success(function(response){
var appSettings = response;
// do stuff
})
}])
I've been reading that Services are great for sharing data. But I am having a hard time making all data be in sync...
For example, let's say you have
an ItemService with an array of items.
a ItemListController, which shows a list of items ($scope.items = ItemService.items)
a AddItemController, a form to add items to the array (using the service).
When I add a new item, it doesn't automatically shows in the list controller. My workaround so far is to use cache:false in the router so that it refreshes every time I look at it...
I can't use $scope.$apply() because the adding happens on one controller while I want to see it on another...
You need to use $rootScope.$broadcast('item.added'); in the controller that initiates changes (AddItemController), after it successfully updates the array in the service.
Then in the ItemListController you use
$rootScope.$on('item.added', function(event){
$scope.items = ItemService.items;
});
Check this question
#Sarpdoruk There is two-way data binding between views and controllers, but not between controllers and services. By using this line $scope.items = ItemService.items; you copy 'items' from service to items in controller but you copy by value, not by reference. You can change $scope.items in your view or controller and they will get updated between the view and controller but these changes will have no effect on the service. Same thing if you update items in the service - controller will not know that something has been changed - so you need to $broadcast or $emit that something has changed from service and listen for the changes in the controller. You can also $broadcast between controllers, directives and even services (but since services have no access to $scope, you have to use $rootScope and some people frown upon that). The bottom line is, if you really have to use a $rootScope in the service because otherwise you will have to overcomplicate parts of your app, then do it and never bother with "best practice evangelist" The first rule of the app is that it has to work, only after it works you should worry about clean code. I hope it makes it clearer now.
I have SPA and on the first page I load a big data object from the REST service.
The first page consists of the main part which resolved by controller, set of directives in the current scope which render some parts of received object and a header directive in the $rootscope which also render some part of received data.
I call API in the controller and when all data will be loaded I should notify about it all related directives for rendering loaded data.
Now I use $watch() and $watchGroup() for the same scope directives and $rootScope.$broadcast() for the header from the $rootscope.
Is there any more gracefully solution for it?
What is the best way to do this?
This sounds like a good use case for ngResource, which is an official Angular module for REST resources. I'd recommend you create a service for your resource like:
app.factory('Widget', function ($resource) {
return $resource('/api/v1/widgets/:id');
});
Then you can use it in your controller to handle the loading of your data.
app.controller('WidgetController', function ($scope, Widget) {
$scope.widgets = Widget.query({active: true});
});
In your views/templates/whatever, can bind right to widgets, which will be an array of widgets that match the query. The array will be empty while the widgets load, then it will be populated with the results -- and the binding will automatically update.
You can also bind to widgets.$resolved which (essentially) indicates whether the resource has finished loading or not.
Check out more about ngResource here.
Angular is loosing my my JSON values, and i'm trying to find out why. I think I need to make a promise or a time out, or maybe apply. I'm not quite sure...
angular version: 1.2.1
galleryApp.controller('GalleryCtrl', function ($scope, $http, $routeParams, $filter){
$http.get('mygallery.json').success(function(data) {
$scope.gallery = data;
//DISPLAY: CONTENTS OF JSON IN OBJECT : WORKS
console.log($scope.gallery);
});
//DISPLAY: undefined : DOES NOT WORK AS EXPECTED
console.log($scope.gallery);
//DISPLAY: CONTENTS OF OBJECT: I can see scope.gallery exists!
//I just can't seem to access scope.gallery directly outside of http.get()
console.log($scope);
});
Note: scope.gallery or "gallery" works perfectly fine in my view! {{gallery.name}} etc.
It seems like there is some behind the scenes things angular is doing to the scope, or some concept that i'm not quite grasping.
Well, it's trivial as $http.get is an asynchronous operation. So while it is working the rest of the code will be finished. If you log the $scope.gallery it is undefined yet. If you log the $scope it's still undefined but will be updated when the success callback is invoked. Th reason of this effect for you is just feature of console.log which writes not the current snapshot but the object itself so if changed the output of the console will be updated respectively. But in general none of your code outside of the $http.get will work as you expected here. So you should either use the success callback or use $watch to track the changes.
Also refer to this documentation: $http, $q
The result of http.$get is a promise (specifically an HtmlPromise, see the $http docs). A promise is described as the following in the $q docs:
an interface for interacting with an object that represents the result of an action that is performed asynchronously, and may or may not be finished at any given point in time
The success method of an HtmlPromise takes a callback function to run once the promise is resolved (meaning the action is complete). The anonymous function thus runs asynchronously. When it is logged outside of the callback, the callback has not yet been run and therefore the scope variable has not been set.
I imagine the view is as expected because the http request completes and the view is updated so fast, it is imperceivable.