Using $watch on an AngularJS service function defined as an ES6 class - javascript

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.

Related

inject $rootScope in config angularJs

I have problem to inject $rootScope in config angularJS, this is my code, but still error, maybe anyone help me how to inject $rootScope in config angularJS. .
thanks.
(function() {
'use strict';
angular
.module('uliappApp')
.directive('angular-loading-bar', ['cfpLoadingBarProvider'])
.config(cfpLoadingBarProvider);
cfpLoadingBarProvider.$inject = ['cfpLoadingBarProvider', '$rootScope'];
function cfpLoadingBarProvider(cfpLoadingBarProvider, $rootScope) {
cfpLoadingBarProvider.includeBackdrop = true;
console.log(rootScope.concessionLoadingScreen);
cfpLoadingBarProvider.spinnerTemplate = '<div class="loading-bar-container">'
+ '<div id="loading-bar-spinner"><div class="spinner-icon"></div></div></div>';
}
})();
You don't need rootScope in configuration phase, it can be simply achieved by using .run().
angular
.module('uliappApp')
.run(['$rootScope', function($rootScope){
$rootScope.concessionLoadingScreen = true;
}])
During the config phase, only providers can be injected.
Basically angularjs first invoke the config method and then invoke the run method. During config only providers are available. A provider can then be used to create service instance. So, you can use .run to inject $rootScope.
For example, the following is not allowed:
myMod.config(function(greeting) {
// WON'T WORK -- greeting is an *instance* of a service.
// Only providers for services can be injected in config blocks.
});
What you do have access to are any providers for services you've made:
myMod.config(function(greetingProvider) {
// ok fine!
});
All the best.
You can not use $rootScope during the configuration phase of an angular application.
Only constant and provider can be injected to the configuration phase.
You can use run phase, or create a provider (that is actually a service) to hold the configuration you want.
// Option 1 - during run
angular
.module('yourApp')
.run(['$rootScope', function($rootScope) {
}])
// Option 2 - provider
angular
.module('yourApp')
.provider('yourSettings', function() {
var $this = this;
this.yourSettings = 'yourValue';
this.$get = function() {
return $this;
}
})
angular
.module('yourApp')
.config(['yourSettingsProvider', function(yourSettingsProvider) {
// You can use yourSettingsProvider.yourSettings
}])

Dynamically injecting a specific factory based on route parameter fails for some reason

I want to dynamically inject a factory into my Angular controller based on the route parameter. This is my route configuration:
$routeProvider
.when("/tables/:table",
{
controller: "tableController",
templateUrl: "/app/views/table.html",
resolve: {
"factory": function r($route) {
return $injector.get($route.current.params.table + "Factory"); // Error!
}
}
})
For instance, when the route is tables/employee, I want an employeeFactory to be injected into tableController, and so on.
Unfortunately, this configuration does not work — I am getting an Unknown provider: employeeFactory error in the r function.
On the other hand, I can instead pass an $injector service directly to the tableController and successfully resolve employeeFactory there:
(function (angular) {
var tableController = function ($routeParams, $injector) {
// employeeFactory resolves successfully here!
var factory = $injector.get($routeParams.table + "Factory");
};
angular.module("appModule").controller("tableController", tableController);
})(angular);
However, I do not like this approach because it follows the service locator anti-pattern. I would really like factory to be injected using routing configuration and not this ugly workaround.
So, why Angular is throwing an error when using $injector.get() with resolve, but successfully resolves the factory inside of the tableController? I am using Angular 1.4.4.
You apparently use $injector that was injected into config block, and it differs from $injector that is injected anywhere else. The former acts on service providers, the latter acts on service instances.
It should be
"factory": function r($route, $injector) {
return $injector.get($route.current.params.table + "Factory");
}

How to inject dependencies to a named angular directive controller?

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

How to test function in $scope from different controller?

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();

How do I know what dependencies I can inject into a controller?

I am trying to use $routeProvider dependency inside my controller:
.controller('mainController', function($scope, $state, $routeProvider) {
But I am getting the error:
Error: [$injector:unpr] Unknown provider: $routeProviderProvider <- $routeProvider
How do I know what dependencies I can inject into any given controller?
There are two phases inside angular
Configuration Phase (Here we use app.config to write a code)
Run phase (Where we use app.run, after run cycle all other directives gets executed using compile cycle)
Provider is nothing but service/factory but the most important thing is it can be accessible inside configuration phase.
Example
Suppose we have below provider
myApp.provider('unicornLauncher', function UnicornLauncherProvider() {
var useTinfoilShielding = false;
this.useTinfoilShielding = function(value) {
useTinfoilShielding = !!value;
};
this.$get = ["apiToken", function unicornLauncherFactory(apiToken) {
return new UnicornLauncher(apiToken, useTinfoilShielding);
}];
});
While inject it inside config you should always prefix it Provider like unicornLauncherProvider
While using it inside controller you could use it as unicornLauncher
Note:
Provider are always accessible inside .config(configuration)
phase with suffix Provider in their name, While inside controller you could > directly inject it using unicornLauncher (direct provider name)
Services/Factory They are not visible in config phase of angular
Still confuse then do refer this link
You can only access services in the controller not the providers so use $route here.
Therefore you are getting error $routeProviderProvider becuase it is looking for the provider for $routeProvider which is itself a provider for $route.
Docs

Categories