Angular UI Bootstrap‘s $modal service has a
$scope
argument that lets you assign it whatever $scope you want, so if you wanted your
modal’s controller to use the same $scope as your parent controller you could do that.
But what if you don’t want to use $scope? What if you’re using controllerAs
and you want to keep your code all scope-less, neat, and tidy?
Luckily there’s an alternative. You can send your data to the modal as resolves. Resolves first appeared with ngRoute, as a way to make sure information was available to a route’s controller before the view was initiated. It prevents elements shifting around in your view as data would otherwise be loaded after the view shows up. It also keeps common data-loading tasks out of your controller.
Let’s look at an example. You’ve got a list of people in a table. Each has a name, and a delete button. When the user clicks the delete button a modal will come up confirming the delete.
We’ll pass the list of people and the person to delete into the modal’s controller using
the resolve
argument. Each property in the resolve object can be a string or function. If
it’s a string, Angular will look for a service with that name and inject it into the modal
controller. If it’s a function you can either return the value directly or return a promise if
you’re fetching the data asynchronously.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
Main.$inject
= ['$modal'];
function Main($modal) {
var vm
= this;
vm.deleteModal
= deleteModal;
vm.people
= [
'Fred',
'Jim',
'Bob'
];
function deleteModal(person) {
$modal.open({
templateUrl:
'modal.html',
controller:
['$modalInstance', 'people',
'person', DeleteModalCtrl],
controllerAs:
'vm',
resolve:
{
people:
function ()
{ return vm.people },
person:
function() { return person;
}
}
});
}
|
And just for clarity here’s our view, with the people ng-repeat
ed in a table:
1
2
3
4
5
6
7
8
|
<table class="table">
<tr ng-repeat="p in vm.people">
<td>{{
p }}</td>
<td>
<button type="button" class="btn
btn-sm btn-primary" ng-click="vm.deleteModal(p)">Delete</button>
</td>
</tr>
</table>
|
Alright, there’s our people and our person; person
is passed in to the
deleteModal
function when the user clicks a delete button, deleteModal
in turn
passes people
and person
to DeleteModalCtrl
as injectables.
Our modal controller can look like this:
1
2
3
4
5
6
7
8
9
10
11
|
function DeleteModalCtrl($modalInstance, people,
person) {
var vm
= this;
vm.person
= person;
vm.deletePerson =
deletePerson;
function deletePerson()
{
people.splice(people.indexOf(person),
1);
$modalInstance.close();
}
}
|
The injectables get passed in as arguments and we don’t need to use $scope at all, hooray! Finally, here is an example plunker showing how this all works together: