I'm using Jasmine for testing my AngularJS application. I have an Authenticaiton controller, which calls a function which I define in the scope from the Application controller. So:
1. AppController
$scope.setUser = function() {}
2. AuthenticationController
$scope.setUser(User);
I am testing the AuthenticationController, and setUser() is not inside the scope of AuthenticationController. How do I inject the scope/function from the AppController?
The error message:
TypeError: $scope.setUser is not a function
Should I mock the whole function? Is the structure smelly? What's the best way to do this?
EDIT:
In the real app, AuthenticationController gets injected into my dashboard-app.
AuthenticationController:
angular
.module( 'authentication', [])
.controller('AuthenticationController', AuthenticationController);
AuthenticationController.$inject = ['$scope', '$rootScope', 'AUTH_EVENTS', 'AuthenticationService'];
Dashboard:
angular
.module('dashboard', [
'authentication'
])
.run(run);
Info: Names are changed in my question to make it easier to understand.
inject $rootScope into your controllers.
AppController :
$rootScope.setUser = function() {}
AuthenticationController
$rootScope.setUser();
Related
I'm using ES6 with AngularJS and am following this guide. It recommends defining services as classes.
In a service definition I'm injecting the $cookieStore service and attaching it to the class like this:
export default class Authentication {
constructor($cookieStore) {
this.$cookieStore = $cookieStore;
}
setAuthenticatedAccount(account) {
this.$cookieStore.put(JSON.stringify(account), 'authenticatedAccount');
}
isAuthenticated() {
return !!this.$cookieStore.get('authenticatedAccount');
}
}
I want to update my navbar to reflect whether or not the user is logged in, which I'm doing with $watch:
var NavbarController = function($location, $scope, Authentication) {
$scope.$watch(Authentication.isAuthenticated, () => {
$scope.isAuthenticated = Authentication.isAuthenticated();
$scope.currentUser = Authentication.getAuthenticatedAccount();
});
}
This gives the following error:
Cannot read property '$cookieStore' of undefined.
This error usually occurs when you don't inject proper dependencies in your controller.
Just make sure that $cookieStore is propertly injected in your angular controller
myApp.controller('myCtrl', ['$scope', '$cookieStore', function ($scope, $cookieStore) {
...
...
point to note
The $cookieStore service is deprecated. Please use the $cookies service instead.
If I have code similar to this question on injecting another controller to a directive:
angular.module('paramApp', []);
angular.module('paramApp').controller('ParamCtrl', ['$scope', '$http', function($scope, $http) {
.
.
.
}]);
angular.module('deviceApp', ['paramApp']);
angular.module('deviceApp').directive('DeviceDirective', function () {
return {
.
.
.
controller: 'ParamCtrl'
};
});
When I minify js, the injected dependencies of $scope and $http break, how can I explicitly define the dependencies of ParamCtrl when creating DeviceDirective to prevent uncaught injector issues with bundled js?
I am very late to this question but I'll give it a shot.
The syntax is based on John Papa's Angular style guide
First you need a way to make your controller reusable. Convert it from an anonymous function to a named function and pass it to your angular app like so:
// Named controller function
ParamCtrl function($scope, $http) {
this.doStuff
}
// Bind it to your app
angular.module('paramApp').controller('ParamCtrl', ['$scope', '$http', ParamCtrl );
// While we are at it, do the same with your directive
DeviceDirective function (controlerParam) {
return {
...
controller: controlerParam
}
}
// Bind it to your app
angular.module('deviceApp', ['ParamCtrl', DeviceDirective]);
However, if you meant to pass the controller's scope to your directive refer to fiznool's post
I am a bit newbiew with javascript and i am starting to use angular.js
So my question is if there is a way to inject a controller inside a module that is declared in an anonymous function
my code looks like this
app.js
(function(angular) {
var app = angular.module('Organizer', ['ngMaterial', 'ngAnimate', 'ngAria']);
})(angular);
siteController.js
(function(angular, app) {
app.controller('site', function($scope, $mdDialog)
{
var alert = $mdDialog.alert({
title: 'Test',
content: 'Testing',
ok: 'Exit'
});
$mdDialog.show(alert);
});
})(angular);
i have tried to look for ways if it is possible, but still i would like to see if anyone here could explain how this can be made if it could.
Note: I have already used angular.js before and i wanted to try a different way to declare controllers so the client wont have any way to modify it
If you create a module in Angular, then you can not obfuscate it in this way. In the console, a user can just run angular.module('Organizer') to get access to your app, and then call any method they want on it.
The reason your code won't work as written, is because you are not passing the app variable to your anonymous function. So if you want to add a controller to the Organizer module, then you would do something like this:
(function(angular)
{
angular.
module('Organizer').
controller('site', function($scope, $mdDialog)
{
...
});
})(angular);
Theres no need to wrap any of this code in self executing functions as if you are trying to keep variables out of the global scope. The only one that's global is the "angular" object.
Your app.js should only have
'use strict';
angular.module('Organizer', ['ngMaterial', 'ngAnimate', 'ngAria']);
You controller file should only have
'use strict';
angular.module('Organizer').controller('siteController', function($scope, $mdDialog) {
var alert = $mdDialog.alert({
title: 'Test',
content: 'Testing',
ok: 'Exit'
});
$mdDialog.show(alert);
});
The first call to module in app.js passes the second parameter which angular uses to instantiate your module. Subsequent calls that omit the second parameter "get" the module.
Let's say I have a module called App which injects two other modules called factories and controllers:
var app = angular.module("app", ["factories", "controllers", "directives"])
.run(function ($rootScope, userFactory) {
userFactory.property = "someKickstartValue";
});
The factories module holds all factories:
var factories = angular.module("factories", []),
factory = factories.factory("testFactory", {
property: "someValue"
});
And the controllers module holds all controllers:
var controllers = angular.module("controllers", ["factories"]),
controller = controllers.controller("controller", function ($scope, testFactory) {
console.log(testFactory.property); // Returns "Some Value" and not
// "someKickstartValue" as expected.
});
The actual Question:
Why does the "someKickstartValue" not apply to the controllers? As far as I do understand the module app has it's own testFactory instance and the module controllers has it's own as well, so there can't be any information shared between modules via factories. Is there a way around, or have I made a mistake?
I fixed it by removing the "factories" dependency of the controller.
var controllers = angular.module("controllers", []),
controller = controllers.controller("controller", function ($scope, testFactory) {
console.log(testFactory.property); // Returns "someKickstartValue" as expected
});
Because I now do not declare factories as dependency, the controllers module doesn't create it's own instance of factories and has access to the instance of the app module which injects the controllers module.
I faced the same problem. I solved it in the following way:
// modules.js
(function (angular) {
angular.module("shared", []);
angular.module("user", ["shared"]);
angular.module("admin", ["shared"]);
})(window.angular);
Such structure allows to use factories, services, directives attached to the shared module in other modules.
I wonder why I can't access a factory within the same module.
As I think it is better to build a web app with different independent modules, I would like to group all methods (services, factories, directives, ...) within the same module.
What do I do wrong?
app = angular.module("MyGreatModuleProvider", []);
app.factory("MyFactory", function($rootScope, $scope) {
return {
myFunction: function() {
console.log("Hello World");
}
}
});
app.controller("myCtrl", function($scope, MyFactory) {
MyFactory.myFunction();
// This doesnt't work, unknown provider
});
Factories don't have a $scope
If you remove the $scope and only keep the $rootScope it works just fine
You can remove both $scope and $rootScope from the factory declaration. Here's a plunker.
Define your injected object names to let the Angular know what to inject into fields:
app.controller("myCtrl", ['$scope', 'MyFactory', function($scope, MyFactory) {
MyFactory.myFunction();
}]);
It's a good practice especially if you are going to compile your application.
Moreover as others pointed out: factories doesn't have $rootScope and $scope.