Hey guys i'm new to angular and am not very proficient with javascript. This setup pulls in the json data fine, however when I make changes to some of the properties in the object, they reset when I change views and the controller is reloaded. Any help or guidance on how to approach this would be appreciated.
app.controller('MainCtrl', function ($scope, $location, Quiz) {
$scope.quiz = {};
Quiz.getQuestions(function(data) {
$scope.quiz = data;
});
});
app.service('Quiz', function($http) {
this.getQuestions = function(callback) {
$http.get('questions/questions.json').success(function(data) {
if (callback) {callback(data);}
return data;
});
};
});
Does the $http get request get repeated on subsequent calls to getQuestions() overwriting the object? If so, perhaps
app.service('Quiz', function($http) {
var _data;
this.getQuestions = function(callback) {
if (_data) {
callback(_data);
}
$http.get('questions/questions.json').success(function(data) {
_data = data;
if (callback) {callback(data);}
return data;
});
};
});
Related
I have a service that grabs JSON from a URL and I would like to alter that data but I cant seem to do it. Right now I change this in the controller but this seems messy with the scope not reaching places I would like.
//SERVICE
app.service("servers", function ($http, $q)
{
// Grab json
var deferred = $q.defer();
$http.get('http://www.mocky.io/v2/58bea87e260000c318f07bfd').then(function (data)
{
deferred.resolve(data);
});
this.getItems = function ()
{
return deferred.promise;
}
})
// CONTROLLER
.controller("AppCtrl", function ($scope, servers, geoIP) {
var promise = servers.getItems();
promise.then(function (data)
{
$scope.items = data.data.items;
});
$scope.getSelectedItem = function() {
return servers.selectedItem;
}
$scope.selectServer = function(item)
{
servers.selectedItem = item;
servers.selectedItem.refactored_match_state = lowerCamelCaseUnderscoreRefactor(servers.selectedItem.session.attributes.match_state);
}
//COMPONENT/TEMPLATES
//dbServerTable
<tr data-ng-repeat="item in items | filter:search | orderBy:'name'" data-ng-click="selectServer(item)">
<td>{{item.display_name}}</td>
</tr>
//dbServerInfoSidebar
<li>{{getSelectedItem().refactored_match_state}}</li>
Could anyone show me with code how to alter data in a service that can be used anywhere by any controller that can access that service
The way the service has been coded is an anti-pattern and should be avoided. Refer this link.
Change your service like below and make modifications to the data before you return the data within the .then function.
app.service("servers", function ($http)
{
this.getItems = function ()
{
return $http.get('http://www.mocky.io/v2/58bea87e260000c318f07bfd')
.then(function (data)
{
// **** Modify data here ****
return data;
});
}
})
You can use transformResponse property of $http
service;
You can modify your data before resolving the promise
deferred.resolve(data);.
Are you trying to do something like:
app.service("servers", function ($http, $q)
{
this.parseData = data => {
//modify data;
return data;
};
this._request = $http.get('http://www.mocky.io/v2/58bea87e260000c318f07bfd')
.then(this.parseData);
this.getItems = () => this._request;
});
You don't need to use deferred at all. It's unnecessary. $http returns a promise for you. If you want to alter any data, you just need to chain after the request and return the modified data in the chained method.
app.service('services',['$q','$http','$rootScope',function($q,$http,$rootScope){
var obj ={};
obj.getData =function(x){
var defer = $q.defer();
$http.get('http://www.mocky.io/v2/58bea87e260000c318f07bfd')
.then(function(response){
defer.resolve(response);
},function(error){
defer.reject(error);
});
return defer.promise;
}
return obj;
}])
app.controller('ctrl',function($scope,services){
$scope.getItems = function(){
services.getData()
.then(function(response){
$scope.Items=response.data;
},function(error){
console.log(error);
});
}
})
I'm currently working on a project to help me better understand angularjs! I am currently stuck on how to pass a parameter from the controller to service.
In my program, I have created a function called "GetForecastByLocation" when a user types in an input clicks on a button. From there I want to take their input and then pass it to the http call in service.js.
Originally, $http.get was in a long giant string of the API url, but I googled around and it seems that I'm supposed to use parameters when trying to change a portion of the string. As of right now, I know parameter is hardcoded to a specific city, but I want to take new input and pass the value of vm.city to the $http.get call.
If any one can help I would greatly appreciate it. Thank you!
controller.js
var app = angular.module('weatherApp.controllers', [])
app.controller('weatherCtrl', ['$scope','Data',
function($scope, Data) {
$scope.getForecastByLocation = function(myName) {
$scope.city = myName;
Data.getApps($scope.city);},
Data.getApps(city)
.then(function(data)){
//doing a bunch of things like converting units, etc
},
function(res){
if(res.status === 500) {
// server error, alert user somehow
} else {
// probably deal with these errors differently
}
}); // end of function
}]) // end of controller
service.js
.factory('Data', function($http, $q) {
var data = [],
lastRequestFailed = true,
promise;
return {
getApps: function() {
if(!promise || lastRequestFailed) {
promise = $http.get('http://api.openweathermap.org/data/2.5/weather?',{
params: {
q: Tokyo,
}
})
.then(function(res) {
lastRequestFailed = false;
data = res.data;
return data;
}, function(res) {
return $q.reject(res);
});
}
return promise;
}
}
});
Passing arguments to a factory method is no different than passing arguments to a plain old function.
First, set up getApps to accept a parameter:
.factory('Data', function($http, $q){
// ...
return {
getApps: function(city){
promise = $http.get(URL, {
params: {q: city}
}).then( /* ... */ );
// ...
return promise;
}
};
});
Then pass it your argument:
$scope.getForecastByLocation = function(myName) {
$scope.city = myName;
Data.getApps($scope.city);
}
It's just like setting a value to a function's context variable.
Services.js
Simple example of a service.
.factory('RouteService', function() {
var route = {}; // $Object
var setRoute_ = function(obj)
{
return route = obj;
};
var getRoute_ = function()
{
if(typeof route == 'string')
{
return JSON.parse(route);
}
return null;
};
return {
setRoute: setRoute_,
getRoute: getRoute_
};
})
Controllers.js
Simple example of Service usage:
.controller('RoutesCtrl', function ($scope, RouteService) {
// This is only the set part.
var route = {
'some_key': 'some_value'
};
RouteService.setRoute(route);
})
I created an angular factory for $http service. I am getting the response and able to use the same in the controller but the problem is, when i check the network tab in the browser, the http request is made twice
Factory:
app.factory('myService', function ($http, $q) {
var deferred = $q.defer();
var responseData = null;
var obj = {};
obj.getData = function(){
$http.get('test.json').success(function(response){
responseData = response;
deferred.resolve(responseData);
}).error(function(response){
deferred.reject(responseData);
});
return deferred.promise;
}
obj.myData = function(){
return responseData;
}
return obj;
});
Controller:
app.controller('myController', function($scope,myService){
myService.getData().then(function(){
$scope.myDetails = myService.myData();
});
});
what's wrong in my approach. Please provide me a solution
The way you are making your caching scenario is quite complicated and not really helpful. How do you know if data has already been loaded?
Maybe you can create a simple Caching Service to handle your caching at a single point (nr of code lines will go down).
angular.module("YourApp").factory("CachingService", [
"$q",
"$http",
function ($q, $http,) {
var cache = {};
return {
getFromCache: getFromCache
};
function getFromCache(url) {
var deferred = $q.defer();
if (cache[url]) {
deferred.resolve(cache[url]);
} else {
return $http.get(url).then(function (result) {
cache[url] = result;
return result;
});
}
return deferred.promise;
}
}
]);
And then, you simply call it inside your other service :
angular.module("YourApp").factory("myService", [
"CachingService",
function(CachingService){
return {
getData: getData
};
function getData(){
return CachingService.getFromCache("test.json");
}
}
]);
And then, inside your controller :
app.controller('myController', function($scope,myService){
myService.getData().then(function(result){
$scope.myDetails = result.Data;
});
});
you can return $http not deferred.promise
I am wondering about the best way to structure the services / factories in an Angular app to consume a REST API. I know about $resource but I don't want to use it since my API is a bit special and not just CRUD on /api/resource/:id etc.
There are two basic ways I can think of and I'm not sure which is the better once. I guess there are up- and downsides for both and that's why I'm asking.
Option 1
Have an API factory with many methods for each model. That would look something like this:
angular.module('myApp', ['$http'])
.factory('apiService', function() {
var o = {
posts: [],
comments: []
};
o.getAllPosts = function() {
return $http.get('/api/v1/posts').success(function(data){
angular.copy(data, o.posts);
});
};
o.getAllComments = function() {
return $http.get('/api/v1/comments').success(function(data){
angular.copy(data, o.comments);
});
};
})
.controller('MainCtrl', function($scope, apiService) {
// Get all posts
$scope.posts = apiService.getAllPosts();
// Get all comments
$scope.comments = apiService.getAllComments();
});
Option 2
Have a factory for every data model. Something like this:
myModule.factory('posts', ['$http', function($http){
var o = {
posts: [],
post: {}
};
o.getAll = function() {
return $http.get('/api/v1/posts').success(function(data){
angular.copy(data, o.posts);
});
};
o.getOne = function(params) {
return $http.get('/api/v1/posts/'+params.hash_id).success(function(data){
angular.copy(data, o.post);
});
};
o.create = function(post) {
return $http.post('/api/v1/posts', post).success(function(data){
o.posts.unshift(data);
});
};
return o;
}]);
.controller('MainCtrl', function($scope, posts) {
// Get all posts
$scope.posts = posts.getAll();
});
What is the better way to handle this and why?
I am trying to listen to changes in my injected service (self-updating) in the controller. In the below example you'll find two $watch cases - one that works but I don't know exactly why and one that was obvious to me, yet doesn't work. Is the second example the right way to do it? Isn't that code duplication? What is the right way to do it?
Service:
app.factory("StatsService", [
'$timeout', 'MockDataService',
function ($timeout, MockDataService) {
var service, timeout;
timeout = 5000;
service = {
fetch: function () {
// Getting sample data, irrelevant, however this is what updates the data
return this.data = MockDataService.shuffle();
},
grab: function () {
this.fetch();
return this.update();
},
update: function () {
var _this = this;
return $timeout(function () {
return _this.grab();
}, timeout);
}
};
service.grab();
return service;
}
]);
Controller:
app.controller("StatsController", [
'$scope', 'StatsService',
function ($scope, StatsService) {
var chart;
$scope.stats = StatsService;
$scope.test = function (newValue) {
if (arguments.length === 0) {
return StatsService.data;
}
return StatsService.data = newValue;
};
// This doesn't work
$scope.$watch('stats', function (stats) {
return console.log('meh');
});
// This works, don't know why
$scope.$watch('test()', function (stats) {
return console.log('changed');
});
}
]);
See the third parameter for $watch: objectEquality
Compare object for equality rather than for reference.
However if you're only interested in watching the returned data, then you should do:
$scope.$watch('stats.data', function (stats) {
return console.log('meh');
});
You could use $rootScope events. For example inside the service you could dispatch an event with $rootScope.$broadcast("somethingFetched", data) and catch it in the controller $scope.$on("somethingFetched", function(event, data) { $scope.data = data }).
More details you could find in the documentation http://docs.angularjs.org/api/ng.$rootScope.Scope