Reputation: 3853
I'm having trouble creating a modal that responds to the application state. From angular ui-router wiki I saw how to achieve my goal but my code is not working and I'm not figuring out why for the following reasons:
I can see the following output at my console
=> "about.sign"
=> "about.sign.in"
The 2) means that both routers and firing!
In other words the modal should be opened about.sign
and the template from about.sign.in
state should be inserted on it's parent template, more precisely on tag.
I tried both techniques. 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 those nested views??
Upvotes: 3
Views: 5161
Reputation: 5382
I think the accepted answer is a good one. (The trick was naming the view with modal@
instead of just modal
- see the docs for an explanation.) But I thought I'd post a more general solution, in case that helps others who come looking here with similar problems. (It took me quite a while to figure this all out.)
One notable difference with my approach is that I decided to create a controller to launch the modal, rather than using the onEnter
hook (even though every other example I saw used onEnter
), because onEnter
doesn't give you access to the scope. This way, the controllers both for the modal and for the child states can inherit from the same parent scope.
Interesting caveat: the named views for the child states cannot reference the parent state. The modal essentially creates its own state, so in my example, ui-view="modal"
doesn't exist within the context of the launch_modal
state - it exists in the root unnamed template (hence why the child's view must 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 that helps some people!
Upvotes: 3
Reputation: 22705
I bumped into this one as well. It turns out 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>'
}
}
})
}]);
Upvotes: 8