I have a angular project with a angular-data to work with my Restful API.
my situation is as following:
in my service I return a defineresource
in my controller I use service.defineresource.findAll().then
it all works fine but here is my question. when new data is added to the server how do I update the cache or add the new data to my cache.
Please advice
code:
//in service.js
.factory('Service', function(DS) {
DS.defineresource({
name: 'items'
endpoint:'api/v2/users'
});
});
//in controller.js
.controller('MainCtrl', function($scope, Service) {
Service.findAll().then(function (data) {
$scope.items = data
});
});
my code is above fetches all the data when I load it first time, but after the initial loading it only loads from the cache. My question is there a way to sync and fetch new data without destroying the cache.
To force the refresh of the data from the backend you need to set bypassCache: true in the options. If you don't pass this then angular-data will load from cache. This is documented in the api documentation.
To refresh the data every 15 minutes use $timeout with 900000 milliseconds. To have a button to refresh use a scope function that will be called from a ng-click on a button.
.controller('MainCtrl', function($scope, $timeout, Service) {
$scope.refreshData = function () {
Service.findAll({}, { bypassCache: true }).then(function (data) {
$scope.items = data;
});
}
$scope.refreshData();
$timeout($scope.refreshData, 900000);
});
<button ng-click="refreshData()">Refresh</button>
If you are using only Angular Routes, Use :
$route.reload()
it will reload / refresh your page . so the data will be sync .
you can use it in ng-click or check in your controller when new data is entered use it
$route.reload()
if you are using UI-Router you can do the same but instead of $route.reload() use this :
$state.go($state.current, {}, {reload: true});
Related
I'm building a rest api with fosrestbundle and I manage the frontend with angular and Twig template. One on my url address looks like this :
http://mywebsite/myroute/idContain
When I load the url in my browser, in a twig template (kind of html), I retrieve the parameter "idContain" (comming from a fosrestbundle controller) with ng-init of angularjs like this :
<div class="container-fluid" ng-init="getContainByID({{ idContain }})">
//...lot html div with angularjs directives
</div>
And immediately, ng-init will go to my angularJS app finds getContainByID(idContain) to run it.
This one looks like this :
angular.module("myApp", ["ngSanitize", 'angular.filter', 'ui.tinymce', ...])
.config(function($interpolateProvider, ...) {
$interpolateProvider.startSymbol('{[{').endSymbol('}]}');
})
.controller("myCtrl",function ($filter,..., myService)
{
// lot of code...
$scope.getContainByID = function(idContain)
{
$scope.currentContain = myService.getContains(idContain);
$scope.containRoot = $scope.currentContain.contain.containRoot;
...
}
// lot of code...
}
The fact is that, myService.getContains(idContain) come from my rest service looking like this :
angular.module("MyServiceRest", ['ngResource'])
.factory("myService", function ($rootScope, $resource) {
var apiData = $resource(
"/api", {},
{
...
"getContains": {method: 'GET', isArray: false, url: "mywebsite/api/myroute/:containid"}
...
});
return {
getContains: function (idContain) {
return apiData.getContains({containid: idContain});
}
}
});
Now the problem is, when I run my angularjs App, $scope.containRoot doesn't wait until myService.getContains(idContain) (coming from my asynchroeous $resource service) finished to load, and caused errors making my webapp crash.
How can I do, to force $scope.containRoot and the rest of my angular code to waiting until myService.getContains(idContain) (connected to the api resource) completly finished to load before continuing ?
$resource makes an asynchronous request but immediately reurns an empty object or array.
There are numerous ways you could handle your issue.
One would be not to worry about declaring $scope.containRoot and just using currentContain.contain.containRoot in the view. This property will get rendered after the request is received
Another is to use the $promise that is also returned by $resource and assign the scope property in promise callback
$scope.currentContain = myService.getContains(idContain);
$scope.currentContain.$promise.then(function(){
$scope.containRoot = $scope.currentContain.contain.containRoot;
});
Another is to use a routing resolve based on the same promise so the route( or state depending on router) is noot entered until the request is complete
We have an Ionic app which polls a node/express API.
When the app starts it fetches the JSON data correctly from the API. When we update the data and fetch it again from the Ionic app, we still see the old data from the time that the app was launched.
We've tried to clear both the Angular cache and the Ionic cache in a variety of ways, but that doesn't seem to make a difference.
Things we've tried are:
$ionicConfigProvider.views.maxCache(0);, cache-view="false" on the template, setting cache: false on the state, tried accessing the state via $state.go($state.currentState, {}, {reload : true});, $ionicHistory.clearHistory(); and $ionicHistory.clearHistory();, $route.reload and $window.location.reload.
Controller:
function contactsController(Contacts, $stateParams) {
var vm = this;
var params = $stateParams.id;
Contacts.getAllContacts.then(function success(response) {
vm.data = response.data;
vm.selectedContact = response.data[params];
});
}
Factory
function contactsFactory($http, $stateParams) {
return {
getAllContacts: $http.get('https://api-call'),
update: function(url) {
$http.patch('https://api-call/update', [$stateParams.id, url]);
},
};
}
Express Back end
app.get('/', function (req, res) {
ref.once("value", function(snapshot){
res.send(snapshot.val());
});
});
app.patch('/update', function(req, res) {
var id = req.body[0];
ref.child(id).update({"imageURL": req.body[1]});
});
Thanks
Modify your view like this
<ion-view cache-view="false" view-title="My Title!">
Try console.log(vm) and verify that the updated data are obtained. If its only the view thats not being updated despite updated data being logged, I would try the following along with cache-view="false".
$scope.apply(function (){
// update your view here
vm.data = response.data;
vm.selectedContact = response.data[params];
});
By using Firebase's once() you have effectively removed all callbacks attached to value besides the first one:
Listens for exactly one event of the specified event type, and then
stops listening
Try switching to on() instead.
app.get('/', function (req, res) {
ref.on("value", function(snapshot){
res.send(snapshot.val());
});
});
It may be that your issue is not related to caching at all...
When I install Ionic 2 Open layers map on android device, i can see Open layers map successfully on the android screen. But when i close it and open the app again, i cant see the map. To solve this problem , what i do is: i uninstall the app, restart my device, then reinstall the app, after that i can see the map.
Please provide me a permanent fix.
Placing this in app config worked for me with
$ionicConfigProvider.views.maxCache(0);
$ionicConfigProvider dependency in config.
In ionic I'm resolving my data with the Ui-Router's resolve functionality before the controller is initialized. As of now I don't have to $inject my EventService into the Controller. The EventService's getEvents() method resolves the data before the controller is initialized. Everything works correctly this way, but now i'm trying to implement the Ion Refresher. I could easily refresh my $scope.events array within the controller, bloating the controller itself, because I would have to $inject the EventService into the controller, and that also means that every controller that uses the same data will have to contain logic to handle a refresh. What is the best way refresh the data outside of the controller or is that the best way?
Events State Definition and data resolution
.state('tab.events', {
url: '/events',
views: {
'tab-event': {
templateUrl: 'views/events.html',
controller: 'EventsController',
resolve: {
events: function (EventService) {
return EventService.getEvents(); //resolves data before ctrl initialized
}
}
}
}
})
Events Controller
(function() {
'use strict'
angular
.module('app.events')
.controller('EventsController', EventsController);
EventsController.$inject = ['$scope','events'];
function EventsController ($scope,events) {
$scope.events = events;
}
}
)();
Bloated Events Controller - Example
(function() {
'use strict'
angular
.module('app.events')
.controller('EventsController', EventsController);
EventsController.$inject = ['$scope','events','EventsService'];
function EventsController ($scope,events,EventsService) {
$scope.events = events;
$scope.refresh = refresh;
function refresh () {
clearCache(); //pretend method
EventsService.getEvents()
.then(function (events) {
$scope.events = events;
$scope.$broadcast('scroll.refreshComplete');
})
}
}
}
)();
Rather than bloating the controller can I refresh this data another way?
call $state.reload() which is an alias for:
$state.transitionTo($state.current, $stateParams, {
reload: true, inherit: false, notify: true
});
This will cause all your states to be "re-entered" which fetches the resolves and re-initializes the controllers.
I wish a hard refresh, which is basically what a $state.reload() does wasn't the answer. I too have this issue and would rather be able to call some method that just forces all the resolved data objects to rerun. The reload causes a page refresh, which causes nasty UI artifacts.
I have a service which loads some data and then stores it into local storage, for a Angular base mobile app. I'm calling this service in the run function of my main JS file, like this:
angular.module('myApp', ['ionic'])
.config(function ($stateProvider, $urlRouterProvider) {
})
.run(function (StartupService) {
StartupService.initialDataLoad();
})
This data loads in to local storage, and then in the init function of the first views controller I try to access this data in local storage and display it in a list:
angular.module('MemberInduction').controller('InductionListCtrl', function($scope, DataAccessService) {
$scope.init = function init() {
if (localStorage.getItem('MI.ApplicationData') != null) {
var data = DataAccessService.getInductionList();
$scope.inductionsList = data;
} else {
$scope.displayReloadMsg = true;
}
}
$scope.init();
});
As you can see in my init() function I access the data through a service, but when the controller initialises the data maybe loaded in localStorage, but at the time of initialisation the data isn't there. So my displayReloadMsg flag is set to true, causing a message to the user telling them to reload the app to display the loaded data.
How can I get the view to initialise once the data has loaded successfully? So that the view and controller only load from localStorage once the data has loaded?
Thanks
Stephen
you want to use resolve on your main controller to make sure the data is loaded prior to accessing the controller.
See this example: https://thinkster.io/egghead/resolve-conventions
In the example below, the state transistion will not happen if the Flickr.search() returns no data - full source for this example is here - http://codepen.io/aaronksaunders/pen/gboQVO
.state('flickr-display', {
url: '/flickr-display:query',
templateUrl: 'flickr-display.html',
controller: 'FlickrDisplayCtrl as flkr',
resolve : {
ImageData : function($stateParams, Flickr) {
return Flickr.search($stateParams.query);
}
}
This might be a beginner question, but I am retrieving data via http calls in AngularJS and setting them as properties in the $scope variable. However, since http calls take a while, my page tries to load AngularJS more than once in order to render different parts of the page as more the data is retrieved. Is there a way around this? (to hold off on loading the page before all data has been retrieved)
What you could do is to use ng-hide or ng-cloak, so that whatever should not be displayed until the http call fully loaded the data would remain hidden.
take a look at the resolve property in the route settings. If you set something to be resolved the router will resolve this before going to the controller.
app.config(function ($routeProvider) {
$routeProvider
.when('/',
{
templateUrl: "app.html",
controller: "AppCtrl"
resolve: {
app: function ($q, $timeout) {
YourFactory.getData({});
}
}
}
)
});
then create a Factory that will get the data you need
app.factory('YourFactory', ['$http', '$q',
function($http, $q) {
var url = '/api2.php/api';
var YourFactory = {};
var factory_data = [];
var messages = [];
YourFactory.getData = function(params) {
console.log("into GET data");
var deferred = $q.defer();
$http.get(url).success(function(response) {
angular.copy(factory_data, response.data);
deferred.resolve();
}).error(function(response) {
//couldn't resolve therefore it's rejected
deferred.reject();
});
//returns a promise that indicates that something is being resolved and will be returned for the app to continue
return deferred.promise;
};
YourFactory.data = function() {
return factory_data;
};
return YourFactory;
}
]);
then in your controller you need to input the factory and set the scope data from the Factory. Remember that Angular used the Factory to get data before the controller using the resolve property.
app.controller("AppCtrl", ['$scope','YourFactory',
function($scope, YourFactory) {
$scope.data = YourFactory.data();
});
(I haven't tested the code, I simply wrote an example based on an app that I'am doing and in which I passed through the same things as you)
Look at this links if you have any doubt.
https://egghead.io/lessons/angularjs-resolve
http://www.javierlerones.com/2013/07/preloading-data-using-deferred-promises-in-angular-js.html