I have spent some time now looking into a generic way of controlling a modal window with AngularJS
and none of the proposed options are anywhere near 'good' solution.
I found this demo, however the downside of that is you have to manually manage and store the state of the modal and cross-scope update it:
scope.$parent[attrs.visible] = true;
Also if you had to add more functionality like actually adding an item with a popup that would involve even more ugly code on the parent page scope.
This is the official guide on how to use modals with ui router.
This however is using ui.bootstrap.modal
My question is, is there any simple and elegant solution to what is quite frankly a very simple problem...
Something like this for example:
.state('popup', {
url: '/item/add/',
views: {
'popupView': {
templateUrl: "/myPopup.html",
controller: "myPopupController"
}
},
type: 'modal'
})
And things like close, redirect, submit, all are handled in the myPopupController
.
I am not seeking an explanation of why the examples are above are as they are, or how I should be using them. I am simply looking if anyone has come up with a better solution.
I've been working for some time now on a modal/dialog plugin for ui-router (utilising it and ui-router-extras).
I'm in the process of porting some in house code to an open source project, and it'd be a huge benefit (certainly so for me) if you would be open to giving it a try.
We are currently using the in house version in our production application and it is working quite well. My goal is to make the open source version even better in terms of consumer API and performance.
var app = angular.module('mod', ['angular.ui.router.modal', /** ui-router + ui-router-extras **/]);
app.config(function ($uiRouterModalProvider) {
$uiRouterModalProvider.config({
viewName: 'my_modal_view_name',
templateUrl: '/path/to/my_modal_wrapper.html',
rootState: 'name_of_my_apps_root_state',
controller: 'my_modal_wrapper_controller',
resolve: {
common: function ($http) {
return $http.get(apiUrl + '/common_modal_settings');
}
}
});
});
Let's go through the different parts:
This is the name of the ui-view
that your modal template will live in. It is required that you have a container in your page with the ui-view
attribute pointing to a view of $uiRouterModalProvider.viewName
that lives beside your regular ui-view
for your regular content (example will be shown later).
The package provides a directive that does this for you
This is the base of all of your modals. Say you wanted a container with certain properties, and a $scope
that is independent of the inner contents of the modal at any given point in time.
This is the name of the root state in your application. It is important that this matches that of the state that holds your root ui-view
element and the modal ui-view
element.
The name of your common modal controller. Can also be a function (though I would always recommend a named controller that can be unit tested in isolation).
The common resolve block for each modal. This is interdependent of each modal states own resolve block. The API and behaviour regarding resolves is still in flux.
Now that the base behaviour is configured, this is how you would register a modal state:
.modalState('home.mySuperModal', {
url: '/my-super-modal',
templateUrl: 'superModal.html',
controller: 'SuperModalController'
});
The .modalState
function will register a state and reference the common settings set in the modalProvider and convert the given state definition into the final state object, looking like so:
.state('home.mySuperModal', {
url: '/my-super-modal',
views: {
'modal_view_name@root_state': {
templateUrl: 'modal_wrapper.html',
controller: 'ModalWrapperController'
}
},
$$originalState: {
templateUrl: 'superModal.html',
controller: 'SuperModalController'
}
});
<!-- The outermost ui-view element -->
<html>
<body ng-app="app">
<div ui-view></div>
</body>
</html>
<!-- The content for the root state of your application {living inside the outermost ui-view directive} -->
<div>
<ui-view></ui-view>
<ui-modal-view></ui-modal-view>
</div>
Now the container for our modal wrapper is set up. But what about the inner contents?
This is where another directive comes into play; uiModalFill
. This needs to be present in your wrapping modal template. As such:
<!-- wrapping modal template -->
<div id="modal_wrapper">
<h1>Some heading. I'm always present!</h1>
<hr>
<ui-modal-fill></ui-modal-fill>
</div>
Some final notes before (if) you feel like giving this a go:
resolve
property and the way a $state.resolve lives together with the common modal.resolve. So, if I haven't managed to scare you off from giving this a go - head on over to GitHub and grab angular-ui-router-modal and give it a go. I'm sort of always available on GitHub and/or on SO if you need any help.
Or if you would just like to pester me about writing some documentation. I would understand that, fully.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With