I have a route as below:
var entryShow = {
name: 'entry.show',
url: '/:entry_id',
views: {
'#':{
templateUrl: TEMPLATES.entry_show,
controller : 'EntryShowController',
resolve: {
entryData: ['$stateParams', 'Entry', function($stateParams, Entry){
return Entry.getEntry($stateParams.entry_id);
}],
entryHistory: ['$stateParams','Entry',function($stateParams,Entry){
return Entry.getHistory($stateParams.entry_id);
}]
}
}
}
};
In my controller I have added the two resolves as follows :
App.controller('EntryShowController',['$scope','$state','entryData', 'Entry',
function($scope, $state, entryData, entryHistory, Entry) {
...
$scope.entry = entryData.data.entry;
console.log('Entry History');
console.log(entryData);
console.log(entryHistory);
$scope.entry.history = entryHistory.data;
...
}]);
Here in console.log I get the correct result for entryData but for entryHistory I get the entryService object instead of the result. Also when I swapped the getEntry and getHistoyr making getHistory being called in first resolve then the value in entryHistory was correct but in entryData I got the entryService object.
I have also checked the wiki for using resolves in state.js. What am I doing wrong ?
Following is my entryService:
App.factory('Entry', ['$http','Common', function($http,Common){
var entryService = {};
entryService.getEntry = function(entry_id) {
show_page_loader();
return $http.get(URLS.entry_show_path, {params: { id: entry_id }})
.success(function(result){
return result;
})
.error(function(data){
common_flash_error_message();
});
};
...
entryService.getHistory = function(entry_id){
return $http.get(
URLS.entry_history_path,
{
params: {id: entry_id}
}
)
.success(function(data){
return data;
})
.error(function(data){
common_flash_error_message();
});
};
return entryService;
}]);
You've forgot to inject entryHistory into the array so you've mixup your injections:
App.controller('EntryShowController',[
'$scope', '$state', 'entryData', 'Entry',
function( $scope, $state, entryData, entryHistory, Entry) {
}]);
Here, enterHistory will hold entry,
Related
I created a simple AngularJS service with .factory() called $getUser that gets data from users.json:
{
"john": {
"name": "John",
"address": "New York"
},
"bob": {
"name": "Bob",
"address": "Boston"
}
}
Now I want to use this data in mainController:
angular.module('myApp', [])
.factory('$getUser', ['$http', function($http){
var users = {};
$http.get('users.json').then(
function(response) {
users.data = response.data;
}
);
return users;
}])
.controller('mainController', ['$getUser', function($getUser){
// I can access whole $getUser object
console.log($getUser);
// but when I want to access $getUser.data it gives me 'undefined'
console.log($getUser.data);
}]);
When I want to console whole $getUser object, it works, but I am not able to access $getUser.data property. Why?
Create factory as:
app.factory('$getUser', ['$http', function($http) {
var factory = {
query: function () {
return $http.get('users.json').then(function (response) {
return response.data;
}, function (result) {
alert("Error: No data returned");
});
}
}
return factory;
}]);
So you can call it as:
$scope.data = $getUser.query()
Simple demo Fiddle
However I suggest to return promise and resolve it in controller
The common approach to load JSON is:
app.factory('Items', ['$http',
function($http) {
return {
getJson: function(url) {
var ItemsJson = $http.get(url).then(function(response) {
return response.data;
});
return ItemsJson;
}
}
}
]);
and Usage:
var jsonPromise = Items.getJson('jsonData/someJSON.json');
jsonPromise.then(function (_response) {
// ...
}, function (error) {
console.error(error);
});
try this:
angular.module('myApp', [])
.factory('$getUser', ['$http', function($http) {
var users = {};
return {
getData: function() {
return $http({
url: 'users.json',
method: 'GET'
})
}
}
}])
.controller('mainController', ['$getUser', function($getUser) {
// I can access whole $getUser object
console.log($getUser);
// but when I want to access $getUser.data it gives me 'undefined'
console.log($getUser.data);
$getUser.getData().then(function(data) {
console.log(data.data);
});
}]);
Fiddle Link
How can I access values returned from service using controller. In my code service.js function showInfo() returns JSON objects. But I cannot access these objects outside this function. If I try to do console.log from controller.js
console.log(chartService.showInfo.new_data)
I get
error Cannot read property 'new_data' of undefined.
Same happens if I try to
console.log(chartService.showInfo)
I get undefined.
How can I access the JSON object new_data inside function showInfo from the controller?
Service.js
angular.module('myApp')
.service('chartService', function (){
return {
getUrl: function init(path) {
Tabletop.init( { key: path,
callback: showInfo,
simpleSheet: true } )
}
}
function showInfo(data, tabletop){
var new_data = JSON.stringify(data.map(function(el) {
return {
"name": el[Object.keys(el)[0]],
"y": +el[Object.keys(el)[1]]
};
}));
}
})
Controller.js
angular.module('myApp')
.controller('piechartCtrl', [ '$scope', 'chartService', function (chartService, $scope) {
console.log(chartService.showInfo.new_data)
}]);
Service
angular.module('myApp').service('chartService', function (){
return {
init: init,
showInfo: showInfo
};
function init(path) {
return Tabletop.init({
key: path,
callback: showInfo,
simpleSheet: true
});
}
function showInfo(data, tabletop){
return JSON.stringify(data.map(function(el) {
return {
"name": el[Object.keys(el)[0]],
"y": +el[Object.keys(el)[1]]
};
}));
}
});
Controller
angular.module('myApp').controller('piechartCtrl', [ '$scope', 'chartService', function (chartService, $scope) {
var tabletop = chartService.init(),
chartInfo = chartService.showInfo(someData, tabletop);
console.log(chartInfo);
}]);
I don't know exactly what you wanted with the parameters in showInfo but this should get you a good way in the right direction.
Best way is with Promise.
In angular you have the q framework as $q service $q docs
Service
angular.module('myApp')
.service('chartService', function($q) {
var deferredSpreadsheet = $q.defer();
return {
getSpreadsheet: function init(path) {
Tabletop.init({
key: path,
callback: showInfo,
simpleSheet: true
});
return deferredSpreadsheet.promise;
},
}
function showInfo(data, tabletop) {
data = JSON.stringify(data.map(function(el) {
return {
"name": el[Object.keys(el)[0]],
"y": el[Object.keys(el)[1]]
};
}));
deferredSpreadsheet.resolve(data);
}
})
Controller
angular.module('myApp')
.controller('piechartCtrl', ['$scope', 'chartService', function($scope, chartService) {
var path = "https://docs.google.com/spreadsheet/pub?hl=en_US&hl=en_US&key=0AmYzu_s7QHsmdDNZUzRlYldnWTZCLXdrMXlYQzVxSFE&output=html";
var pro = chartService.getSpreadsheet(path).then(function(data) {
console.log(data)
})
}]);
Working example here
Dirty way: You can use Broadcast and Emit
in the Service:
$rootScope.$broadcast('myEvent', JSONSTUFF);
in the Controller:
$scope.$on("myEvent", function(e, json){
console.log(json);
});
My function is using update() method to update object's value. The problem is that it's referring to users/:user_id/tasks and I need users/:user_id/tasks/:id. Why is that so and how can I solve it?
var app = angular.module('Todolist', ['ngResource']);
app.factory('Task', [
'$resource', function($resource) {
return $resource('/users/:user_id/tasks/:id', {user_id: '#user_id'}, {update: {method: 'PUT'}});
}
]);
app.controller('TasksCtrl', [
'$scope', 'Task', function($scope, Task) {
$scope.user = gon.current_user
$scope.updateTitle = function(data, task) {
Task.update({
user_id: $scope.user.id,
id: task.id,
title: data
});
};
}
]);
You are not setting id parameter value when defining $resource
Use
return $resource('/users/:user_id/tasks/:id', {
user_id: '#user_id',
id: '#id'
}, {
update: {
method: 'PUT'
}
});
Lets say I have a factory called 'Stuff'.
app.factory('Stuff', function($resource) {
return $resource('api/v1/stuff/', {}, {
getThings: {
method: 'GET',
params: {id: '#id'},
url: 'api/v1/things/:id',
isArray: true
}
});
});
In this factory I have a custom getThings function.
In my controller, if I do this:
$scope.stuffs = Stuff.query();
$scope.things = Stuff.getThings({id: $scope.stuffs[0].id});
It works, and $scope.things is what I want.
But if I do this:
$scope.stuffs = Stuff.query();
$scope.things = $scope.stuffs[0].$getThings();
I get an error in angular-resource.
The ajax call happens to the correct url and I get correct data back but getThings errors out immediatly after getting data, and the only thing left in $scope.things is what looks like a promise:
Object {then: function, catch: function, finally: function}
The error in JS console is:
TypeError: undefined is not a function
at http://dev.blah.com/assets/angular-resource/angular-resource.js?body=1:558:27
at forEach (http://dev.blah.com/assets/angular/angular.js?body=1:326:18)
at $http.then.value.$resolved (http://dev.blah.com/assets/angular-resource/angular-resource.js?body=1:556:17)
at wrappedCallback (http://dev.blah.com/assets/angular/angular.js?body=1:11574:81)
at wrappedCallback (http://dev.blah.com/assets/angular/angular.js?body=1:11574:81)
at http://dev.blah.com/assets/angular/angular.js?body=1:11660:26
at Scope.$eval (http://dev.blah.com/assets/angular/angular.js?body=1:12703:28)
at Scope.$digest (http://dev.blah.com/assets/angular/angular.js?body=1:12515:31)
at Scope.$apply (http://dev.blah.com/assets/angular/angular.js?body=1:12807:24)
at done (http://dev.blah.com/assets/angular/angular.js?body=1:8380:45)
I can't figure out why this isn't working.
I believe a promise is returned on a resource query. Try this:
Stuff.query(function(response) {
response[0].$getThings(function(things) {
$scope.things = things;
);
});
Or:
Stuff.query()
.$promise
.then(function(stuff) {
$scope.stuffs = stuff;
return stuff[0].$getThings();
})
.then(function(things) {
$scope.things = things;
});
See this plnkr http://plnkr.co/edit/qlMrZ9?p=preview. You are returned a $promise on $resource.query() and using the returned value before it is resolved will get you errors.
This is in services.js
var myServices = angular.module('myApp.services', ['ngResource']);
myServices.factory('Stuff', ['$resource', function($resource) {
return $resource('stuff.json', {}, {
getThings: {
method: 'GET',
params: {id: '#id'},
url: ':id/things.json',
isArray: false
}
});
}]);
This is in controllers.js
angular.module('myApp.controllers', [])
.controller('MyCtrl1', ['$scope', 'Stuff', function($scope, Stuff) {
$scope.data = {};
$scope.thingies = [];
$scope.data = Stuff.get();
console.log('is stuffs resolved='+$scope.data.$resolved);
$scope.thingies = Stuff.getThings({id: 'id1'});
console.log('is thingies resolved='+$scope.thingies.$resolved);
}])
.controller('MyCtrl2', ['$scope', 'Stuff', function($scope, Stuff) {
$scope.data = {};
$scope.thingies = [];
$scope.status = [];
Stuff.get(function(response){}).$promise.then(
function(value1) {
$scope.data = value1;
console.log("MyCtrl 2 stuffs="+$scope.data.stuffs[0].id);
Stuff.getThings({id:$scope.data.stuffs[0].id}).
$promise.then(
function(value2){
$scope.thingies = value2;
console.log("MyCtrl 2 thingies="+value2.things);
}, function(error2){
console.log('error in Stuff.getThingies='+error2);
$scope.status = error2;
});
}, function(error1){
console.log('error in Stuff.get='+error1);
$scope.status = error1;
}
);
}]);
I don't understand your line of code. There is something missing for this line to work.
$scope.stuffs[0].$getThings();
You need to show us your actual code or create a plnkr so that we can help you better.
I'm doing some small exercises to learn AngularJS, trying to understand how to work with promises at the moment.
In the following exercise, I'm trying to get some data async. I can see the data in the console.log but the promise is returned NULL.
GET /entries 200 OK
Promise is resolved: null
Anyone experienced can give me some advice to understand what I'm doing wrong ? Thanks for looking!
angular.module('questions', [])
.config(function($routeProvider) {
$routeProvider
.when('/', {
controller: 'MainCtrl',
resolve: {
'MyServiceData': function(EntriesService) {
return EntriesService.promise;
}
}
})
})
.service('EntriesService', function($http) {
var entries = null;
var promise = $http.get('entries').success(function (data) {
entries = data;
});
return {
promise: promise,
all: function() {
return entries;
}
};
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
console.log('Promise is resolved: ' + EntriesService.all());
$scope.title = "Q&A Module";
$scope.entries = EntriesService.all() || [];
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
}]);
/****** Thanks everyone for your help so far *****/
After taking the advice of #bibs I came up with the following solution, that's clear using ngResource:
angular.module('questions', ['ngResource'])
.factory('EntriesService', function($resource){
return $resource('/entries', {});
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
$scope.title = "Q&A Module";
$scope.entries = [];
EntriesService.query(function(response){
$scope.entries = response;
});
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
}]);
You should access the data in the callback. Since entries maybe empty before the data arrives, the all() function is not quite useful in this case.
Try this, you should be able to chain then() method to synchronously get data.
.service('EntriesService', function ($http) {
var services = {
all: function () {
var promise = $http.get('entries').success(function (data) {
entries = data;
}).error(function (response, status, headers, config) {
//error
});
return promise;
},
someOtherServices: function(){
var promise = ....
return promise;
}
return services;
}
});
$scope.entries = [];
EntriesService.all().then(function(data){
$scope.entries = data;
});
If you want the data returned by the server to be immediately reflected in your view:
.service('EntriesService', function($http) {
var entries = [];
var promise = $http.get('entries').success(function (data) {
for (var i = 0; i < data.length; i++) {
entries[i] = data[i];
}
});
return {
promise: promise,
all: entries
};
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
$scope.title = "Q&A Module";
$scope.entries = EntriesService.all;
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
You may want to check out $resource to do this for you: http://docs.angularjs.org/api/ngResource.$resource