Nested views inside the modal are not displayed. (ui-router and ui-bootstrap)
I am having a problem creating a modality that is responsive to application state. From the angular wi-router wiki I have seen how to achieve my goal, but my code is not working and I do not understand why for the following reasons:
- when running app router / sign / in module
-
I see the following output on my console
=> "about.sign"
=> "about.sign.in"
-
2) means both router and shooting! In other words, the modal should be open
about.sign
, and the template fromabout.sign.in
should be inserted into its parent template, more precisely on the tag.
I've tried both technologies. Named ui-views and anonymous but none worked.
var app = angular.module('app.auth',
[
'ui.bootstrap',
'ui.router'
]);
app.config(function($stateProvider){
$stateProvider
.state('about',{
url: '/',
views:{
'main': {
templateUrl: 'about/about.tpl.html'
}
}
})
.state('about.sign',{
url: '',
onEnter: function($stateParams, $state, $modal){
console.log('about.sign')
var modalInstance = $modal.open({
template:'<h1>Modal</h1><div ui-view="bar-view"></div>',
size: 'sm',
});
}
})
.state('about.sign.in',{
url:'sign/in',
onEnter: function($stateParams, $state, $modal){
console.log('about.sign.in')
},
views: {
'bar-view': {
template: 'Sign in #1'
}
}
})
.state('about.sign.up',{
url:'sign/up',
onEnter: function($stateParams, $state, $modal){
console.log('about.sign.in')
},
views: {
'bar-view': {
template: 'Sign up #2'
}
}
})
}); //end of app.config
Am I doing something wrong with these nested views?
source to share
I ran into this too. It turns out that you need to use "parent" instead of dot notation.
Here is the plunker
angular.module('app', ['ui.router', 'ui.bootstrap'])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('view', {
url: '',
template: '<button class="btn btn-default" ui-sref="modal"> Modal</button> <ui-view />',
controller: function($scope) {
}
})
.state('modal', {
//abstract: true,
parent: 'view',
url: '/modal',
onEnter: ['$modal', '$state', function($modal, $state) {
console.log('Open modal');
$modal.open({
template: '<button class="btn btn-danger" ui-sref="signin"> sign-in </button> <button ui-sref="signout" class="btn btn-success"> sign-out </button> <div ui-view="modal"></div>',
backdrop: false,
windowClass: 'right fade'
}).result.finally(function() {
$state.go('list');
});
}]
})
.state('signin', {
url: '/signin',
parent: 'modal',
views: {
'modal@': {
template: '<p>sign-in</p>'
}
}
})
.state('signout', {
url: '/signout',
parent: 'modal',
views: {
'modal@': {
template: '<p>sign-out</p>'
}
}
})
}]);
source to share
I think the accepted answer is good. (The trick was naming the view modal@
instead modal
- see the docs for an explanation.) But I thought I'd post a more general solution in case it helps others who come to look here with similar problems. (It took me a while to figure this out.)
One notable difference with my approach is that I chose to create a controller to run the modal instead of using a hook onEnter
(although every other example I've seen has used onEnter
) because it onEnter
doesn't give you scope access. This way, controllers for both modal and child states can inherit from the same parent scope.
An interesting caveat: named views for child states cannot reference the parent state. The modal essentially creates its own state, so in my example it ui-view="modal"
doesn't exist in the context of the state launch_modal
- it exists in the root unnamed template (hence the child view should be modal@
, not modal@launch_modal
).
registerRoutes: function($stateProvider) {
var modal_instance = null;
return $stateProvider.state('launch_modal', {
url: '/',
template: '',
controller: [
'$uibModal', '$state', '$scope', function($modal, $state, $scope) {
// init scope variables that you want the modal and child states to inherit
$scope.modal = {
title: '',
};
// launch the dialog
modal_instance = $modal.open({
template: '<div ui-view="modal">',
controller: 'MyModule.Controllers.DialogController',
scope: $scope
});
// make sure we leave the state when the dialog closes
return modal_instance.result['finally'](function() {
modal_instance = null;
if ($state.includes('launch_modal')) {
return $state.go('^');
}
});
}
],
onExit: function() {
// make sure the dialog is closed when we leave the state
if (modal_instance != null) {
modal_instance.close();
}
}
}).state('launch_modal.child1', {
url: '',
views: {
// note: doing `modal@launch_modal` won't work!
'modal@': {
templateUrl: "path/to/child1/template",
controller: "MyModule.Controllers.Child1ViewController"
}
}
});
}
Hope this helps some people!
source to share