I have an AngularJS factory which I am attempting to use to create modals. However, when I attempt to use the resolve method in the $modal my modal instance controller gets an unresolved provider.
Here is how I am calling my factory from my controller:
var modalOptions = {
template: 'app/common/modalwindow.html',
data: data
};
modalFactory.openModal(modalOptions);
My modal factory is simple for now, all it has is a single open modal method:
(function() {
'use strict';
var factoryId = 'modalFactory';
angular.module('app').factory(factoryId, ['$modal', modalFactory]);
function modalFactory($modal) {
var factory = {
openModal: openModal
}
return factory;
function openModal(data) {
$modal.open({
templateUrl: data.template,
controller: 'modalInstanceCtrl',
resolve: {
modalData: function () {
return data.data;
}
}
});
}
}
})();
However, when my modalInstanceCtrl is called it throws an error. Here is my modalInstanceCtrl
(function () {
'use strict';
var controllerId = 'modalInstanceCtrl';
angular.module('app').controller(controllerId, ['common', 'modalData', modalInstanceCtrl]);
function modalInstanceCtrl(common, modalData) {
var getLogFn = common.logger.getLogFn;
var log = getLogFn(controllerId);
log(modalData);
};
})();
The error it throws is:
Unknown provider: modalDataProvider <- modalData <- modalInstanceCtrl
I thought the resolve in the $modal would handle this injection. Am I assuming wrong here?
Related
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;
});
}));
I decided to base my AngularJS project on angular-seed if found on GitHub. But I have a problem with factory that I try to call from my controller.
I have controller like this:
(function() {
'use strict';
angular.module('myApp.authentication', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/authentication', {
templateUrl: 'views/authentication/authentication.partial.html',
controller: 'AuthenticationCtrl',
controllerAs: 'vm',
bindToController: true
});
}])
AuthenticationCtrl.$inject = ['authenticationService']
.controller('AuthenticationCtrl', [function(authenticationService) {
var vm = this;
vm.login = function() {
var all = authenticationService.getAll();
console.log("login" + all)
}
}]);
})();
So when vm.login() get triggered I want to call authenticationService.getAll();to get data from my service as below:
(function () {
'use strict';
angular
.module('myApp')
.factory('authenticationService', authenticationService);
function authenticationService() {
var service = {
getAll: getAll
};
return service;
function getAll() {
return [
{first: 'Alan', last: 'Dex', lunchMoney: 123},
{first: 'Ada', last: 'True', lunchMoney: 82},
{first: 'Adam', last: 'Mc Donald', lunchMoney: 122},
{first: 'Anthony', last: 'Heys', lunchMoney: 322},
{first: 'Pamela', last: 'Anders', lunchMoney: 422}
];
}
}
})();
But I got following error Uncaught ReferenceError: AuthenticationCtrl is not defined Is that because I try to inject factory into controller that is not created yet? If so how should I write this piece?
Make the followinf changes to your controller :
(function() {
'use strict';
angular.module('myApp.authentication', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/authentication', {
templateUrl: 'views/authentication/authentication.partial.html',
controller: 'AuthenticationCtrl',
controllerAs: 'vm',
bindToController: true
});
}])
.controller('AuthenticationCtrl', AuthenticationCtrl);
AuthenticationCtrl.$inject = ['authenticationService']
function AuthenticationCtrl(function(authenticationService) {
var vm = this;
vm.login = function() {
var all = authenticationService.getAll();
console.log("login" + all)
}
});
})();
Actually you are trying to inject service to your controller before defining that controller.i.e. when it tries to inject service it don't found the controller.
Thanks & Cheers
If you want to define your controller explicitly as a function, then you need write it like so:
function AuthenticationCtrl (authenticationService) {
var vm = this;
vm.login = function() {
var all = authenticationService.getAll();
console.log("login" + all)
}
};
AuthenticationCtrl.$inject = ['authenticationService'];
angular.module('myApp.authentication')
.controller('AuthenticationCtrl', AuthenticationCtrl);
I suggest to write dependencies in that way:
.controller('AuthenticationCtrl', ['authenticationService', function(authenticationService) {
var vm = this;
vm.login = function() {
var all = authenticationService.getAll();
console.log("login" + all)
}
}]);
Seems more readable and less lines of code
I am trying to lazy load my controllers in angular via requirejs
.when('/', {
templateUrl: 'views/main.html',
resolve: {
load: ['$q', '$rootScope', function ($q, $rootScope) {
var deferred = $q.defer();
// At this point, use whatever mechanism you want
// in order to lazy load dependencies. e.g. require.js
// In this case, "itemsController" won't be loaded
// until the user hits the '/items' route
require(['controllers/main'], function () {
$rootScope.$apply(function () {
deferred.resolve();
});
});
return deferred.promise;
}]
}
});
This is my controller
define(['angular'], function (angular) {
'use strict';
var app = angular.module('someApp.controllers.MainCtrl', [])
.controller('MainCtrl', ['$scope', function ($scope) {
$scope.abc = "abc";
return app;
});
My view doesnt show the variable abc. Even though the view is rendering fine
<span>abc={{abc}}</span>
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
});
I have this controller:
angular.module('clientApp')
.controller('MainCtrl', function ($scope, projects) {
$scope.projects = projects;
});
projects is a resolve from a database. It works in the view.
This is my service:
angular.module('clientApp.services', ['ngResource'])
.factory('Projects', function($resource){
return $resource('/api/project/:prj_id', {'prj_id':'#prj_id'});
})
.factory('MultiProjectsLoader',['Projects', '$q', '$stateParams',
function(Projects, $q) {
return function() {
var delay = $q.defer();
Projects.query(function(projects) {
delay.resolve(projects);
}, function() {
delay.reject('Unable to fetch sizes');
});
return delay.promise;
};
}
]);
And this is my app.js
$stateProvider
.state('home', {
url: '/',
templateUrl: 'views/home.html',
resolve:{
projects: ['MultiProjectsLoader', function(MultiProjectsLoader){
return new MultiProjectsLoader();
}]
},
controller: 'MainCtrl'
});
Trying to write a test for this:
'use strict';
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('clientApp'));
beforeEach(function () {
angular.module('clientApp.services');
});
var MainCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
}));
it('should attach a list of projects to the scope', function () {
expect(scope.projects.length).toBeGreaterThan(1);
});
});
I get:
Error: [$injector:unpr] Unknown provider: projectsProvider <- projects
I guess I need to include the service somehow beforeEach(..). But I can't get it working. Any ideas?
You can inject the service a couple ways but my recommended way is to mock the service.
describe('Controller: MainCtrl', function () {
var
projectServiceMock = {
getData: function() {}
},
DATA_FROM_SERVER = {}
;
// load the controller's module
beforeEach(module('clientApp'));
beforeEach(function () {
angular.module('clientApp.services');
//angular.module('project'); // But dont use this method as you will be testing the service in the controller:
});
var MainCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
spyOn(projectServiceMock, 'getData').andReturn(DATA_FROM_SERVER);
MainCtrl = $controller('MainCtrl', {
$scope: scope,
project: projectServiceMock
});
}));
it('should attach a list of projects to the scope', function () {
expect(projectServiceMock.getData).toHaveBeenCalledWith(DATA_FROM_SERVER);
expect(scope.projects.length).toBeGreaterThan(1);
});
});
Your service should expose a method for returning the data it has gotten from the server not just straight data through project.
For example:
project.getData();