I have the following resolve:
.state('posts', {
url: '/posts/{id}',
templateUrl: 'posts.html',
controller: 'postsController as postsCtrl',
resolve: {
post: getSinglePostWrapper
}
})
and helper function
getSinglePostWrapper.$inject = ['postsService', '$stateParams'];
function getSinglePostWrapper(postsService, $stateParams) {
return postsService.getSinglePost($stateParams.id);
}
and my controller looks like this:
angular.module('flapperNews')
.controller('postsController', postsController);
postsController.$inject = ['postsService', 'post'];
function postsController(postsService, post) {
var vm = this;
vm.post = post;
console.log(post); //undefined here
}
I'm getting an undefined "post" when I try to inject the post from the resolve. I tried logging the post in the getSinglePostWrapper function, and it logs the correct object. I seem to be losing some binding or something from the resolve to the controller.
posts service
angular.module('flapperNews')
.factory('postsService', postsService);
postsService.$inject = ['httpService'];
function postsService(httpService) {
return {
getSinglePost: getSinglePost
}
function getSinglePost(postId) {
httpService.baseGet('/posts/' + postId)
.then(function(data) {
return data;
}, function(data) {});
}
}
httpservice
angular.module('httpService', [])
.factory('httpService', httpService);
httpService.$inject = ['$http', '$q'];
function httpService($http, $q) {
return {
baseGet: baseGet
}
function baseGet(url) {
return $http.get(url).then(
function (result) {
return result.data;
},
function (result) {
return $q.reject(result);
}
);
}
}
and I've injected httpservice into the first place I declare the flapperNews module.
FYI- everything is working. Other http requests are fine. This one is fine too. It just doesn't inject the post into the controller.
Promise chain breaks here.
function getSinglePost(postId) {
httpService.baseGet('/posts/' + postId)
.then(function(data) {
return data;
}, function(data) {});
}
You don't return the promise, hence post will be resolved to undefined before httpService.baseGet request has been finished.
try this:
.state('posts', {
url: '/posts/{id}',
templateUrl: 'posts.html',
controller: 'postsController as postsCtrl',
resolve: {
post: function('postsService', '$stateParams') {
return postsService.getSinglePost($stateParams.id);
}
})
angular.module('flapperNews')
.controller('postsController', function($scope, post){
$scope.post = post;
console.log($scope.post); //undefined here
});
Related
Here is my code :
Js:
angular.module('main', [])
.config(['$locationProvider', '$routeProvider',
function($locationProvider, $routeProvider) {
$routeProvider.when('/tables/bricks', {
controller: "myController",
resolve: {
"check" : function($location){
if(!$scope.bricks) {
$route.reload();
}
}
},
templateUrl: 'tables/bricks.html'
});
$routeProvider.otherwise({
redirectTo: '/tables/datatables'
});
}
])
.controller('myController', function($scope, $location, $http) {
var vm = this;
$scope.Bricks = function(){
$location.path('/tables/bricks');
};
vm.getbricks = function(n){
var url = n;
$http({
method: 'GET' ,
url: url,
})
.then(function successCallback(data) {
$scope.bricks = data.data;
console.log($scope.bricks);
}, function errorCallback(response) {
console.log(response);
console.log('error');
});
};
});
HTML:
<button ng-click="vm.getbricks(n.bricks_url);Bricks();"></button>
After click the button in html, my page goes into /tables/bricks, but nothing happend, because resolve probably is wrong. What I want - that i could go to /tables/bricks only then, when $scope.bricks exist, so only when vm.bricks() will be called.
Thanks for answers in advance!
I think your problem is that the vm.getbricks will always return something (in success or error handler), so will never be falsy, and you will always call the Bricks() constructor. try to return true on success callback and false in error callback.
$scope is for controllers, which it can't reach in the config. Instead, you should be returning something from a service, which will be called during your resolve. E.g. if(YourService.getbricks())
Solution: move your logic from a controller into a service. And make sure to return a value from it that can be checked in the config.
app.service('BrickService', function() {
this.getbricks = function(url) {
return $http.get(url) // return the Promise
.then(function(response) {
return response.data; // return the data
}, function(error) {
console.log(error);
});
};
});
With this you can inject the service into the config and run its function.
angular.module('main', [])
.config(['$locationProvider', '$routeProvider',
function($locationProvider, $routeProvider) {
$routeProvider.when('/tables/bricks', {
controller: "myController",
resolve: {
"check": function(BrickService) { // inject
if ( BrickService.getbricks() ) { // run its function
$route.reload();
}
}
},
templateUrl: 'tables/bricks.html'
});
$routeProvider.otherwise({
redirectTo: '/tables/datatables'
});
}
])
You can also use the loaded values in the controller after they have been resolved. For that, you would need to simply return it. So change the logic to this:
resolve: {
"check": function(BrickService) { // inject
var bricks = BrickService.getbricks(); // run its function
if ( bricks ) {
$route.reload();
}
return bricks; // return the result (note: it's not a Promise anymore)
}
}
Then you can inject this resolve into your controller:
.controller('myController', function($scope, $location, $http, check) {
var vm = this;
vm.bricks = check;
...
(Note check was added)
I've this service, it returns a list of students asynchronously using callback:
studentModule.factory('StudentService', function (DB_URL) {
return {
getAllStudents: function (callback) {
var Datastore = require('nedb'),
path = require('path');
db = {};
db.students = new Datastore({
filename: DB_URL + '/students.db',
autoload: true
});
db.students.find({}, function (err, stds) {
callback(stds);
});
}; //end return
My old way to use it in controller:
StudentService.getAllStudents(function(sts) {
$scope.students = sts;
$scope.$apply();//notify angular about the change
});
This works for me, but now i want to use some best practices. I need to resolve the result in the route before coming to the controller, here what i did:
.state('payment', {
url: '/payment',
templateUrl: 'frontend/components/payment/views/payment.html',
controller: 'PaymentController',
resolve: {
students: function (StudentService, $q) {
var defer = $q.defer();
defer.promise.then(function () {
StudentService.getAllStudents(function (sts) {
alert(JSON.stringify(sts));
return sts;
});
})
defer.resolve();
}
}
})
The alert is returning data from the route successfully but not from the controller - i get an undefined in the controller:
paymentModule.controller('PaymentController', function($scope,students) {
alert(JSON.stringify(students));
Any help will be appreciated!
You should always return a promise to resolve functions, and, when creating a promise of your own, you should resolve it with the data you need to pass along with it.
.state('payment', {
url: '/payment',
templateUrl: 'frontend/components/payment/views/payment.html',
controller: 'PaymentController',
resolve: {
students: function (StudentService, $q) {
var defer = $q.defer();
//defer.promise.then(function () {
StudentService.getAllStudents(function (sts) {
//alert(JSON.stringify(sts));
//return sts;
defer.resolve(sts);
});
//})
//defer.resolve();
return defer.promise
}
}
})
I'm new at Javascripts and i'm trying to use Angular UI route, here is my code
myApp.config(['$stateProvider', '$urlRouterProvider',function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/test',
templateUrl: '/custom.html'
})
.state('detail', {
url: '/{examID}',
views: {
'': {
templateUrl: '/templates/customize.html',
controller: ['$scope', '$stateParams', 'utils',
function ( $scope,$stateParams,utils) {
$scope.exam = utils.findById($stateParams.examID);
console.log('exam is ' + $scope.exam );
}
]
}
}
} )
}])
and this is the service which has findbyID function
angular.module('service', [])
.factory('utils', function ( $http) {
return {
findById: function findById(id) {
$http.get('/api/exams/' + id).success(function(response) {
return response;
})}
};});
i've already follwed this topic but $scope.exam still undefined
How to return value from an asynchronous callback function?
PS. i've tried to print out response and it's an object
Thx
This is a place where a lot of developers new to JavaScript stumble.
What is going on here is that you are assigning the return value of utils.findById() to $scope.exam. The problem is that utils.findById() doesn't actually return anything. (When a function doesn't have an explicit return statement in JavaScript, the return value is implicitly undefined.)
Here is what your service should look like:
angular
.module('service', [])
.factory('utils', function ($http) {
return {
findById: function (id) {
return $http.get('/api/exams/' + id);
}
};
});
You probably noticed that the call to .success() has disappeared too! Don't worry. It just moved.
Instead of calling .success() on $http.get(), we want to call it on utils.findById(). Doing this will give you access to the response variable in your controller. Because you will have access to the response variable, you will be able to assign response to $scope.exam like so:
.state('detail', {
url: '/{examID}',
views: {
'': {
templateUrl: '/templates/customize.html',
controller: ['$scope', '$stateParams', 'utils',
function ($scope, $stateParams, utils) {
utils.findById($stateParams.examID)
.success(function (response) {
$scope.exam = response;
});
}
]
}
}
});
Hopefully that cleared it up. If I haven't been clear on anything, please let me know so I can update this answer.
You have to wait for the ajax call to finish. Modify the code in your controller to:
$scope.exam;
utils.findById($stateParams.examID).then(function(data) {
$scope.exam = data.data;
}
Read about the concept of 'Promises' in AngularJS and JavaScript.
Use deferred promise, So that it would return value after response
Service:
angular.module('service', [])
.factory('utils', function ( $http) {
return {
findById: function findById(id) {
var promise=$http.get('/api/exams/' + id);
return promise;
};});
Controller:
myApp.config(['$stateProvider',
'$urlRouterProvider',function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/test',
templateUrl: '/custom.html'
})
.state('detail', {
url: '/{examID}',
views: {
'': {
templateUrl: '/templates/customize.html',
controller: ['$scope', '$stateParams', 'utils',
function ($scope, $stateParams, utils) {
utils.findById($stateParams.examID).then(function(value) {
$scope.exam = value;
console.log('exam is ' + $scope.exam );
});
}
]
}
}
})
}])
How can I wait with my function till the $http request is finished?
My services.js looks as follows:
var app = angular.module('starter.services', []);
app.factory('Deals', function($http) {
function getDeals() {
$http.get('http://www.domain.com/library/fct.get_deals.php')
.success(function (data) {
var deals = data;
return deals;
})
.error(function(err){
});
}
return {
all: function() {
return getDeals();
},
get: function(keyID) {
//...
}
}
});
My controllers.js looks like:
var app = angular.module('starter.controllers', []);
app.controller('DealCtrl', function($scope, Deals) {
$scope.deals = Deals.all();
console.log($scope.deals);
});
The console.log in my controllers.js file outputs "undefined", but when I output the deals in the getDeals() function it contains the correct array which I get from my server.
What am I doing wrong?
$http and all of the async services in angularjs return a promise object. See promise api.
You need to use then method to assign it to a value in the scope.
So your controller:
app.controller('DealCtrl', function($scope, Deals) {
Deals.all().then(function (deals) {
$scope.deals = deals;
console.log($scope.deals);
});
});
Your service
app.factory('Deals', function($http) {
function getDeals() {
return $http.get('http://www.domain.com/library/fct.get_deals.php')
.success(function (data) {
var deals = data;
return deals;
});
}
return {
all: function() {
return getDeals();
},
get: function(keyID) {
//...
}
}
});
I am using the ui-router(http://angular-ui.github.io/ui-router/site/#/api/ui.router) solution for a form wizard and my state configuration looks like the following:
$stateProvider
.state('TabsView', {
url: '/mcm/:mcmcid',
controller: 'TabsController',
templateUrl: 'ngapps/mcm/views/TabsView.html'
})
.state('TabsView.Campaign Info', {
url: '/campaign-info',
templateUrl: 'ngapps/mcm/views/Campaign Info.html',
resolve: {
campaignFactory: 'CampaignFactory',
campaignData: function($stateParams,campaignFactory) {
return campaignFactory.getCampaignInfo($stateParams.mcmcid).$service;
}
},
controller: 'CampaignInfoController'
});
For the state "TabsView.Campaign Info" I try to resolve the campaignData by calling the CampaignFactory. The code for Campaign Factoy is as follows:
marketingCampaignModule.factory("CampaignFactory", ['AjaxFactory', '$q', function(AjaxFactory, $q) {
return {
getCampaignInfo: function(mcmcid) {
var result = {empty: true};
if (mcmcid > 0) {
var ajaxPromise = AjaxFactory.post("index.php/mcm/infosave/view", {mcmcid: mcmcid});
ajaxPromise.then(function(data) {
if (data['success']) {
if (data['params']) {
result = {'name': data['params']['name'], 'description': data['params']['description']};
}
}
return result;
});
}
}
};
}]);
campaignData in resolve does not get resolved. But I see that a call to the getCampaignInfo function of the CampaignFactory is being made in the console. I know I am doing something wrong with promise.Please tell me what am I doing wrong?
As per Chandermani's comment I modified the factory to return a promise as follows:
marketingCampaignModule.factory("CampaignFactory", ['AjaxFactory', '$q', function(AjaxFactory, $q) {
return {
getCampaignInfo: function(mcmcid) {
var deferred = $q.defer();
var result = {empty: true};
if (mcmcid > 0) {
var ajaxPromise = AjaxFactory.post("index.php/mcm/infosave/view", {mcmcid: mcmcid});
ajaxPromise.then(function(data) {
if (data['success']) {
if (data['params']) {
result = {'name': data['params']['name'], 'description': data['params']['description']};
}
}
deferred.resolve(result);
});
}else{
deferred.resolve(result);
}
return deferred.promise;
}
};
}]);
And modifed the resolve as follows:
resolve: {
campaignFactory: 'CampaignFactory',
campaignData: function($stateParams,campaignFactory) {
campaignFactory.getCampaignInfo($stateParams.mcmcid).then(function(data){
return data;
});
}
}
Still doesnt work. What am I doing wrong?
After the update you have done, you are just missing the return statement in resolve
campaignData: function($stateParams,campaignFactory) {
return campaignFactory.getCampaignInfo($stateParams.mcmcid);
}