diff --git a/src/modal/docs/readme.md b/src/modal/docs/readme.md index a889bd2640..d4986a49f4 100644 --- a/src/modal/docs/readme.md +++ b/src/modal/docs/readme.md @@ -129,3 +129,7 @@ Events fired: * `modal.closing` - This event is broadcast to the modal scope before the modal closes. If the listener calls preventDefault() on the event, then the modal will remain open. Also, the `$close` and `$dismiss` methods returns true if the event was executed. This event also includes a parameter for the result/reason and a boolean that indicates whether the modal is being closed (true) or dismissed. + +##### UI Router resolves + +If one wants to have the modal resolve using [UI Router's](https://github.com/angular-ui/ui-router) pre-1.0 resolve mechanism, one can call `$uibResolve.setResolver('$resolve')` in the configuration phase of the application. One can also provide a custom resolver as well, as long as the signature conforms to UI Router's [$resolve](http://angular-ui.github.io/ui-router/site/#/api/ui.router.util.$resolve). diff --git a/src/modal/modal.js b/src/modal/modal.js index c846cf9bf0..7b740fa1ca 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -54,6 +54,52 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) }; }) +/** + * Pluggable resolve mechanism for the modal resolve resolution + * Supports UI Router's $resolve service + */ + .provider('$uibResolve', function() { + var resolve = this; + this.resolver = null; + + this.setResolver = function(resolver) { + this.resolver = resolver; + }; + + this.$get = ['$injector', '$q', function($injector, $q) { + var resolver = resolve.resolver ? $injector.get(resolve.resolver) : null; + return { + resolve: function(invocables, locals, parent, self) { + if (resolver) { + return resolver.resolve(invocables, locals, parent, self); + } + + var promises = []; + + angular.forEach(invocables, function(value) { + if (angular.isFunction(value) || angular.isArray(value)) { + promises.push($q.resolve($injector.invoke(value))); + } else if (angular.isString(value)) { + promises.push($q.resolve($injector.get(value))); + } else { + promises.push($q.resolve(value)); + } + }); + + return $q.all(promises).then(function(resolves) { + var resolveObj = {}; + var resolveIter = 0; + angular.forEach(invocables, function(value, key) { + resolveObj[key] = resolves[resolveIter++]; + }); + + return resolveObj; + }); + } + }; + }]; + }) + /** * A helper directive for the $modal service. It creates a backdrop element. */ @@ -542,8 +588,8 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) backdrop: true, //can also be false or 'static' keyboard: true }, - $get: ['$injector', '$rootScope', '$q', '$document', '$templateRequest', '$controller', '$uibModalStack', - function ($injector, $rootScope, $q, $document, $templateRequest, $controller, $modalStack) { + $get: ['$rootScope', '$q', '$document', '$templateRequest', '$controller', '$uibResolve', '$uibModalStack', + function ($rootScope, $q, $document, $templateRequest, $controller, $uibResolve, $modalStack) { var $modal = {}; function getTemplatePromise(options) { @@ -552,20 +598,6 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) options.templateUrl() : options.templateUrl); } - function getResolvePromises(resolves) { - var promisesArr = []; - angular.forEach(resolves, function(value) { - if (angular.isFunction(value) || angular.isArray(value)) { - promisesArr.push($q.when($injector.invoke(value))); - } else if (angular.isString(value)) { - promisesArr.push($q.when($injector.get(value))); - } else { - promisesArr.push($q.when(value)); - } - }); - return promisesArr; - } - var promiseChain = null; $modal.getPromiseChain = function() { return promiseChain; @@ -602,7 +634,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) } var templateAndResolvePromise = - $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); + $q.all([getTemplatePromise(modalOptions), $uibResolve.resolve(modalOptions.resolve, {}, null, null)]); function resolveWithTemplate() { return templateAndResolvePromise; @@ -629,14 +661,13 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) }); var ctrlInstance, ctrlLocals = {}; - var resolveIter = 1; //controllers if (modalOptions.controller) { ctrlLocals.$scope = modalScope; ctrlLocals.$uibModalInstance = modalInstance; - angular.forEach(modalOptions.resolve, function(value, key) { - ctrlLocals[key] = tplAndVars[resolveIter++]; + angular.forEach(tplAndVars[1], function(value, key) { + ctrlLocals[key] = value; }); ctrlInstance = $controller(modalOptions.controller, ctrlLocals); diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index d6903471ac..9ed27b3ca6 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -1,3 +1,51 @@ +describe('$uibResolve', function() { + beforeEach(module('ui.bootstrap.modal')); + + it('should resolve invocables and return promise with object of resolutions', function() { + module(function($provide) { + $provide.factory('bar', function() { + return 'bar'; + }); + }); + + inject(function($q, $rootScope, $uibResolve) { + $uibResolve.resolve({ + foo: 'bar', + bar: $q.resolve('baz'), + baz: function() { + return 'boo'; + } + }).then(function(resolves) { + expect(resolves).toEqual({ + foo: 'bar', + bar: 'baz', + baz: 'boo' + }); + }); + + $rootScope.$digest(); + }); + }); + + describe('with custom resolver', function() { + beforeEach(module(function($provide, $uibResolveProvider) { + $provide.factory('$resolve', function() { + return { + resolve: jasmine.createSpy() + }; + }); + + $uibResolveProvider.setResolver('$resolve'); + })); + + it('should call $resolve.resolve', inject(function($uibResolve, $resolve) { + $uibResolve.resolve({foo: 'bar'}, {}, null, null); + + expect($resolve.resolve).toHaveBeenCalledWith({foo: 'bar'}, {}, null, null); + })); + }); +}); + describe('$uibModal', function () { var $animate, $controllerProvider, $rootScope, $document, $compile, $templateCache, $timeout, $q; var $uibModal, $uibModalStack, $uibModalProvider; @@ -1430,3 +1478,4 @@ describe('$uibModal', function () { }); }); }); +