$stateProvider.state('blogPost', {
url: '/post/:id',
templateUrl: 'blogpost.html',
controller : function($scope, $stateParams){
$scope.postId = $stateParams.id;
}
})
I had a service which will fetch the blog content base on $stateParams.id, but how to execute that service only when the user reached the blogPost page? About is my state of the blogPost. I know I cannot call my service in that state because I can't inject that in my config.
I'm assuming your data comes as a promise from a http call. Which means that you should use the resolve property.
$stateProvider.state('blogPost', {
url: '/post/:id',
templateUrl: 'blogpost.html',
controller : function($scope, $stateParams, blogposts){
$scope.blogposts = blogposts;
},
resolve: {
blogposts: function(yourBlogDataService, $stateParams) {
return yourBlogDataService.getBlogPosts($stateParams.id)
}
}
})
As you can see you know just inject the blogpost object as parameter into your controller:
controller : function($scope, $stateParams, blogposts){
$scope.blogposts = blogposts;
}
Related
I have a state as such:
.state('home.deletemsg', {
views: {
"contentworker#": {
url: '/delete/:entityname/:id/:redirectstate',
templateUrl: "Scripts/proteanapp/templates/delete.html",
controller: 'deletectrl',
controllerAs: 'del',
authenticate: true
}
}
Then in the controller I have:
return app.controller('deletectrl', ['$scope', '$rootScope', '$stateParams', function ($scope, $rootScope, $stateParams) {
debugger;
// check for ui router error
var del = this;
del.entityname = $stateParams.entityname;
del.entityid = $stateParams.id;
}]);
Calling $state.go from a controller like :
$state.go('home.deletemsg', { 'entityname': cd.Customer.Name, 'id': cd.Customer.CustomerID }, { 'location': false, 'notify': true });
But the $stateParams is empty, I don't understand why it is empty. I have tried putting an params object into the state and also resolve.
$stateParams.entityname //undefined
$stateParams.id //undefined
url option should be present there on state definition directly, not inside views object of state. But even your controller should not have been called the way you have configured your state.
Code
.state('home.deletemsg', {
//url should present here, rather than putting it inside `views`
url: '/delete/:entityname/:id/:redirectstate',
views: {
"contentworker#": {
templateUrl: "Scripts/proteanapp/templates/delete.html",
controller: 'deletectrl',
controllerAs: 'del',
authenticate: true
}
}
In a $stateProvider state I want to:
Load a service JS file
Resolve a service function (API call)
Pass resulting data to controller
controllers/my-controller.js
angular.module('app').
controller('MyController', ['$scope', function($scope, serviceData){
console.log(serviceData)
}]);
config.js
...
.state('main', {
url: "/",
templateUrl: 'templates/my-template.html',
controller: 'MyController',
resolve: {
dependencies: ['$ocLazyLoad', function($ocLazyLoad) {
return $ocLazyLoad.load([
'controllers/my-controller.js'
])
}],
serviceData: ['$ocLazyLoad', '$injector', function($ocLazyLoad, $injector) {
return $ocLazyLoad.load('services/my-service.js')
.then(function(){
var $myService = $injector.get('MyService');
return $myService.GetData();
})
}]
}
})
I would expect the controller to console.log the data coming back from the API call that MyService does (not included for brevity, but that part works). Instead, I get undefined.
Any ideas?
Thanks!
Using angular ui-router I'm trying to use $state.go() to change to the blogEdit state after creating a new entry with blogCreate to continue editing after saving. When I click to save and trigger addPost() method, it doesnt redirect correctly and I see /#/null as the route in the address bar instead of the expected /blog/post/:postId/edit.
blogModule.controller('PostCreateController', ['$scope', '$state', '$stateParams', 'PostResource',
function ($scope, $state, $stateParams, PostResource) {
$scope.post = new PostResource();
$scope.addPost = function () {
$scope.post.$save(function () {
$state.go('blogEdit', {postId: $stateParams.postId}); // THIS SHOULD REDIRECT TO CONTINUE EDITING POST
});
}
}
]);
blogModule.controller('PostEditController', ['$scope', '$stateParams', 'PostResource',
function ($scope, $stateParams, PostResource) {
$scope.post = PostResource.get({postId: $stateParams.postId});
$scope.updatePost = function () {
$scope.post.$update({postId: $stateParams.postId});
}
}
]);
State route configuration:
var app = angular.module('app', [
'ui.router',
'blogModule'
]);
app.config(['$stateProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('blog', {
url: '/blog',
templateUrl: 'app/blog/view/blog-list.html',
controller: 'PostListController'
})
.state('blogView', {
url: '/blog/post/{postId:[0-9]}',
templateUrl: 'app/blog/view/blog-detail.html',
controller: 'PostViewController'
})
.state('blogCreate', {
url: '/blog/post/new',
templateUrl: 'app/blog/view/blog-create.html',
controller: 'PostCreateController'
})
.state('blogEdit', {
url: '/blog/post/{postId:[0-9]}/edit',
templateUrl: 'app/blog/view/blog-edit.html',
controller: 'PostEditController'
});
}]);
It seems to do this regardless of what state I try to change to.
I suppose you are saving your post on backend. When you perform save (PUT) operation your backend should return you some response. The response should be like HTTP 201 Entity created and there should be location attribute set (f.e. http://example.com/blog/post/1). Then you can get the id from location header like this:
$scope.post.$save(function (createdPost, headers) {
var postId = headers.location.split("/").pop();
$state.go('blogEdit', {postId: postId});
});
Another way is to just ignore headers and return json response from your backend. F.e. {"postId": 1, "title": "New post", ...}. Then you can do something like:
$scope.post.$save(function (createdPost) {
$state.go('blogEdit', {postId: createdPost.postId});
});
The most important is to know API of your backend (what "it returns").
I'm setting up an access control system in angular. This is how it looks so far.
It's doing the ajax to return the current user's role, then checking that role with the access array to see if the user has permission. If not it redirects.
That all works fine, but the view is still being shown for a split second before the redirect.
It may also be important to note that the ajax request is necessary because the user auth is being handled with Laravel, so I made an API for Angular to talk to get information about the user's session.
var app = angular.module('application', ['ngResource']);
app.config(function($routeProvider){
$routeProvider
.when('/admin', {
controller: 'showAdmin',
templateUrl: 'admin.html',
access: ['Admin', 'Manager'],
resolve: AppCtrl.resolve
});
});
function AppCtrl ($scope, getUser, $location, $rootScope) {
}
AppCtrl.resolve = {
getUser : function($q, $http, $location, $rootScope) {
return $http({
method: 'GET',
url: '/api/getUser'
})
.success(function(data, status) {
$rootScope.user = data;
if($rootScope.access.indexOf(data.permissions[0].role_name) < 0) $location.path('/');
});
}
};
app.run(function ($rootScope, sessionFactory, $location){
$rootScope.$on('$routeChangeStart', function (event, next) {
$rootScope.access = next.access;
});
});
Use an ng-cloak directive on the containing element to eliminate the flicker. See this page for an example along with some CSS/browser-specific gotchas.
I have 2 routes that share a controller, one needs data resolved prior to the view loading, and the other does not need the resolved data.
Routing segment example:
...
when('/users', {
controller: 'UsersCtrl',
templateUrl: '/partials/users/view.html',
resolve: {
resolvedData : ['Accounts', function(Accounts) {
return Accounts.get();
}]
}
}).
when('/users/add', {
controller: 'UsersCtrl',
templateUrl: '/partials/users/add.html'
})
...
Controller example:
app.controller('UsersCtrl', ['$scope', 'Helper', 'resolvedData',
function($scope, Helper, resolvedData) {
// this works for the first route, but fails for the second route with
// unknown "resolvedDataProvider"
console.log(resolvedData);
}]);
Is there any way I can get the resolvedData in the controller without explicitly using the resolve name as a dependency? So a check can be performed?
Using the $injector does not work. I would like to do something similar to:
if ($injector.has('resolveData')) {
var resolveData = $injector.get('resolveData');
}
However this does not work even for the route that has the resolveData set ('/users'):
app.controller('UsersCtrl', ['$scope', 'Helper', '$injector',
function($scope, Helper, $injector) {
// this does not work -> fails with the unknown "resolvedDataProvider" as well
$injector.get('resolvedData');
}]);
Can this be done in angularjs? Or should I just create a new controller?
Thank you.
Looks like I figured out another way to go. The resolved data is part of the $route. So you can access it using:
app.controller('UsersCtrl', ['$scope', '$route', 'Helper',
function($scope, $route, Helper) {
if ($route.current.locals.resolvedData) {
var resolvedData = $route.current.locals.resolvedData;
}
}]);
If the other route doesn't need it, just inject undefined on that route:
router:
when('/users', {
controller: 'UsersCtrl',
templateUrl: '/partials/users/view.html',
resolve: {
resolvedData : ['Accounts', function(Accounts) {
return Accounts.get();
}]
}
}).
when('/users/add', {
controller: 'UsersCtrl',
templateUrl: '/partials/users/add.html',
resolve: {
resolvedData: function() {
return undefined;
}
}
})
controller:
app.controller('UsersCtrl', ['$scope', 'Helper', 'resolvedData',
function($scope, Helper, resolvedData) {
if(resolvedData){
//set some scope stuff for it
} else {
//do what you do when there is no resolvedData
}
}]);