Passing result of resolve into controller with UI-Route - angularjs

I'm trying to learn how to use resolves with UI-Router, and I think there's a piece of information I'm missing, because I can't figure out how to make them work.
I have a state set like this:
app.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('testState', {
url: '/testRoute',
controller: 'TestContoller',
views: {
"body": {
templateUrl: "testHtml.html"
}
},
resolve: {
test: function(){
return {value: "test"};
}
}
})
}]);
And then I have a controller:
app.controller("TestController", ["$scope", "test", function($scope, test) {
console.log(test);
}]);
then I have a testHtml.html partial file that doesn't have anything in at the moment:
<div ng-controller="TestController">
Test content
</div>
And that gets loaded into the ui-view in index.html:
<div ui-view="body" autoscroll></div>
I've been fiddling around with this for an hour or so now and googling around and I can't quite figure out what I should be doing to get the resolve to do something and pass the result into the controller.

When you mention views properties on state level options, it ignores templateUrl & controller on that state. It only take controller & template/templateUrl from one of view.
Code
views: {
"body": {
templateUrl: "testHtml.html",
controller: 'TestContoller' //moved it to named-view level
}
},

Related

How to hide content in the parent view when the user goes to a nested state and show it again when the user backs to the parent one?

I use ui-router and have two nested views.
I’d like to hide some html-content in the parent view when the user goes to child state and show it again when the user backs to parent one.
Could anybody give an advice how to achieve that?
It’s easy to do that using root scope and state change events but it looks like a dirty way, doesn’t it?
app.js
'use strict';
var myApp = angular.module('myApp', ['ui.router']);
myApp.controller('ParentCtrl', function ($scope) {
$scope.hideIt = false;
});
myApp.controller('ChildCtrl', function ( $scope) {
$scope.$parent.hideIt = true;
});
myApp.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('parent', {
url: '/parent',
templateUrl: 'parent.html',
controller: 'ParentCtrl'
})
.state('parent.child', {
url: '/child',
template: '<h2>Child view</h2>',
controller: 'ChildCtrl'
});
});
parent.html
<h2>Parent view</h2>
<div ng-hide="hideIt">
<p>This text should be hidden when the user goes to the nested state.</p>
</div>
<a ui-sref="parent.child">Go to the nested view</a>
<div ui-view></div>
One simple solution is to fill ui-view tag in the parent template with the content that you want gone when child state is loaded.
<ui-view>
<h2>Parent view</h2>
<div ng-hide="hideIt">
<p>This text should be hidden when the user goes to the nested state.</p>
<a ui-sref="parent.child">Go to the nested view</a>
</ui-view>
You should check out named views for this. That would probably be the best way to go. https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
Also, there's another thread that answered this question over here: https://stackoverflow.com/a/19050828/1078450
Here's the working code for nested named views, taken from that thread:
angular.module('myApp', ['ui.state'])
.config(['$stateProvider', '$routeProvider',
function($stateProvider, $routeProvider) {
$stateProvider
.state('test', {
abstract: true,
url: '/test',
views: {
'main': {
template: '<h1>Hello!!!</h1>' +
'<div ui-view="view1"></div>' +
'<div ui-view="view2"></div>'
}
}
})
.state('test.subs', {
url: '',
views: {
'view1#test': {
template: "Im View1"
},
'view2#test': {
template: "Im View2"
}
}
});
}
])
.run(['$state', function($state) {
$state.transitionTo('test.subs');
}]);
http://jsfiddle.net/thardy/eD3MU/
Edit:
Adding some thoughts re the angular-breadcrumbs comment. I haven't used it myself, but at first glance it seems like subroutes shouldn't break the breadcrumbs. I'm just looking at the source code of their demo, around line 62. I'd have to spin it all up to really go about testing it, but it looks like they're doing almost the same thing with specifying views, and it works there: https://github.com/ncuillery/angular-breadcrumb/blob/master/sample/app.js#L62
.state('room', {
url: '/room',
templateUrl: 'views/room_list.html',
controller: 'RoomListCtrl',
ncyBreadcrumb: {
label: 'Rooms',
parent: 'sample'
}
})
.state('room.new', {
url: '/new',
views: {
"#" : {
templateUrl: 'views/room_form.html',
controller: 'RoomDetailCtrl'
}
},
ncyBreadcrumb: {
label: 'New room'
}
})
.state('room.detail', {
url: '/{roomId}?from',
views: {
"#" : {
templateUrl: 'views/room_detail.html',
controller: 'RoomDetailCtrl'
}
},
ncyBreadcrumb: {
label: 'Room {{room.roomNumber}}',
parent: function ($scope) {
return $scope.from || 'room';
}
}
})
Edit2:
This solution will not combine routes into one crumb
See the official demo
re: But I use angular-breadcrumb and in your solution they will be combined into one crum.

many controller for state in ui-router

how to add many controller for state in ui-router ?
I have searched long and hard but found nothing that helped yet. Where I wrong? I really do not know what to do. I wrote all the details below. I've tried and did not succeed.
angular.module('uiRouterApp.typeNews', [
'uiRouterApp.typeNews.Service',
'ui.router'
])
.config(
[
'$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('detail', {
url: '/typeNews/detail/typeNewsId=:typeNewsId',
templateUrl: '/Scripts/ui-route/typeNews/typeNews.detail.html',
controller: [
'$scope', '$stateParams', '$state', 'typeNewsService',
function($scope, $stateParams, $state, typeNewsService) {
typeNewsService.readTypeNews($stateParams.typeNewsId)
.success(function(data, status, headers, config) {
$scope.typeNews = data;
});
}
]
})
.state('typeNews', {
url: '/typeNews/PageSize=:PageSize/PageIndex=:PageIndex',
templateUrl: '/Scripts/ui-route/typeNews/typeNews.html',
controller: 'pagerCtrl'// need two many controller like controller: 'pagerCtrl' , 'gridCtrl'
});
}
]
);
Every state in your state provider maps to a single controller.
Having multiple (many) controllers handling one state is not possible and goes against the basic concept of the framework.
I don't understand what you want to achieve with multiple controllers in one state.
What is your idea and how should this function? Can you explain?
You can have parent and child states and they can have their own controllers. Maybe that is what could help you out.
Based on your comment:
controller: 'pagerCtrl'// need two many controller like controller: 'pagerCtrl' , 'gridCtrl'
I think you want controllers for ui elements. You probably want to use or create a Directive. Have a look at ngTable and ng-Grid for example.
Yes u will need this if u reference some other controllers info....just add one controller to the state and the other one u can nest it as a ng-controller in the html.
JS snippet
angular.module('xTimeApp').config(function ($stateProvider, $httpProvider) {
$stateProvider.state('editpayhistory', {
url: '/payhistory/:id/edit',
templateUrl: '../PayHist/PayHist-edit.html',
controller: 'PayHistEditController' //<-Controller 1
});
HTML snippet:
<div class="form-group">
<div data-ng-controller="AttendanceListController"> <!--Controller 2 -->
<label for="title" class="col-sm-2 control-label">Attendance</label>
<!--Need to compare with same object type, so create an empty _attend object with the payhist id as the _attend id field-->
<div class="col-sm-10">
<select ng-init="payhist._attend = {AC_CODEID: payhist.AC_CODEID}"
ng-change="payhist.AC_CODEID = payhist._attend.AC_CODEID"
ng-model="payhist._attend"
ng-options="attend.AC_CODEID as attend.AC_NAME for attend in attends track by attend.AC_CODEID"></select>
</div>
</div>
.state('app.somestate', {
url : '/someurl',
views:{
'menuContent': {
templateUrl: 'part1.html',
controller: 'ACtrl'
},
'otherContent': {
templateUrl: 'part2.html',
controller: 'BCtrl'
},
'someotherContent': {
templateUrl: 'part3.html',
controller: 'CCtrl'
}
}
})

child state controller not being reached in angular-ui-router

I have the following setup in my code
.config(function config($stateProvider)
$stateProvider
.state('home', {
url : '/home',
views : {
'main' : {
controller : 'HomeCtrl',
templateUrl : 'home/home.tpl.html'
}
}
})
.state('home.details', {
url : '/details',
views : {
" " : {
template : "<h1>hello</h1>",
controller : function ($scope, $http, $state) {
//do some stuff here
//does not seem to reach code in here
}
}
}
});
})
.controller('HomeCtrl', function ($scope, $http, $state) {
//on a button click do $state.go('.details');
});
When I do this , the button click on my HomeCtrl seems to take me to /home/details but it does not seems to go inside the controller in that particular route at that point. (I checked by putting a break point inside the controller for the details.) Is there something wrong with my setup? I'm trying to do something similar to this sample app shown in the ui-router webpage.
The solution here would in a named-view (not) matching. Here is the working plunker.
We have to place the named ui-view inside of the parent view (or use more precise naming, see for example here)
So, the parent, home template should contain the named ui-view, e.g. nameOtherThanSpace
<div ui-view="nameOtherThanSpace" ></div>
And the child defintion must target that view, the complete snippet is:
$stateProvider
.state('home', {
url: '/home',
views: {
'main': {
controller: 'HomeCtrl',
template: '<div>' +
'<h1>hello from parent</h1>' +
'<hr />' +
'<div ui-view="nameOtherThanSpace" ></div>' +
'<div>',
}
}
})
.state('home.details', {
url: '/details',
views: {
"nameOtherThanSpace": {
template: "<h2>hello from a child</h3>",
controller: function($scope, $http, $state) {},
}
}
});
How to use more specific view names:
View Names - Relative vs. Absolute Names
UI-Router isnt rendering childs correctly with templateurl in Asp.net Mvc
The working plunker using the name nameOtherThanSpace, instead of " " (space)
Try registering your controller on the app instead of on your $stateProvider. e.g.
var app = angular.module('myApp', []);
app.controller('HomeCtrl', function ($scope, $http, $state) {
//on a button click do $state.go('.details');
});
Update 1:
You should only need to specify a view if you have multiple views in which case the view probably needs to have a name. But you only have one view for that state so I would just do this.
.state('home.details', {
url : '/details'
template : "<h1>hello</h1>",
controller : function ($scope, $http, $state) {
//do some stuff here
//does not seem to reach code in here
}
}

When using angular-ui-router, what is the suitable structure for controller?

Before use angular-ui-router, one controller always support several router&views, such as:
$routeProvider.
when('/posts', {
templateUrl: 'views/posts/list.html'
}).
when('/posts/create', {
templateUrl: 'views/posts/create.html'
}).
all views for one object share one controller:
app.controller('PostsCtrl', function($scope) {
$scope.create = function() {
// ...
}
$scope.list = function() {
// ...
}
});
and init data in view:
<div data-ng-controller="PostsController" data-ng-init="list()">
...
</div>
But in angular-ui-router, we use state, so we need create several controller for each state, such as:
$stateProvider
.state('posts', {
abstract: true,
url: '/posts',
templateUrl: 'views/posts/list.html',
controller: 'PostsCtrl'
})
.state('posts.detail', {
url: '/:postId',
templateUrl: 'views/posts/detail.html',
controller: 'PostsDetailCtrl'
})
Separating controller seems not a good design pattern.
So, is there any better suggestion to structure controllers?
It is a little late for an answer, but as I was struggling with it and found an answer, I might as well post it.
I agree with Nate's comment that in most circumstances you should keep the controllers as small as possible, i.e. you should write a separate controller for every state. However, if you find yourselves in a situation that really think that using the same controller for both the parent and child views is preferable you can simply omit the controller option in the child view. This view will then use the state of the parent. This can be read in the documentation. A little example:
app.js
app.controller('testController', ['$scope', function($scope){
$scope.message= 'This comes from testController';
}]);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider ,$urlRouterProvider) {
$stateProvider
.state('test', {
url: '/test',
templateUrl: 'partials/test.html',
controller: 'testController'
})
.state('test.child', {
url: '/child',
templateUrl: 'partials/test2.html'
});
}]);
partials/test.html
<div>
Test.html: {{message}}
<div data-ui-view></div>
</div>
partials/test2.html
<div>
Test2.html: {{message}} as well.
</div>
This will produce the following (with url #/test/child)
Test.html: This comes from testController
Test2.html: This comes from testController as well.
I hope this helps anyone

Routing in angularjs for multiple controllers?

I'm trying to build a view - I've set up two controllers to practice, one's HeaderCtrl, with some data in it (site title, header background, etc), the other should have the main content of the page - MainCtrl.
When defining the route, I'm doing like so:
mainApp.config(function ($routeProvider) {
$routeProvider
.when('/',
{
controller: 'MainCtrl',
templateUrl: 'modules/dashboard.html'
})
})
This works perfectly fine, but what I would want is to specify multiple parameters to this, something like this:
mainApp.config(function ($routeProvider) {
$routeProvider
.when('/',
{
controller: 'HeaderCtrl',
templateUrl: 'modules/header.html'
},
{
controller: 'MainCtrl',
templateUrl: 'modules/dashboard.html'
})
})
This doesn't work so I'm guessing it's not the way to do it. What I'm actually asking - can you specify multiple controllers in $routeProvider ? Or what would be the correct way to build this view ?
My approach to this problem would be to have two directives - header and main which reference the corresponding templates.
For Example:
app.directive('header', function () {
return {
restrict: 'A',
replace: true,
templateUrl:'templates/header.html'
}
})
Then you can have a page that contains the directives - index.html.
<div header></div>
<div main></div>
Then have one controller that routes to your index.html
You can also encapsulate the header and main in separate header and main controllers if you want to deal with them separately.
e.g.
<div ng-controller="HeaderCtrl">
<div header></div>
</div>
<div ng-controller="MainCtrl">
<div main></div>
</div>
or with the templates themselves
What you might want to do is place your HeaderCtrl outside of ng-view and then have MainCtrl mapped to your index route (ie. '/'). If you needed to have multple controllers mapped to your index route, you can assign them within the template that you have mapped to that route. Here is what that would look like:
index.html
<html>
<body ng-app='yourApp'>
<div id="header" ng-controller="HeaderCtrl"></div>
<div ng-view></div>
</body>
</html>
app.js
angular.module('mainApp', []).
config(function ($routeProvider) {
$routeProvider.when('/', {
controller: 'MainCtrl',
templateUrl: 'modules/dashboard.html'
})
});
dashboard.html
<div ng-controller="SomeCtrl"></div>
<div ng-controller="SomeOtherCtrl"></div>
...or, if you really wanted to get creative, you could include ui-router from the AngularUI folks https://github.com/angular-ui/ui-router This would allow you to have multiple "views" and map them to your routes.
You should use angular's ui-router : https://github.com/angular-ui/ui-router, you can specify a controller and template for each "element" of your page :
myApp.config(function($stateProvider) {
$stateProvider
.state('index', {
url: "",
views: {
"viewA": { template: "index.viewA" },
"viewB": { template: "index.viewB" }
}
})
.state('route1', {
url: "/route1",
views: {
"viewA": { template: "route1.viewA" },
"viewB": { template: "route1.viewB" }
}
})
.state('route2', {
url: "/route2",
views: {
"viewA": { template: "route2.viewA" },
"viewB": { template: "route2.viewB" }
}
})
});
I don't think you can specify multiple controllers. I think what you're looking for is something like an 'index.html' template that refers to your header and dashboard:
<div id='header' ng:controller='HeaderCtrl' />
<div id='main' ng:controller='MainCtrl' />
To actually fill in with the right templates, I would use a directive. I think this is one of the most powerful parts of angular. You can create a header directive that you can reuse on all your pages.
Try this it should work
mainApp.config(function ($routeProvider) {
$routeProvider
.when('/',
{
controller: 'HeaderCtrl',
templateUrl: 'modules/header.html'
}).when('', //route here in the empty quotes
{
controller: 'MainCtrl',
templateUrl: 'modules/dashboard.html'
});
});

Resources