I am using the following pattern for my REST API, but vm.listing in my controller is always undefined? Probably my pattern is not right? Is there a different pattern to use here? I don't want to call the .get(..) in my controller code.
.factory("listingsResource", ["$resource", "$q", 'appSettings',
function ($resource, $q, appSettings) {
return $resource(appSettings.serverPath + "api/Listings/:id")
}]);
.factory("editService",
var _listing;
var _getListing = function (listingId) {
_listing = listingsResource.get({
id: listingId
});
}
return {
listing: _listing,
getListing: _getListing
};
Controller Code:
createService.getListing(listingId);
vm.listing = createService.listing;
The problem is that when you call listingsResource.get() it returns a promise. Not the data response.
You have to pass the get() a success callback and then set the listing variable inside this callback. I would do something like this:
.service("listingsService", ["$resource", "$q", 'appSettings',
function ($resource, $q, appSettings) {
var _this = this;
_this.listing = {};
var listingResource = $resource(appSettings.serverPath + "api/Listings/:id");
this.getListing = function(listingId){
listingResource.get({id: listingId},
function (data) {
// Success callback
// Set listing keys-value pairs
// do not do: _this.listing = data
_this.listing.id = data.id;
_this.listing.title = data.title;
},
function(err) {
// error callback
console.log(err);
}
)
}
}
])
This works fine with a factory aswell if you prefer. Then in the controller:
listingService.getListing(listingId);
vm.listing = listingService.listing;
Related
I'd like to create dynamically controllers responsible for view of data from REST API. My idea is to use ng-repeat directive with data from service and inside it create object with ng-controller directive with parameter from ng-repeat output (The most important condition is that each one question must have its own $scope). Unfortunatelly I don't know how to pass data from service.
AngularJS service code
(function () {
'use strict';
angular
.module('App')
.factory('questionsDataService', questionsDataService);
questionsDataService.$inject = ['$http'];
function questionsDataService($http) {
return {
getMetadata: function (taskId) {
var metaData = $http.get('api/toDo/taskVariables/' + taskId).then(
function (response) {
return response.data;
});
return metaData;
},
getQuestionsData: function (taskId) {
var questionsData = $http.get('api/toDo/getQuestions/' + taskId).then(
function (response) {
return response.data;
});
return questionsData;
}
}
}
})();
I'm not sure if I understood the question, your title is misleading, but I will show how to get the data from the service. I don't think you need a new controller for each item in an ng-repeat, but without more info on why you are trying to do this, I can't help there.
(function () {
'use strict';
angular
.module('App')
.controller('myController', myController);
// you are injecting your service here, this will be whatever the string is from the .factory() call
myController.$inject = ['$scope', 'questionsDataService'];
// again, we are passing the service in to the controller function
function myController($scope, questionsDataService) {
// your service calls are returning promises
// this will get run when the controller is initialized
questionsDataService.getMetadata(1).then(function(data){
// here is where you can access the returned metadata
// save it to the scope so you can access it in the DOM
console.log(data);
})
// if you want to call your service on a button click, or with some other function
$scope.getQuestions = function (id) {
questionsDataService.getQuestionsData(id).then(function (data) {
// here is where you can access the returned data
// save it to the scope so you can access it in the DOM
console.log(data);
})
}
// I added a service method that returns a string, rather than a promise
// this will get run when the controller is initialized
var str = questionsDataService.getServiceName();
console.log(str);
}
})();
(function () {
'use strict';
angular
.module('App')
.factory('questionsDataService', questionsDataService);
questionsDataService.$inject = ['$http'];
function questionsDataService($http) {
return {
getMetadata: function (taskId) {
var metaData = $http.get('api/toDo/taskVariables/' + taskId).then(
function (response) {
return response.data;
});
return metaData;
},
getQuestionsData: function (taskId) {
var questionsData = $http.get('api/toDo/getQuestions/' + taskId).then(
function (response) {
return response.data;
});
return questionsData;
},
// adding this just to show you how to access functions that don't return promises
getServiceName: function () {
return "questionsDataService";
}
}
}
})();
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);
})
Here is what i try to do :
Json from "urldatas":
[{ "name" : "John" }]
JS file:
var app = angular.module('app', []);
app.service('service', function($http, $q){
this.getDatas = function () {
var datas = $http.get('urldatas', {cache: false});
return $q.all({datas});
};
app.controller('FirstCtrl', function($scope, service, $http, $timeout) {
var vm = this;
vm.loadData = function () {
var promise = service.getDatas();
promise.then(function (data) {
$scope.datas = data.datas.data;
console.log($scope.datas);
});
};
vm.loadPackages = function () {
var url = "urlPackages" + datas.name;
$http.get(url).then(function (response) {
$scope.MyPackages = response.data;
});
};
So i try to dynamicly change url in $http.get in getPackages, by values from getDatas, but i don't know how to do it. url in console shows "urlPackagesundefinded". Thanks for answers in advance.
$q send multiple requests as an array, not as an object. remove the curly bracket and add a square bracket
var datas = $http.get('urldatas', {cache: false});
return $q.all([datas]);
since you reference the controllerAs remove the scope variables and reference them through vm.
also in then promises response data comes under data property
var promise = service.getDatas();
promise.then(function (response) {
vm.datas = response.data.datas.data;
console.log(vm.datas);
});
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