how to create composite route in $stateProvider - angularjs

If I go to /settings/wizard/hv then I see only Settings Page. what am I doing wrong?
I have Page: "Settings" url: '/settings'
on page button.handler > go to url: '/settings/wizard'
I have this code:
$stateProvider
.state('settings', {
url: '/settings',
template: '<div>Settings panel with fields</div>',
title: 'Конфигурация',
controller: function(){
console.log('controller settings')
}
})
.state('settings.wizard', {
url: '/wizard',
abstract: true,
template: '<ui-view></ui-view>',
title: 'Мастер настройки',
/** #ngInject */
controller: function($state, $scope, $controller){
console.log('controller Wizard');
if($scope.mode == 'vw'){
$state.go('settings.wizard.vw')
}else{
$state.transitionTo('settings.wizard.hv')
}
}
})
.state('settings.wizard.hv', {
url: '/hv',
parent: 'settings.wizard',
templateUrl: 'app/plugins/settings/wizard/tpl/wizard.html',
title: 'Мастер настройки',
/** #ngInject */
controller: function ($controller, $scope) {
console.log('controller wizard/hv')
$scope.mode = 'hv';
var ctrl = $controller('Settings.Wizard');
ctrl.setMode('hv');
},
controllerAs: 'wizard'
})
.state('settings.wizard.vw', {
url: '/vw',
// parent: 'settings.wizard',
templateUrl: 'app/plugins/settings/wizard/tpl/wizard.html',
title: 'Мастер настройки',
/** #ngInject */
controller: function ($controller, $scope) {
console.log('controller wizard/vw')
$scope.mode = 'hv';
var ctrl = $controller('Settings.Wizard');
ctrl.setMode('vw');
},
controllerAs: 'wizard'
});
on Page '/settings/wizard/hv' I have some subPages and Views
<div>
settings > wizard > hv
<input />
<ui-view></ui-view>
<button onclick="$state.go('settings.wizard.hv.servers')" >go to servers</button>
</div>

First of all, try to add ui-view to your settings state template:
$stateProvider
.state('settings', {
url: '/settings',
template: '<section><div>Settings panel with fields</div><div ui-view></div></section>',
title: 'Конфигурация',
controller: function(){
console.log('controller settings')
}
})
Child states requires a spot to render into.

Related

URL doesn't change after changing ui-router state

I have followed the documentation and online tutorials to create my ui-router states however when I enter my state, the URL doesn't update. Same happens when I do $state.go('main.about-me'); for example. The state changes but not the URL. Is there something wrong with my config that I can't see clearly?
Will be thankful for any tips. Thanks.
'use strict';
angular
.module('myApp.config', ['ui.router'])
.config(routes)
.run(['$rootScope', '$location', '$stateParams', '$state', appRun]);
function routes($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
url: 'main',
abstract: true,
views: {
'': {
templateUrl: 'main/main.tpl.html',
controller: 'mainController as vm'
},
'nav-bar#main': {
templateUrl: 'main/nav-bar/nav-bar.tpl.html',
controller: 'navigationBarController as vm'
}
}
})
.state('main.home', {
url: '/home',
views: {
'content': {
templateUrl: 'home/home.tpl.html',
controller: 'homeController as vm'
}
}
})
.state('main.about-me', {
url: '/about-me',
views: {
'content': {
templateUrl: 'about-me/about-me.tpl.html',
controller: 'aboutMeController as vm'
}
}
})
.state('main.contact-me', {
url: '/contact-me',
views: {
'content': {
templateUrl: 'contact-me/contact-me.tpl.html',
controller: 'contactMeController as vm'
}
}
});
$urlRouterProvider.otherwise('');
}
function appRun($rootScope, $location, $stateParams, $state) {
console.log('run the app');
console.log('$location', $location);
console.log('$rootScope', $rootScope);
console.log('$stateParams', $stateParams);
$state.go('main.home');
}
Inside my body I have this
<div ng-cloak>
<div ui-view class="content-container"></div>
</div>

Passing resolved data to child state in Ui-Router

So, I have a state where the resolve spits out an array which shows correctly on the frontend.
But I can't seem to be able to pass the parent resolve data to the child state.
$stateProvider.state('berliner', {
url: '/berlinerliste',
params : {search: 'Berliner 2017'},
resolve: {
fair: function(SearchService, $stateParams) {
return SearchService.getAllExhibitors($stateParams.search);
}
},
views: {
'header': {
templateUrl: 'header.htm'
},
'main':{
templateUrl: 'bl2017.htm',
controller: function($scope, fair){
$scope.fair = fair;
console.log($scope.fair);
}
}
}
})
.state('berliner.exhibitor', {
url: '/{id}',
resolve: {
exhibitor: function($stateParams, fair) {
var slug = $stateParams.id;
return slug;
}
},
views: {
'header': {
templateUrl: 'header.htm'
},
'wop':{
templateUrl: 'exhibitor.htm',
controller: function($scope, exhibitor, $filter){
$scope.fairs = $scope.fair;
console.log($scope.fair);
$scope.chosenexhibitor = $filter("filter")($scope.fairs, {'slug':exhibitor}, true);
console.log($scope.chosenexhibitor);
}
}
}
})
All the console log come out undefined.
What am I missing?
PLUNKR
Here's a Plunkr to examplify the issue.
I would say, that the concept should work.. just:
controller belongs to view. not to all views: {}
E.g. this (wrong)
// each view can have controller,
// but views : {} property 'controller' is not used at all
views: {
'header': {
templateUrl: 'header.htm'
},
'wop':{
templateUrl: 'exhibitor.htm',
},
controller: function($scope, exhibitor, $filter){
$scope.fairs = $scope.fair;
console.log($scope.fair);
$scope.chosenexhibitor = $filter("filter")($scope.fairs, {'slug':exhibitor}, true);
console.log($scope.chosenexhibitor);
}
should be adjusted as that:
views: {
'header': {
templateUrl: 'header.htm'
controller: function($scope, exhibitor, $filter){
$scope.fairs = $scope.fair;
console.log($scope.fair);
$scope.chosenexhibitor = $filter("filter")($scope.fairs, {'slug':exhibitor}, true);
console.log($scope.chosenexhibitor);
}
},
'wop':{
templateUrl: 'exhibitor.htm',
controller: ...
There is an example, how
parent does resolve
child view's controller consumes it
states:
.state('parent', {
url: "/parent",
templateUrl: 'tpl.html',
resolve: {
example: ['$timeout', function($timeout){
return $timeout(function(){
return {x: 1}
},100)
}],
},
})
.state('parent.child', {
url: "/child",
templateUrl: 'tpl.html',
controller: 'ChildCtrl',
})
child controller
.controller('ChildCtrl', ['$scope', 'example', function ($scope, example) {
console.log(JSON.stringify(example));
}])
Check it here

Angular router, calling controller many times

This code is functional, but it could work better. My question:
How i can insert navDetalle or other views in many states without call controller again.
(function() {
'use strict';
angular
.module('miApp')
.config(routerConfig);
var nav = {
templateUrl: 'app/nav/nav.html',
controller: 'NavController',
controllerAs: 'nav'
};
var navInter = {
templateUrl: 'app/nav/navInter.html',
controller: 'NavController',
controllerAs: 'nav'
};
var navDetalle = {
templateUrl: 'app/navDetalle/navDetalle.html',
controller: 'NavDetalleController',
controllerAs: 'navDetalle'
};
/** #ngInject */
function routerConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
views: {
// the main template will be placed here (relatively named)
'nav': nav,
'carousel': {
templateUrl: 'app/carousel/carousel.html',
controller: 'CarouselController',
controllerAs: 'carousel'
},
'footer':{
templateUrl: 'app/footer/footer.html'
}
}
})
.state('detalle', {
url: '/detalle/:idDetalle',
views:{
'nav': navInter,
'detalle': {
templateUrl: 'app/detalle/detalle.html',
controller: 'DetalleController',
controllerAs: 'detalle'
},
'navdetalle': navDetalle,
'footer':{
templateUrl: 'app/footer/footer.html'
}
}
})
.state('resumen', {
url: '/resumen',
views:{
'nav': navInter,
'navdetalle': navDetalle,
'footer':{
templateUrl: 'app/footer/footer.html'
}
}
})
.state('success', {
url: '/success',
views:{
'nav': navInter,
'success': {
templateUrl: 'app/success/success.html',
controller: 'SuccessController',
controllerAs: 'success'
},
'navdetalle': navDetalle,
'footer':{
templateUrl: 'app/footer/footer.html'
}
}
})
.state('cancel', {
url: '/cancel',
views:{
'nav': navInter,
'navdetalle': navDetalle,
'cancel': {
templateUrl: 'app/cancel/cancel.html',
controller: 'CancelController',
controllerAs: 'cancel'
},
'footer':{
templateUrl: 'app/footer/footer.html'
}
}
});
$urlRouterProvider.otherwise('/');
}
})();
and if you have suggestion on another improvements please comment
I'm not sure if this is possible to prevent executing controller every time. But, I do have another solution. That might work. The Ionic Framework do this internally by preserving controller state.
Create a global controller and add it to <body> or <html> tag so that its scope can be available every time.
app.controller('GlobalController', function($scope) {
var navDetalleCtrlInstantiated = false;
$scope.$on('$stateChangeStart', function(e, toState, toParams) {
if (!navDetalleCtrlInstantiated && toState.views && toState.views.navdetalle) {
// Do the common logic on controller instantiation
// Mark so that we don't have to do the same logic again
navDetalleCtrlInstantiated = true;
}
});
});
In your view:
<body ng-controller="GlobalController">
</body>
And remove logic from your NavDetalleController.
I don't know if what you want is possible. Because ui-router always creates a new instance to the view's controller, and that makes sense cause every single view has your own scope.

ui-router loading html but not showing

I have a job state with :jobId parameter.
$stateProvider
.state('employer', {
url: "/",
abstract: true,
templateUrl: '../partials/employer/employerHome.html',
controller: 'UserHomeController',
})
.state('employer.edit', {
url: "^/edit",
templateUrl: '../partials/employer/profile.html',
controller: 'UserHomeController',
})
.state('employer.jobs', {
url: "^/jobs",
templateUrl: '../partials/employer/jobs.html',
controller: 'formController'
})
.state('job', {
parent: 'employer.jobs',
url: '/job/:jobId',
// abstract: true,
controller: 'formController',
onEnter: ['$uibModal', '$state', '$http', '$stateParams', function ($uibModal, $state, $http, $stateParams) {
console.log('Open modal');
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
backdrop: false,
windowClass: 'right fade',
keyboard: true,
controller: 'PostModalInstanceCtrl',
resolve: {
job: function () {
return $stateParams.jobId;
},
},
}).result.finally(function () {
$state.go('employer.jobs');
console.log('job modal closed')
});
}],
})
.state('system_matches', {
parent: 'job',
url: "/system_matches",
controller: 'TController',
views: {
'job#': {
templateUrl: '../partials/employer/system_matches.html',
}
}
});
when I go to the system_matches state the URL looks good: /employer#/jobs/job/1/system_matches and the HTML is loading in the console but cant see the view.
the job/:jobId state is in a modal and from there I want to go to
the system matches state that is not in a modal.
I guess I need to add a ui-view div. my question is where do I need to put the div and how is it supposed to be named with the id parameter?

ui router - abstract state inside à normal one (3 levels)

i'm trying to get work this combination of sub levels routes.
http://plnkr.co/edit/1nBzppJkB45Ljv5SRW4b?p=preview
i took a sample from ui-route on github and added a parent view (contactg).
$stateProvider
.state('contactg', {
url: '/contactg',
templateUrl: 'contactG.html',
onEnter: function () { console.log("enter contactG"); }
})
.state('contactg.contacts', {
abstract: true,
url: '/contacts',
templateUrl: 'contacts.html',
controller: function ($scope) {
$scope.contacts = [{ id: 0, name: "Alice" }, { id: 1, name: "Bob" }];
},
onEnter: function () {
console.log("enter contacts");
}
})
.state('contactg.contacts.list', {
url: '/list',
// loaded into ui-view of parent's template
templateUrl: 'contacts.list.html',
onEnter: function () {
console.log("enter contacts.list");
}
})
.state('contactg.contacts.detail', {
url: '/:id',
// loaded into ui-view of parent's template
templateUrl: 'contacts.detail.html',
controller: function ($scope, $stateParams) {
$scope.person = $scope.contacts[$stateParams.id];
},
onEnter: function () {
console.log("enter contacts.detail");
}
})
My issues is when i click on an item in contactg.contacts.list, the link generated tends to redirect me to /contacts/:id (detail) instead of /contactg/contacts/:id
is there a way to specify that ?
Thanks
Guillaume.

Resources