Caching JSON with AngularJS [duplicate] - json

This question already has answers here:
AngularJS : Initialize service with asynchronous data
(10 answers)
Closed 8 years ago.
I'm loading JSON in my controller, changing routes the JSON gets reloaded. I would like to cache it.
var sampleApp = angular.module('sampleApp', [
'ngRoute',
'sampleAppControllers',
]);
var sampleControllers = angular.module('sampleControllers', []);
sampleControllers.controller('PostsCtrl', ['$scope', '$http',
function($scope, $http) {
// Should be loaded only on app load
$http.get('http://example.org/source.json').success(function(data) {
$scope.posts = data;
});
$scope.orderProp = 'id';
}]);
I tried using .constant, but couldn't get it work:
sampleApp.constant('myCache', ['$http',
function($http) {
$http.get('http://example.org/source.json').success(function(data) {
return data;
});
}]);
sampleControllers.controller('PostsCtrl', ['$scope', 'myCache',
function($scope, myCache) {
$scope.posts = myCache;
$scope.orderProp = 'id';
}]);
I'm looking for a way to load JSON on app start, and use it in controllers.

That's what Angular Services are for - load the data inside the service instead of inside the controller, and have the controller access this data. Services are instantiated once in the lifetime of an app, which is exactly what you want here.

Related

Angular factory with $http [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I am writing a factory that calls a JSON feed and returns the results.
Here is the factory using $http
nearestLocationApp.factory("allTheLocationsFactory", function($http){
var locations = "Not sure why it don't work";
$http.get('/json/locations/').then(function(res){
locations = res.data;
});
return locations;
});
When I include this in the controller I get the first version of the locations variable. It's like there are 2 different scopes here. I am pretty sure that's my problem but I don't know why.
Here is me calling and printing out the console.log for the controller.
nearestLocationApp.controller("getTheLocation", function($scope, allTheLocationsFactory){
$scope.locationResponse = "Find your location";
$scope.locations = allTheLocationsFactory;
console.log($scope.locations);
});
What I need to know is why I have multiple scopes in my factory and how to fix it.
If anyone is interested the JSON data looks like this.
[
{
"Name":"#########",
"ID":#########,
"address1":"#########",
"address2":"#########",
"city":"#########",
"state":"#########",
"zip":"#########",
"phoneNumber":"#########",
"thumbnail":[
"#########",
#########,
#########,
#########
],
"permalink":"#########",
"weekdayHours":"#########",
"saturdayHours":"#########",
"sundayHours":"#########",
"coords":{
"longitude":"#########",
"latitude":"#########"
},
"options":{"animation":#########}
}, ......
You are dealing with asynchronous call, that gets data asynchronously for you. In this Your factory should return $http promise & you could get that promise inside your controller and put .then function, That will get call when the factory $http returns a locations from it success callback.
Factory
nearestLocationApp.factory("allTheLocationsFactory", function($http){
return $http.get('/json/locations/').then(function(res){
return res.data;
});
});
Controller
nearestLocationApp.controller("getTheLocation", function($scope, allTheLocationsFactory){
allTheLocationsFactory.then(function(data){
$scope.locations = data;
console.log($scope.locations);
})
});
Your factory instance should ideally return a promise instance that can be resolved either within a controller or ideally within a routers resolve option.
nearestLocationApp.factory("allTheLocationsFactory", function($http){
var jsonURL = '/json/locations/',
getLocations = function(){
return $http.get(jsonURL).then(function(result){
return result.data;
});
};
return {
getLocations: getLocations
};
});
Then within your application config or router something like;
var nearestLocationsApp = angular.module('myApp', [
'ngRoute'
])
.config(function($routeProvider) {
$routeProvider.when("/", {
templateUrl: "templates/someTemplate.html",
controller:'SomeCtrl',
controllerAs: 'ctrl',
resolve: {
locations: function(allTheLocationsFactory) {
return allTheLocationsFactory.getLocations();
}
}
});
});
And within your controller something similar to;
nearestLocationApp.controller('someController', [
'$scope',
'allTheLocationsFactory',
'locations',
function($scope, allTheLocationsFactory, locations) {
$scope.locations = locations;
}
]);
Or without using the resolve option in your router;
nearestLocationApp.controller('someController', [
'$scope',
'allTheLocationsFactory',
function($scope, allTheLocationsFactory) {
allTheLocationsFactory.getLocations().then(function(res) {
$scope.locations = res;
});
}
]);
The former option is one I personally prefer rather to relying on promises within the controller. You can check out some other useful angular tips here
Hope some of that helps you out!

angularjs get data from Json using $resourse

Good afternoon! Learning Angularjs. Below is the structure of the project.
I have a service that reads data from json
var WebKrServices = angular.module('WebKrServices', ['ngResource']);
WebKrServices.factory('DataPlant', ['$resource',
function($resource){
return $resource('plants/:plantId.json', {}, {
query: {method:'GET', params:{plantId:'plants'}, isArray:true}
});
}]);
And Controller
var WebKrControllers = angular.module('WebKrControllers', []);
WebKrControllers.controller('PlantsCtrl', ['$scope', 'DataPlant',
function($scope, DataPlant) {
$scope.plants = DataPlant.query();
}]);
which transmits this information to the html
<div ng-repeat="plant in plants">
<h2 class="text-center">{{plant.name}}</h2>
</div>
And, in fact question. In html I see data from json, and the controller when accessing the plants I see an empty object?
for (var p in plants) {
. . .
}
How to get data from the plants in the controller?
Thank you all for your answers.
Cause it is asynchronous call. After $scope.plants = DataPlant.query();, plants remain undefined until data arrives (Well, it is not exactly undefined, you can inspect it in debugger). When data arrives - $scope.plants get resolved and html is updated. To run some code after data arrives, use callbacks:
$scope.plants = DataPlant.query(function(response) {
console.log($scope.plants);
}, function (response) {
console.log('Error');
});

Fetching data from a JSON object (from a given API) in AngulaJS

I have the following code to present data from a link (API) as suggestion for an autocomplete box. Although it is working for one link and not the other. I observed that data format for both are different, modified my code accordingly but it is still not helpful.
.js file:
var plunker= angular.module('plunker', ['ui.bootstrap', 'ngGrid']);
function TypeaheadCtrl($scope, $window, $http, limitToFilter) {
$scope.cities = function (cityName) {
return $http.jsonp("http://mtapi.azurewebsites.net/api/institute").then(function (response) {
return response[0].description;
});
};
}
HTML file:
<input type="text" id="depn" ng-model="formdata.department"
typeahead="suggestion.description for suggestion in cities($viewValue)"
placeholder="department" class="form-control">
If you replace the cities function with this one,
$scope.cities = function (cityName) {
return $http.jsonp("http://gd.geobytes.com/AutoCompleteCity?callback=JSON_CALLBACK &filter=US&q=" + cityName).then(function (response) {
return response.data;
});
};``
Even after I changed my code jsonP request to .get, it is still not working
var plunker= angular.module('plunker', ['ui.bootstrap', 'ngGrid']);
function TypeaheadCtrl($scope, $window, $http, limitToFilter) {
$scope.cities = function (cityName) {
return $http.get("http://mtapi.azurewebsites.net/api/institute").success(function(data) {
return data[0].description;
});
};
}
It is working fine.
Is there a problem with my code, or a back end server issue?
Change your cities function to use the data property of the response in your .then (that's how you'll access the response from a resolved HttpPromise):
var plunker= angular.module('plunker', ['ui.bootstrap', 'ngGrid']);
function TypeaheadCtrl($scope, $window, $http, limitToFilter) {
$scope.cities = function (cityName) {
return $http.get("http://mtapi.azurewebsites.net/api/institute").then(function (response) {
return response.data[0].description;
});
};
EDIT
Even making that code change won't solve your problem. This url does not support cross-origin requests, so you either need to host your angularjs app on the same domain and use a plain $http.get instead of $http.jsonp, or this url needs to support JSONP requests (the content-type of the response from this url is application/json. For JSONP to work it should be application/javascript).
I figured it out lately. Apart from the problem at back end there were issues in this code as well. I was returning the promise, but promise was never resolved to return the value also I was trying to return a string, whereas I should return array of strings. Here's the change:
$scope.aap = result.data;
var res = [];
res.push($scope.aap[0].Description);
return res;

Why is $http.get() undefined in my Angular service?

I'm trying to load some JSON and store it using $rootScope so that it persists between controllers. When I run my app I get the following error:
TypeError: Cannot call method 'get' of undefined
The get method was working perfectly until I tried to introduce $rootScope... any ideas?
My service looks like this:
1 /**
2 * Service to get the quiz data from a JSON source
3 */
4 app.factory('quizService', ['$rootScope', function ($scope, $rootScope, $http) {
5 var promise;
6 var service = {
7 getQuiz: function($scope, $http) {
8 if ( !promise ) {
9 promise = $http.get('QuizFileName.quiz').then(function (response) {
10 return response.data;
11 });
12 }
13 return promise;
14 }
15 };
16 return service;
17 }]);
My controller looks like this:
7 // Get Quiz data from service
8 quizService.getQuiz().then(function(data) {
9 $scope.quiz = data;
10
11 // Redirect to scores if already completed this
12 if($scope.quiz.complete === true) {
13 $location.path('scores');
14 }
15 });
You are using the 'array pattern' in defining your factory. You should have a string for each of the services you use in your function, but you only have one.
That is, what you do is
app.factory('quizService', ['$rootScope', function ($scope, $rootScope, $http) {
//insert code
}]);
but what you should do is
app.factory('quizService', ['$scope', '$rootScope', '$http', function ($scope, $rootScope, $http) {
//insert code
}]);
AngularJS will map the functions named with the strings to the parameters. Try that and see if it fixes your issue.
EDIT: Ah,the answer from Reboog711 makes more sense in solving the issue, I somehow missed the latter part of the code. But I'm leaving this answer in since you should also fix the factory definition.
getQuiz is a function inside a factory:
getQuiz: function($scope, $http) {
When you call the getQuiz, you do not pass any arguments into it:
quizService.getQuiz()
$http is undefined because you call it without passing any arguments into it. Angular will not inject items into a function that you call manually. It will only do so with functions that AngularJS calls itself--such as controller or factory functions.
So, you have a few options. One is to pass the $scope and $http arguments into the function, like this:
quizService.getQuiz($scope, $http)
I'm sure this would solve the issue, but it would be a weird approach for sure.
I would probably remove the $scope and $http functions out of the function definition:
getQuiz: function() {
Then make sure that you modify your factory definition:
app.factory('quizService', ['$scope','$rootScope','$http', function ($scope, $rootScope, $http) {
Without this modification, the Angular services will not be passed into your function.
Then, when you access $http inside the function, it should access the value passed into the factory which should not be undefined.
OK, Reboog711 put me on the right track, I needed to modify my factory definition to include $http, I had previously tried to do this, but mistakenly put it together like this:
'$rootScope, $http'
Don't do this, it's bad and wrong! But Reboog711's answer also gave me errors because I think you can't use $scope in the way we both thought.
The correct (or working) solution was:
app.factory('quizService', ['$rootScope', '$http', function ($rootScope, $http) {
I hope this helps other newcomers to Angular. Many thanks to all who replied with their comments. I really respect this community for its great attitude to helping others :)

Read local file in AngularJS

I used to work with RequireJS and Backbone and used requirejs/text and requirejs-plugins to load local json files I normally use for configuration.
How does one achieve the same with AngularJS?
Everyone seems to suggest to use $http, but is this the only way?
Do I really need to make 20 calls if I have 20 configuration files?
Maybe something like ng-constant is the "preferred" way?
This is what I did. But it uses $http though so I'm hoping someone has a better solution.
app.js:
var myModule = angular.module('myApp', []);
myModule.config(function($routeProvider, $locationProvider) {
$routeProvider.when('/', {
templateUrl: 'html/home.html',
controller: 'MainCtrl as ctrl',
resolve: {
initializeData: function($q, $timeout, myService) {
return myService.promiseToHaveData();
}
}
});
});
myService.js:
var myModule = angular.module('myApp');
myModule.service('myService', function($http, $q) {
var _this = this;
this.promiseToHaveData = function() {
var defer = $q.defer();
$http.get('someFile.json')
.success(function(data) {
angular.extend(_this, data);
defer.resolve();
})
.error(function() {
defer.reject('could not find someFile.json');
});
return defer.promise;
}
});
Then I can inject myService anywhere and it will have all the fields from the json file.
I guess alternatively you could just make your .json files .js files, have them expose a global variable, and reference them in your index.html
Can you use jQuery's getJSON function?
E.g something like:
$.getJSON("config-1.json", function( data ) {
// do whatever you want
});
Here's an AngularJs service that uses the FileReader API:
http://odetocode.com/blogs/scott/archive/2013/07/03/building-a-filereader-service-for-angularjs-the-service.aspx