Angular UI Bootstrap Modal: [$injector:unpr] Unknown provider: $uibModalInstanceProvider - angularjs

This is a bit strange. When I search this issue online I see many pages of Google results and SO solutions... but none seem to work!
In a nutshell, I am trying to implement AngularUI Bootstrap Modal. I keep getting the following error:
Error: [$injector:unpr] Unknown provider: $uibModalInstanceProvider <- $uibModalInstance <- addEntryCtrl
Here is my HTML:
<nav class="navbar navbar-default">
<div class="container">
<span class="nav-col" ng-controller="navCtrl" style="text-align:right">
<a class="btn pill" ng-click="open()" aria-hidden="true">Add New</a>
</span>
</div>
</nav>
Here is my controller:
var app = angular.module('nav', ['ui.bootstrap']);
app.controller('navCtrl', ['$scope', '$uibModal', function($scope, $uibModal) {
$scope.open = function() {
var uibModalInstance = $uibModal.open({
animation: true,
templateUrl: 'addEntry/addEntry.html',
controller: 'addEntryCtrl',
});
};
}]);
And finally, here is my modal code:
var app = angular.module('addEntry', ['firebase', 'ui.bootstrap']);
app.controller('addEntryCtrl', ['$scope', '$firebaseObject', '$state', '$uibModalInstance', function($scope, $firebaseObject, $state, $uibModalInstance) {
$scope.cancel = function() {
$uibModalInstance.dismiss('cancel');
};
$uibModalInstance.close();
}]);
Solutions I've tried:
updated both Angular Bootstrap (Version: 0.14.3) and Angular (v1.4.8)
changed uibModalInstance to modalInstance
changed $uibModalInstance to modalInstance
put my addEntryCtrl inside my ModalInstance
Any thoughts? This has been driving me up the wall for almost 2 days now.
* EDIT *
I should note two things:
1) when I remove $uibModalInstance as a dependency from addEntry, my HTML form submit buttons work just fine and the form looks perfect. Even the redirect occurs correctly (upon submission). The problem remains: the modal still stays on the screen and an error is thrown that $uibModalInstance is undefined. This makes sense since I removed it as a dependency but I obviously still need the modal is close upon submission.
2) Also, I have almost identical code working in another part of my app. The only difference there is that it's working via a factory. Otherwise, the code is identical. Thus, I am confident my dependencies are all there and versions are correct. So. Freaking. Strange.
Thanks!

Answer Found! After hacking away with my friend, we discovered the answer. I wanted to post it here just in case someone else reads this.
It turns out that we had an ng-controller in our modal window that was in a div tag that wrapped the entire html form that was in the modal. Previously, this worked fine when our form was NOT in a modal (it had a separate URL) but for some reason it breaks when it is in a modal. The ng-controller was referencing the addEntryCtrl. Immediately after removing it, the form worked!

The problem was that you were specifying a (or double) controller(s) in 2 places- when opening a modal and inside a template - this is not needed. Remove ng-controller from a template and things will work as expected.Trust me,it will work.

It turns out that if you specify the controller inside the html template (with ng-controller="...") it will not resolve the $uibModalInstance. Specifying the controller from the call to $uibModal.open({controller="...", ...}) will allow it to resolve correctly.
Since you only need the dismiss() and close() methods, you can get them from $scope (named $dismiss and $close) instead, since that will resolve correctly in both ways of instantiating the controller.
var app = angular.module('addEntry', ['ui.bootstrap']);
app.controller('addEntryCtrl', ['$scope', function($scope) {
$scope.cancel = function() {
$scope.$dismiss('cancel');
};
$scope.$close();
}]);

You are trying to reference a controller that is part of a separate module. In order for this to work, you need to inject your secondary module (addEntry) into your main module (nav):
var app = angular.module('nav', ['ui.bootstrap', 'addEntry']);

As you use $uibModal.open() (see lower) and specify explicitly the controller name, you shouldn't put the directive ng-controller in the template.
That cause the error. No ng-controller in the View !
var uibModalInstance = $uibModal.open({
animation: true,
templateUrl: 'addEntry/addEntry.html',
controller: 'addEntryCtrl',
});

Related

AngularJS + RequireJS + angular-ui-grid

I am trying to use angular-ui-grid with AngularJS and RequireJS. See plunker here.
My index31.html has grid and indexController.js defines the gridOptions object. indexController is injected when needed.
When browser loads indexController.js before index31.html, it works fine (i.e. grid is displayed) but when it is the other way round, I get error: $scope.uiGrid is undefined.
How do I specify (in $stateProvider config or elsewhere) to always load indexController.js before index31.html. Or, how do I make all controllers load before the html?
The reason for this is that you require the actual code of the controller asynchronously, i.e. with an inline require:
// app.js
define(function () {
...
app.controller('IndexController', ['$scope', '$injector', function ($scope, $injector) {
// HERE!!!
require(['indexController'], function (controller) {
$injector.invoke(controller, this, { '$scope': $scope });
});
}]);
});
There is no guarantee for the order of loading with this pattern.
What can you do: Require the 'indexController' at the top:
define(['indexController'], function (indexController) {
...
app.controller('IndexController', indexController);
});
It even removes the (horrible IMO) usage of $injector!
(Sidenote: Doing this, the plunk complained about the $scope.$apply() in the last line of indexController.js; I commented it out, it really seems redundant.)
Plunk: http://plnkr.co/edit/fsyljR8FEeZdvXB3SRJP?p=preview

Inserting modalInstance service in Angular UI Bootstrap

I am making a modal box using Angular bootstrap, I follow the following posts and its plunker example
AngularJS Modal not showing up when templateUrl changes
Plunker example
http://plnkr.co/edit/p9qsqgMVOvT4yDmI7C0j?p=preview
And below is my code (controller)
.controller('apProfileDetailCtrl' , function($scope, $detailedProfileInstance , ap, newProfiles){
$scope.hostname = ap.hostname;
$scope.ip = ap.ipaddr;
})
.controller('apConfCtrl', function($scope, $q, serverProcess, printDialog, valueFactory, configLogic, $modal){
$scope.showDetailAPInfo = function(ap, size){
var detailedProfileInstance = $modal.open({
templateUrl: 'templates/profile_detail_list.html',
controller: 'apProfileDetailCtrl',
scope: $scope,
size: size,
resolve:{
ap:function(){
return ap;
},
newProfiles: function(){
return $scope.newTagsData;
},
}
});
};
(Markup)
<div class="panel-heading" style="padding:4px;">
<h3 class="panel-title">{{ ap.hostname }} (IP: {{ ap.ipaddr }})
<span style="float:right;"
class="glyphicon glyphicon-info-sign"
ng-click="showDetailAPInfo(ap,'lg')"
tooltip="{{ proLang.tooltip.currentAPInfo }}"
></span>
The above code brings me the following error
But when I remove the "$detailedProfileInstance" from the apProfileDetailCtrl controller, everything works as expected, I wonder when should I inject the service in the controller?
My thinking is, in the $modal service, the modal instance already defines the controller, therefore injecting the modal service is not allowed. Am I right?
Appreciate for any help and clarification
Add the following code After the apProfileDetailCtrl.It works for me.
apProfileDetailCtrl.$inject = ['$scope', '$detailedProfileInstance'];
or just use
.controller('apProfileDetailCtrl',['$detailedProfileInstance','$scope' , function($scope, $detailedProfileInstance , ap, newProfiles){
$scope.hostname = ap.hostname;
$scope.ip = ap.ipaddr;
}])
In the modal controller, looks like you believe that the modal instance must be injected just as you instantiated in your main controller (with the same name), which is wrong, instead if that, inject $modalInstance, that's the name of the provider, it doesn't matter how you called the variable which holds the modal object in your main controller, $modalInstance its the name of the provider you are missing
I finally figure out why I can't inject, my silly mistake for not carefully check the option api, according to the option description
modal. Accepts the "controller-as" syntax in the form 'SomeCtrl as
myctrl'; can be injected with $modalInstance
So, I try to change the controller as follow
controller('apProfileDetailCtrl' , function($scope, $modalInstance , ap, newProfiles){
$scope.hostname = ap.hostname;
$scope.ip = ap.ipaddr;
})
And problem solved, the injection is perfectly done!

Why does an Angular controller that is a function work, but a controller in a package does not?

In a recent question, I was having an issue with a simple modal dialog implemented using Angular UI for Bootstrap.
I started with this fiddle, and the person who answered came up with this result.
However, one thing immediately caught my attention!
Old Controller Implementation
var controllers = angular.module('app.controllers', []);
controllers.controller('ModalController', ['$scope', '$modal', '$log',
function ($scope, $modal, $log) {
// Overarching controller code...
}
]);
controllers.controller('ModalInstanceController', ['$scope', '$modalInstance',
function ($scope, $modalInstance, params) {
// ...Modal Instance Code...
}
]);
This code does not work with the Angular UI for Bootstrap Modal, but for some reason, this code does:
var ModalController = function($scope, $modal, $log) {
// Overarching controller code...
};
var ModalInstanceController = function($scope, $modalInstance, params) {
// Modal Instance Code...
};
...The problem being, that AngularJS code is usually modularized like the first example to avoid cluttering the global namespace.
So far none of my experiments have been able to get a modularized setup to succeed in the first place. I attempted some simple substitutions, where I would make one controller or the other be a modularized controller, in hopes that it was only one controller preventing the params from being passed between controllers; this turned out not to be the case. Implementing $scope.params = []; before declaring the $scope.open() function, and populating $scope.params in the open function similarly had no effect.
Question: In the context of the AngularUI for Bootstrap system, why does the modularized approach fail? And more importantly, how can I make it work?
Here is your fixed plnkr (http://jsfiddle.net/pEmXt/4/), it had several problems:
You defined your modules in the wrong order.
You had the ui DI in the wrong place.
Your resolve syntax was wrong.
The DI in your modal instance controller was missing an item in the list of dependencies.
The resolve method is used like this:
resolve: {
objectName: function(){
return myObject;
}
}
OK...so I recently ran into same issue and was perplexed also. I just never bothered to dig into it. A quick trip to angular-ui github repo and I found out in the issue tracker.
Angular-Ui demos are passing a function reference as controller. For a modular controller it needs to be a string
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl', /* use string for modular controller */
/* OR */
controller: ModalInstanceCtrl, /* use reference for controller as function*/
});
Issue tracker reference: https://github.com/angular-ui/bootstrap/issues/2330
Working demo from issue tracker: http://plnkr.co/edit/38vBcPalBBNMgYis4cZX?p=preview
In the first example, the module 'app.controllers' has to be added to the list of dependencies for the main app.
var app = angular.module('app', ['app.controllers']);
In the second instance the controllers are global functions and therefore are visible without being explicitly added as a dependency.

Angular Bootstrap Modal: Unknown provider: $modalInstanceProvider

I am trying to use the Angular Bootstrap Modal directive (http://angular-ui.github.io/bootstrap/) as follows, in my controller to open the modal:
function customerSearch() {
var modalInstance = $modal.open({
templateUrl: 'app/customer/customers.modal.html',
controller: 'customers.modal'
});
modalInstance.result.then(function(selectedCustomer) {
console.log(selectedCustomer);
});
}
In the modal controller:
var controllerId = 'customers.modal';
angular.module('app').controller(controllerId,
['$modalInstance', customersModal]);
function customersModal($modalInstance) {
// Modal controller stuff
}
But when I do, I get the following error:
Unknown provider: $modalInstanceProvider <- $modalInstance
If I take out $modalInstance, it works but I obviously have no reference to the modal in the calling controller..
Edit
I don't know if it is worth noting, but I am using the Controller As syntax:
<div class="container-fluid" data-ng-controller="customers.modal as vm">
Application dependencies:
var app = angular.module('app', [
// Angular modules
'ngAnimate', // animations
'ngRoute', // routing
'ngSanitize', // sanitizes html bindings (ex: sidebar.js)
// Custom modules
'common', // common functions, logger, spinner
'common.bootstrap', // bootstrap dialog wrapper functions
// 3rd Party Modules
'ui.bootstrap', // ui-bootstrap (ex: carousel, pagination, dialog)
'breeze.directives', // breeze validation directive (zValidate)
]);
I've created a plunker which is showing the problem here: http://plnkr.co/edit/u8MSSegOnUQgsA36SMhg?p=preview
The problem was that you were specifying a controller in 2 places - when opening a modal and inside a template - this is not needed. Remove ng-controller from a template and things will work as expected:
http://plnkr.co/edit/khySg1gJjqz1Qv4g4cS5?p=preview
try this syntax first
angular.module('app').controller('customers.modal',
['$modalInstance', function($modalInstance){
// Modal controller stuff
}]);
I think it get messed up if you use bracket notation and declare the controller outside.
$modalInstance is the modalInstance you create there
var modalInstance = $modal.open({
templateUrl: 'app/customer/customers.modal.html',
controller: 'customers.modal'
});
it's really the same object. It get injected back in the controller but it's not a service/factory. So it doesn't have a Provider.
This is a tricky part in the lib. Feel free to ask to the original authors of ui-bootstrap. They have been helpful in explaining that.

Angular $routeParams is blank

I have a really simple Angular app that I've distilled to the following:
var napp = angular.module('Napp',['ngResource']);
var CompanyCtrl = function($scope, $routeParams, $location, $resource) {
console.log($routeParams);
};
napp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/company/edit/:id',
{templateUrl: '/partials/edit', controller: 'CompanyCtrl'}
);
}]);
and the HTML:
<div ng-controller="CompanyCtrl"></div>
When I log $routeParams, it comes up blank. When I use .otherwise(), it will load whatever I've specified there. Any idea what I'm missing?
You have a couple of errors:
You've specified the controller in two places, both in the view (<div ng-controller="CompanyCtrl"></div>) and in $routeProvider (.when('/company/edit/:id', {templateUrl: '/partials/edit', controller: 'CompanyCtrl'}). I'd remove the one in the view.
You have to register the controller in the module when specifying it in the $routeProvider (you should really do this anyway, it's better to avoid global controllers). Do napp.controller('CompanyCtrl', function ... instead of var CompanyCtrl = function ....
You need to specify a ng-view when you're using the $route service (not sure if you're doing this or not)
The new code:
var napp = angular.module('Napp', ['ngResource']);
napp.controller('CompanyCtrl', function ($scope, $routeParams, $location, $resource) {
console.log($routeParams);
});
napp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/company/edit/:id',
{templateUrl: '/partials/edit', controller: 'CompanyCtrl'}
);
}]);
The template (/parials/edit)
<div> ... </div>
And the app (index.html or something)
... <body> <div ng-view></div> </body>
I've created a working plunker example: http://plnkr.co/edit/PQXke2d1IEJfh2BKNE23?p=preview
First of all try this with
$locationProvider.html5Mode(true);
That should fix your starting code. Then adjust your code to support non-pushState browsers.
Hope this helps!
Not sure if this helps, but I just came across this issue myself, and found that I couldn't log the route params until I had something bound to them.
So,
Router:
var myApp = angular.module('myApp', []);
myApp.config(function($routeProvider){
$routeProvider.when('/projects/:id',
{templateUrl: '/views/projects/show.html', controller: 'ProjectCtrl'}
);
});
Controller:
myApp.controller('ProjectCtrl', function($scope, $routeParams){
$scope.id = $routeParams.id;
console.log('test');
});
View:
<h1>{{ id }}</h1>
When I removed the '{{id}}' from the view, nothing was logged and $routeParams was empty, at least at the time of the controller's instantiation. As some of the answers above have pointed to, the route params are passed in asynchronously, so a controller with no bindings to that property won't execute. So, not sure exactly what you've distilled your snippet down from, but hope this helps!
This may happen (not in the OP's case) if you're using ui-router instead of ngRoute.
If that's the case, use $stateParams instead of $routeParams.
https://stackoverflow.com/a/26946824/995229
Of course it will be blank. RouteParams is loaded asynchronously so you need to wait for it to get the params. Put this in your controller:
$scope.$on('$routeChangeSuccess', function() {
console.log($routeParams);
});
It works for me http://plunker.co/edit/ziLG1cZg8D8cYoiDcWRg?p=preview
But you have some errors in your code:
Your don't seem to have a ngView in your code. The $routeProvider uses the ngView to know where it should insert the template's content. So you need it somewhere in your page.
You're specifying your CompanyCtrl in two places. You should specify it either in the $routeProvider, or in you template using ng-controller. I like specifying it in the template, but that's just personal preference.
Although not an error, you're specifying your CompanyCtrl in the global scope, instead of registering it on your Napp module using Napp.controller(name, fn).
Hope this helps!
You can always go on #angularjs irc channel on freenode: there's always active people ready to help
Could it be that your templateUrl points to an invalid template?
When you change the templateUrl to an unexisting file, you will notice that the $routeParams will no longer be populated (because AngularJS detects an error when resolving the template).
I have created a working plnkr with your code for your convenience that you can just copy and paste to get your application working:
http://plnkr.co/edit/Yabp4c9zmDGQsUOa2epZ?p=preview
As soon as you click the link in the example, you will see the router in action.
Hope that helps!

Resources