In $stateProvider#state(), I define it as follows for Bootrtrap-ui modal using UI-Router. reference
var state = {
name: 'modala',
parent: 'home',
onEnter: function($modal, $state) {
modalInstance = $modal.open({
templateUrl: 'modala.html',
controller: 'modalaCtrl',
controllerAs: 'modal'
});
modalInstance.result['finaly'](function() {
modalInstance = null;
if ($state.$current.name === 'modala') {
$state.go('^');
}
});
},
onExit: function() {
if (modalInstance) {
modalInstance.close();
}
}
};
I want to use 'modala' any place other than home.
I do not want to create a lot of definitions of 'modala'
.
Is there a method to accept it, and to set what is necessary in parent?
add explanation
No good solutions
Don't set parent in modal state.
result: when open modal window, parent isn't displayed.
pattern 1 example
modal state name is ${parent.name}.modal format.
result: It's work. but, About one modal window, it is necessary to define many states. and, It is necessary to add a state whenever I add an parent who call modal.
pattern 2 exapmle
define the modal state every parent
result:same as pattern 2.
pattern 3 exapmle
There is updated plunker (the second try from the question)
What we would see in action, is different use of decorator, as in detail described in my previous post
So, firstly, let's have few states e.g. 'home', 'page1', 'page2' ... and we would like for all of them introduce the child state - with modal functionality. That modal features are expected to be the same across all child states - but these will belong to different parents.
To make it happen we can use state definition like this:
.config(function($stateProvider) {
// we just define empty child state for each existing parent
$stateProvider.state('home.generalModal', {});
$stateProvider.state('page1.generalModal', {});
$stateProvider.state('page2.generalModal', {});
})
And that could be enough, if we will hijack the decorator this way:
.config(['$stateProvider',
function($stateProvider) {
var endsWith = function(stringToBesearched, valueToBeFound) {
return stringToBesearched.slice(-valueToBeFound.length) === valueToBeFound;
}
$stateProvider.decorator('data', function (state, dataBuilder) {
// this is original, by configuration created parent
var data = dataBuilder(state);
// we can define where we do not want to change that default, configured
// in our case, we extend every state which ends with .generalModal
var skipState = !endsWith(state.name, ".generalModal")
// and return taht default
if(skipState)
{
return data;
}
// the modal instance per this state instance
var modalInstance;
// definition of the onEnter
var onEnter = function($modal, $state) {
console.log("Entering state: " + $state.current.name)
modalInstance = $modal.open({
templateUrl:'modal.html',
controller: 'modalCtrl',
controllerAs: 'modalCtrl'
});
modalInstance.result['finally'](function() {
modalInstance = null;
if(endsWith($state.$current.name, ".generalModal")) {
$state.go('^');
}
});
};
// definition of the onExit
var onExit = function($state) {
console.log("Exiting state: " + $state.current.name)
if (modalInstance) {
modalInstance.close();
}
};
// extend state with both of them
state.self.onEnter = onEnter;
state.self.onExit = onExit;
return data;
});
}])
We extended every child state which name endsWith ".generalModal"
with onExit
and onEnter
. That's all. At one place...
Check it in action here
All you have to do is add the property parent: modala
to all child states that you define in order to set a parent state.
There is a solution built inside of the UI-Router, called state decorator
decorator(name, func)
This way, we can create an aspect, which will be injected into any state we want later. That aspect, could drive some common, global setting. E.g. parent
or views
...
Check an example here: How to decorate current state resolve function in UI-Router? Current function isn't invoked, small cite:
Allows you to extend (carefully) or override (at your own peril) the stateBuilder object used internally by $stateProvider. This can be used to add custom functionality to ui-router, for example inferring templateUrl based on the state name...
There is a working example for our scenario
What we would need, is the decorator definition, like this:
.config(['$stateProvider',
function($stateProvider) {
$stateProvider.decorator('parent', function (state, parent) {
// this is original, by configuration created parent
var result = parent(state);
// we can define where we do not want to change that default, configured
var skipState = state.name === "home"
|| state.name === "modala"
// child already has that in parent
|| state.name.indexOf(".") > 0 ;
// and return taht default
if(skipState)
{
return result;
}
// FINALLY - HERE
// we want to change parent, or even introduce new
state.parent = 'modala';
// and rebuild it
result = parent(state);
// new parent in place
return result;
});
}])
Check that in action here
I was wanting the solution to this too. I eventually worked it out.
See my stackoverflow answer / question