Ui-router modal injection error on minification - angularjs

I'm using ui-router and ui-bootstrap/modal
I've got a sale screen split in 2 so I have a left side with the cart and the right one can have the catalog, an edit product or a payment section.
I need to have a modal in all states so I've created a function to add in some ui-router states.
Here's the function:
var modalSaleDelete = ['$state', '$modal',
function($state, $modal) {
$modal.open({
templateUrl: 'views/sale/delete.html',
resolve: {
parentScope: function($rootScope) {
return $rootScope.parentScope;
}
},
controller: function($scope, parentScope) {
$scope.delete = function() {
// TODO: change the way this is called
parentScope.resetOrder();
parentScope = null;
$scope.$close('cancel');
};
$scope.cancel = function() {
parentScope = null;
$scope.$dismiss('cancel');
};
}
}).result.then(function() {
return $state.transitionTo($state.$current.parent);
}, function() {
return $state.transitionTo($state.$current.parent);
});
}
];
Then I put that in every state:
.state('sale.new.catalog.delete', {
url: '/delete',
onEnter: modalSaleDelete
})
It works great on development but when I minify this I get an error:
Error: [$injector:unpr] Unknown provider: aProvider <- a
http://errors.angularjs.org/1.2.24/$injector/unpr?p0=aProvider%20%3C-%20a
at http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:3:26944
at http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:11462
at Object.c [as get] (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:10723)
at http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:11557
at c (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:10723)
at Object.d [as invoke] (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:11008)
at http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:8:20044
at Object.f [as forEach] (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:3:27387)
at j (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:8:19961)
at Object.k.open (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:8:20414)
I debugged that and aProvider should be '$state'.
Any idea on how to make that work?

You need to annotate EVERY injection for minification to work. Or, if you are using an angular-aware minifier, it probably doesn't understand which functions are injected by UI-Router and which are standard functions.
var modalSaleDelete = ['$state', '$modal',
function($state, $modal) {
$modal.open({
templateUrl: 'views/sale/delete.html',
resolve: {
parentScope: [ '$rootScope', function($rootScope) {
return $rootScope.parentScope;
}]
},
controller: [ '$scope', 'parentScope', function($scope, parentScope) {
$scope.delete = function() {
// TODO: change the way this is called
parentScope.resetOrder();
parentScope = null;
$scope.$close('cancel');
};
$scope.cancel = function() {
parentScope = null;
$scope.$dismiss('cancel');
};
}]
}).result.then(function() {
return $state.transitionTo($state.$current.parent);
}, function() {
return $state.transitionTo($state.$current.parent);
});
}
];

Try injecting them manually by creating an inject property. Do you have a jsfiddle or plunker set up?
modalSaleDelete.$inject = ['$state', '$modal'];

Well, I've figured it out. I don't see why but the problem was in resolve.
I solved it injecting '$state' in resolve though it's not needed.
When debugging I just saw the aProvider was trying to be injected in there.
var modalSaleDelete = ['$rootScope', '$state', '$modal',
function($rootScope, $state, $modal) {
$modal.open({
templateUrl: 'views/sale/delete.html',
resolve: {
parentScope: ['$state', '$rootScope', function($state, $rootScope) {
return $rootScope.parentScope;
}]
},
controller: ['$scope', '$state', 'parentScope', function($scope, $state, parentScope) {
$scope.delete = function() {
// TODO: change the way this is called
parentScope.resetOrder();
parentScope = null;
$scope.$close();
};
$scope.cancel = function() {
parentScope = null;
$scope.$dismiss();
};
}]
}).result.then(function() {
// close
return $state.transitionTo($state.current.name.replace('.delete', ''));
}, function() {
// dismiss
return $state.transitionTo($state.current.name.replace('.delete', ''));
});
}
];

Related

Karma test failed when I inject a ui-router resolve in a controller

I've been trying to test my controller:
app.js
angular
.module('MyModule', [
'ui.router'
]);
angular
.module('MyModule')
.config(configFn);
configFn.$inject = ['$stateProvider'];
function configFn($stateProvider){
$stateProvider
.state('myState',{
url:'state',
views: {
'main' : {
templateUrl: 'src/views/view.html',
controller: 'MyCtrl',
controllerAs: 'ctrl',
resolve: {
DataResolve: ['MyService', function(MyService){
return MyService.getData();
}]
}
}
}
});
controller.js
angular
.module('MyModule')
.controller('MyCtrl', Controller);
Controller.$inject = ['DataResolve'];
/* #ngInject */
function Controller(DataResolve) {
var vm = this;
vm.data = DataResolve;
}
My spec
controller_spec.js
describe('Controller', function(){
beforeEach(module('MyModule'));
beforeEach(inject(function($controller){
this.myCtrl = $controller('MyCtrl');
}));
it('Controller should be defined', function() {
expect(this.myCtrl).toBeDefined();
});
});
But when the test runs, I get the following error:
Error: [$injector:unpr] Unknown provider: DataResolveProvider <- DataResolve <- MyCtrl
What I have been doing wrong?
In your beforeEach, add a reference to your service :
beforeEach(inject(function($controller, DataResolve){
this.DataResolve = DataResolve;
this.myCtrl = $controller('ParcelasController', {
DataResolve: this.DataResolve;
});
}));

How to use one controller inside another one

I would like to use one controller inside another one. I have found that I could use angular service $controller.
This is what I have tried:
.controller(
'UnplannedTasksController',
[
'$location',
'$uibModal',
'$controller',
'unplannedTasksService',
'messages',
function($location, $uibModal, $controller, unplannedTasksService, messages) {
var ctrl = this;
var modalInstanceCtrl = $controller('ModalInstanceCtrl');
this.openModal = function(unplannedTask) {
var modalInstance = $uibModal.open({
animation: false,
templateUrl: 'unplanned-tasks/unplanned-tasks-modal.html',
controller: modalInstanceCtrl,
controllerAs: 'mdCtrl',
size: 'lm',
resolve: {
object: function() {
return unplannedTask;
},
title: function() {
return messages.unplannedTasks.deleteTitle;
},
question: function() {
return messages.unplannedTasks.deleteQuestion + unplannedTask.partner.name;
}
}
});
modalInstance.result.then(function(unplannedTask) {
ctrl.display.getUnplannedTasksBusyPromise = unplannedTasksService.removeUnplannedTask(unplannedTask.id).then(function(data) {
ctrl.searchUnplannedTasks();
});
});
};
}])
This ModalInstanceCtrl is in another file and look like this:
.controller('ModalInstanceCtrl', function($modalInstance, object, title, question) {
var ctrl = this;
this.object = object;
this.title = title;
this.question = question;
this.ok = function() {
$modalInstance.close(ctrl.object);
};
this.cancel = function() {
$modalInstance.dismiss('cancel');
};
})
But I am getting an error:
"Error: [$injector:unpr] Unknown provider: $modalInstanceProvider <- $modalInstance <- ModalInstanceCtrl ..."
Could you please advise. Thank you.
[EDIT]
Anyone? Please ...
Best regards,
mismas
According to the Angular-UI documentation, you do not need to use $controller. You just have to tell the controller name the the $uibModal service, as a simple string.
In your case:
var modalInstance = $uibModal.open({
controller: 'modalInstanceCtrl'
// + more params
});

Angular Modal with Dynamic Content that has Custom Directives

I am trying to display a dynamic form which contains custom directives as a modal. I have tried to use ng-bind-html but the html content that has custom directive shows up empty and throws error "The sanitizer was unable to parse the following block of html:"
Here is the running demo. Please advise.
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap', 'ngSanitize']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {
$scope.textvalue = "";
$scope.cbvalue = "";
});
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {
$scope.items = items;
$scope.textvalue;
$scope.ddvalue;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
angular.module('ui.bootstrap.demo').directive('customTextinput', function(){
return {
restrict: "EA",
scope: {
label: "=",
fieldvalue: "="
},
templateUrl: "customti.html",
controller: function($scope, $log){
}
}
})
angular.module('ui.bootstrap.demo').directive('customDropdown', function(){
return {
restrict: "EA",
scope: {
label: "="
},
templateUrl: "customcb.html",
controller: function($scope, $modal, $sce){
$scope.showModal = function(){
var modalInstance = $modal.open({
animation:true,
templateUrl: 'modaldemo.html',
backdrop: 'static',
controller: function($scope, $log, $modalInstance){
$scope.myContent = '<custom-textinput label="\'Text Input\'" ng-model="textvalue"';
//$scope.myContent = "<p>Hello World</p>";
$scope.ok = function () {
$modalInstance.close('');
}
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
}
}
})
}
}
}
})
You need module called ngSanitize take a look on angular docs here
https://docs.angularjs.org/api/ngSanitize
After installing this .You can use $sce service like this
var cleanHtml = $sce.trustAsHtml(html);
It will solve sanitizer errors.Also do not forget to inject it into direcitve.

unable to open a modal with angular and ui.routes

I am trying to follow this example to show a bootstrap modal on a certain state. It works fine without a modal (so the state config should be ok). All needed dependencies (ie angular bootstrap) should be available.
when I do a console.debug($stateParams) before $modal.open I get the correct data, within the $modal.open-method however the stateParams from the last state are returned (the state I am coming from)
Any hints?
EDIT
the relevant state cfg:
.state('publications.view', {
parent: 'publications.productSelection',
url: '/{productSlug:[a-zA-Z0-9-]+}/{docID:[0-9]+}_{slug:[a-zA-Z0-9-]+}',
onEnter: ['restFactory', '$state', '$stateParams', '$modal',
function(restFactory, $state, $stateParams, $modal) {
console.debug($stateParams.docID);
$modal.open({
templateUrl: 'partials/publication.html',
resolve: {
publication: ['restFactory', '$stateParams',
function(restFactory, $stateParams) {
console.debug($state.params);
console.debug($stateParams);
return restFactory.view($stateParams.language, $stateParams.productSlug, $stateParams.docID);
}
]
},
controller: ['$scope', '$sce', 'publication', '$rootScope',
function($scope, $sce, publication, $rootScope) {
$rootScope.pageTitle = publication.data.data.publication.Publication.title;
$scope.publication = $sce.trustAsHtml(publication.data.data.publication.Publication.content);
}
]
});
}
]
});
You can get around this issue by injecting the current $stateParams into the onEnter function, save them as state in some service, and inject that service instead into your modal resolves.
I am adapting the code from here: Using ui-router with Bootstrap-ui modal
.provider('modalState', function($stateProvider) {
var modalState = {
stateParams: {},
};
this.$get = function() {
return modalState;
};
this.state = function(stateName, options) {
var modalInstance;
$stateProvider.state(stateName, {
url: options.url,
onEnter: function($modal, $state, $stateParams) {
modalState.stateParams = $stateParams;
modalInstance = $modal.open(options);
modalInstance.result['finally'](function() {
modalInstance = null;
if ($state.$current.name === stateName) {
$state.go('^');
}
});
},
onExit: function() {
if (modalInstance) {
modalInstance.close();
}
}
});
};
})
Then in your app config section
.config(function($stateProvider, $urlRouterProvider, modalStateProvider) {
modalStateProvider.state('parent.child', {
url: '/{id:[0-9]+}',
templateUrl: 'views/child.html',
controller: 'ChildCtrl',
resolve: {
role: function(Resource, modalState) {
return Resource.get({id: modalState.stateParams.id}).$promise.then(function(data) {
return data;
});
}
}
});
}

ui bootstrap modal's controller 'is not defined'

i am trying to use the modal directive from ui-bootstrap 0.6
here is the working default plunker from the ui-bootstrap page:
http://plnkr.co/edit/JGBiBSeRqOnwRhYA9py8?p=preview
now, i tried to make the coding style fits angular-seed style to include it in one app like this :
http://plnkr.co/edit/Y59rwlcNpQdijKtmjOPy?p=preview
angular.module('MyModal', ['ui.bootstrap', 'MyModal.controllers']);
angular.module('MyModal.controllers', [])
.controller('ModalDemoCtrl', [ '$scope', '$modal', '$log', function ($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
}])
.controller('ModalInstanceCtrl', [ '$scope', '$modalInstance', 'items', function ($scope, $modalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}]);
but it's giving an error ReferenceError: ModalInstanceCtrl is not defined
how can i make this work using this way of defining controllers ?
Provide controller name as String, exactly as you would do in route definitions, directives etc.:
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
items: function () {
return $scope.items;
}
}
});
You can use quotes as the other answer suggests, or you can also do as the example in the docs and define the variable:
var ModalInstanceCtrl = function ($scope, $modalInstance, items) { ... }

Resources