Modal Window Issue (Unknown Provider: ModalInstanceProvider)

edward.louis picture edward.louis · Oct 6, 2013 · Viewed 36k times · Source

New to AngularJS and can't seem to find out what this error means. I've found a few others with the same error but it seems their issues don't correlate to mine.

Unknown provider: $modalProvider <- $modal error with AngularJS (Seems I've got the latest ui-bootstrap version)

And all of the others seem to be having scope issues with a modal, yet I can't seem to get the modal to begin with so I'm thinking these aren't related. Please tell me if I'm wrong and how that's the case:

Scope issue in AngularJS using AngularUI Bootstrap Modal

Scope issues with Angular UI modal

I grabbed the ui-bootstrap-tpls-0.6.0.min.js script from here: https://github.com/angular-ui/bootstrap/tree/gh-pages#build-files and I even tried adding the ui-bootstrap-0.6.0.min.js script as well thinking it was possibly needed. Though if I read it properly, it seems if I chose the ui-bootstrap-0.6.0.min.js script I'd need to also grab all of the templates here https://github.com/angular-ui/bootstrap/tree/master/template Which seems to be the case if I use only that script based on the errors:

Error: Failed to load template: template/modal/window.html
Error: Failed to load template: template/modal/backdrop.html

I've created a plunker with everything for simplicity of explaining structure etc and pasting in all the code here.

http://plnkr.co/edit/yg3G8uKsaHNnfj4yNnJs?p=preview

The error (which you can see by testing the code on plunker with the console open) is the following:

Error: Unknown provider: $modalInstanceProvider <- $modalInstance
     at Error (<anonymous>)
     at http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:30:24
     at Object.c [as get] (http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:27:310)
     at http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:30:109
     at c (http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:27:310)
     at d (http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:27:444)
     at Object.instantiate (http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:29:80)
     at http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:53:80
     at http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:44:136
     at m (http://run.plnkr.co/8OIh0YtLn1dg9OvR/angular.min.js:6:494)

If anyone can give any insight as to what I may be doing wrong here. It doesn't seem like a scope issue. More like a setup issue or possibly the way I'm manually bootstrapping the app?

Answer

J. Bruni picture J. Bruni · Oct 6, 2013

It seems you are not injecting the $modal service as a dependency.

How to "inject a service"?

Consider the function you are trying to use the service... you should declare it like this:

['$modal', function($modal) {
    // $modal has been injected here, you can use it
}]


Edit:

I've studied you Plunk now... it is overcomplicating simple things, and reveals some miscomprehensions about AngularJS concepts (controller, scope, etc.)

Also, it was using Bootstrap's 3 CSS - which is not compatible with AngularJS Bootstrap currently. I've changed the CSS link to Bootstrap 2.

See how it can be much much more simple and effective: http://plnkr.co/edit/YFuAA5B65NZggd6fxjCh?p=preview

I'd recommend studying this document carefully, from start to finish: http://docs.angularjs.org/guide/concepts

This video is also very very good, but it does not provide deeper insight into the concepts: http://weblogs.asp.net/dwahlin/archive/2013/04/12/video-tutorial-angularjs-fundamentals-in-60-ish-minutes.aspx


Basically, the error message was telling that you were trying to inject a service into something (the "ModalController", in your case) - but this service was not found.

"How I was trying to inject?" - you may ask. The answer is: every parameter you require in a Controller function is a "dependency" to be "injected" - and AngularJS "injector" service performs this task. This is how "$scope" parameter magically receives a "scope" - it is the injector working behind the scenes.

In you ModalController, the injector was trying to satisfy both the "$modalInstance" and the "items" dependencies (remove the "$modalInstance" parameter - the error message will change to "itemsProvider not found")...

If you want to receive dependencies like this, through the "magical" work of the injector, you need to create/declare services with these names... (or properly use the "resolve" attribute as you were trying to do) ...

...but this is not needed in this case at all. You just want access to "items", and return a selected item. You were also trying to close/dismiss the modal programatically.

You could resolve dependencies through the "resolve" attribute, but why complicate so much what can be achieved with simplicity? Just use the "scope" attribute instead, and provide the scope to the modal - it will have access to its properties. The modal also automatically adds "$close" and "$dismiss" functions to the scope, so you can easily use these functions.

You were trying to pass attributes from the main scope to the modal scope by injecting them as services into the modal controller! :-) You were trying to inject the own modal instance into its controller!!!

So, your main issue is related to the $injector - it worths studying what is this inject thing all about - it is well explained in the documented I linked above.

"Inject a service" is not as simple as "passing a variable to a function". You were almost there through the "resolve" attribute, but as I've said - really not needed for this simple case.

I've created another Plunker without using "scope", and keeping the "resolve"... it is not possible to inject the "modalInstance" as we do with "items":

'$modalInstance': function() { return modalInstance; }

...because it is still undefined at this moment... we could workaround by just calling $scope.$close in the ModalController (and not injecting the modal)...

...or, like I did, injecting it through a function... very crazy, but it works:

http://plnkr.co/edit/9AhH6YFBUmhYoUDhvnhQ?p=preview

...I would never do like this... it is just for learning purposes!


At last but not least: by adding ng-controller in the template file, you are requiring the ModalController twice... you already stated it in the modal configuration. But through the modal configuration, you can have the dependency injection through the resolver - while through the template you don't have the "resolve" thing applied.

Update:

As pointed in the comments by Mahery, $modalInstance is made available for injection in the controller by AngularUI Bootstrap implementation. So, we don't need any effort ro "resolve" or make it available somehow.

Here is the updated Plunker: http://plnkr.co/edit/BMfaFAWibHphDlZAkZex?p=preview

Indeed, the error was happening mainly due to the "ng-controller" atttribute in the template. The controller created through this way does not receive the "AngularUI treatment". Only the controller specified in the modal options receives the "treatment" where $modalInstance is provided...