authenticating a route in angular - angularjs

I need certain routes to require authentication, I am using this module:
https://github.com/enginous/angular-oauth
Which has $scope.authenticate but I am trying to figure out how to access $scope/that function from the $routeProvider. I saw an example call a factory function but that isn't exactly what I am trying to do.
'use strict';
angular.module('app', [
'ngRoute',
'angularOauth',
'googleOauth',
'app.global',
'app.home',
'app.view'
]).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'views/home/index.html',
controller: 'home'
});
$routeProvider.when('/view', {
templateUrl: 'views/view/index.html',
controller: 'view',
resolve: {
factory: checkAuth
}
}).otherwise({redirectTo: '/'});
$routeProvider.otherwise({redirectTo: '/'});
}]);
var checkAuth = function() {
};

The annotation for a resolve is the same dependency injection annotation used anywhere else in Angular. Your logic for authentication should live in a service for testability and reusability, so injecting and calling a method on your service is precisely what you should be doing:
resolve: {
auth: ['AuthenticationService', function (AuthenticationService) {
// Authentication service injected, call your method
return AuthenticationService.isAuthenticated();
}]
}
or
var checkAuth = ['AuthenticationService', function (AuthenticationService) {
// Authentication service injected, call your method
return AuthenticationService.isAuthenticated();
}];
angular.module('app', [
// ...
]).
config(['$routeProvider', function($routeProvider) {
// ...
$routeProvider.when('/view', {
templateUrl: 'views/view/index.html',
controller: 'view',
resolve: {
auth: checkAuth
}
})
// ...
}]);

Related

Using angular routeProvider with controller

Please consider the this code where the routeProvider is needed to inject page(n).html in ng-view.
In addition to the console error:
unknown provider: $routeProviderProvider <- $routeProvider
The argument to function routeIt is the name of the page to navigate to, How can I mix a conditional switch with routeProvider.when in order to call the page matching the argument in the most efficient manner? Thanks
(function () {
'use strict';
angular
.module('appModule')
.controller('MainMenuCtrl', ['$scope', '$http', 'TogglerFactory', '$routeProvider', MainMenuCtrl]);
function MainMenuCtrl($scope, $http, Toggler, routeProvider) {
$http.get('models/mainMenu.json').then(
function (response) {
$scope.menuItems = response.data;
},
function (error) {
alert("http error");
}
)
function routeIt (page) {
routeProvider
.when('/page1', {
url: "/page1",
templateUrl: 'views/page1.html',
controller: 'Page1Ctrl'
})
.when('/page2', {
url: "/page2",
templateUrl: 'views/page2.html',
controller: 'Page2Ctrl'
})
}
$scope.itemClicked = function (item){
Toggler.menuToggle();
routeIt(item);
}
}
})();
Service providers aren't available for injection in run phase (i.e. anywhere but provider services and config blocks). It is possible to make route provider injectable and configure it after config phase,
app.config(function ($provide, $routeProvider) {
$provide.value('$routeProvider', $routeProvider);
});
And controllers aren't the best places to implement any logic (e.g. route hot-plug).
Ok you're using your routeProvider wrong you need to configure your routes inside .config blocks
angular.module('myApp', [])
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/page1', {
url: "/page1",
templateUrl: 'views/page1.html',
controller: 'Page1Ctrl'
}
})
If you want to change the url from your controller use $location.path('/page1'); inside your controller.

UI router Unknown provider for injecting service into child state resolve

Got Unknown provider when injecting service into the child state resolve function. But if defined a resolve in the parent state, it just works. Below there are some sample codes:
I defined a service module
angular.module('services', [])
.factory('myService', function() {
// my service here
})
and initialize the app
var app = angular.module('app', ['services', 'ui.router']);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider,
$urlRouterProvider) {
$stateProvider.state('wizard', {
url: '/wizard',
abstract: true
})
.state('wizard.step1', {
url: '/step1',
templateUrl: ... ,
resolve: {
name: function(myService) {
// do something with mySerice
}
},
controller: function(name) {
// controller codes here
}
})
}]);
I got the error Unknown provider complaining about myService in the wizard.step1 resolve. But if I add a random resolve in the parent state, like
$stateProvider.state('wizard', {
url: '/wizard',
abstract: true,
resolve: {
a: function() { return 1; }
}
})
then it works without error. Wonder what happens here?
In your controller you have to inject your service MyService, so define something like this
.state('wizard.step1', {
url: '/step1',
templateUrl: ... ,
resolve: {
name: ['myService', function(myService) {
// do something with mySerice
}]
},
controller: ['name', function(name) {
// controller codes here
}]
})
You have to inject your service in your config function :
var app = angular.module('app', ['services', 'ui.router']);
app.config(['$stateProvider', '$urlRouterProvider', 'myService',
function($stateProvider, $urlRouterProvider, myService) {
...
Another way is to embed your resolve code in a service and assign directly the service :
app.config(['$stateProvider', '$urlRouterProvider' ,'mySuperService',function($stateProvider,
$urlRouterProvider, mySuperService) {
...
resolve: {
name: mySuperService()
}
.constant('mySuperService', function() {
var serv= function(){
// your code
}
return serv;
}

Write unit test for resolve function in AngularJS

I have the below code. When I run my unit tests, I get that the resolve function is not code covered.
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/', {
controller: 'HomeCtrl',
resolve: {
homePage: function (homePageLoader) {
return homePageLoader();
}
},
templateUrl: 'views/home.html'
}).
otherwise({ redirectTo: '/' });
}]);
How do I write unit tests for the resolve function?
I had a smilar situation with my app.js with routeprovider & resolve. This was solved with below:
app.js
var appModule = angular.module('myApp',['ngRoute'])
.config(['$httpProvider', '$routeProvider', '$locationProvider', '$translateProvider', function ($httpProvider, $routeProvider, $locationProvider, $translateProvider) {
$locationProvider.html5Mode(true)
$routeProvider
.when('/services/main', {templateUrl: '/services/main/html/main.html', controller: 'MainCtrl', resolve: {
myVar: function (varService) {
return varService.invokeService();
}
}})
}])
Spec file
describe("Unit Testing: config - ", function() {
var appModule;
var mockService;
beforeEach(function() {
appModule = angular.mock.module("myApp");
});
it('should test routeProvider resolve', function() {
mockService = {
invokeService: jasmine.createSpy('invokeService').andReturn('myVar')
};
module(function($provide){
$provide.value('varService', mockService);
});
inject(function($route, $location, $rootScope, $httpBackend) {
$httpBackend.expectGET('/services/main/html/main.html').respond({});
$location.path('/services/main');
$rootScope.$digest();
expect($route.current).toBeDefined();
});
});
});
this ensures the coverage for the resolve.

How do I add a controller to a module in Angular JS

I have the following in my app.js:
var app = angular.module('app', ['admin', 'ui.compat', 'ngResource', 'LocalStorageModule']);
app.config(['$stateProvider', '$locationProvider',
function ($stateProvider, $locationProvider) {
$locationProvider.html5Mode(true);
var home = {
name: 'home',
url: '/home',
views: {
'nav-sub': {
templateUrl: '/Content/app/home/partials/nav-sub.html',
}
}
};
$stateProvider.state(home)
}])
.run(['$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$state.transitionTo('home');
}]);
in admin.js:
angular
.module('admin', ['ui.state'])
.config(['$stateProvider', '$locationProvider',
function ($stateProvider, $locationProvider) {
$locationProvider.html5Mode(true);
var admin = {
name: 'admin',
url: '/admin',
views: {
'nav-sub': {
templateUrl: '/Content/app/admin/partials/nav-sub.html',
}
}
};
var adminContent = {
name: 'admin.content',
parent: admin,
url: '/content', views: {
'grid#': {
templateUrl: '/Content/app/admin/partials/content.html',
controller: 'AdminContentController'
}
}
}
$stateProvider.state(admin).state(adminContent)
}])
I am confused about how to wire up my AdminContentController. Currently I have the following:
app.controller('AdminContentController',
['$scope', 'entityService', 'gridService', 'gridSelectService', 'localStorageService',
function ($scope, entityService, gridService, gridSelectService, localStorageService) {
$scope.entityType = 'Content';
Can someone verify if this is the correct way for me to set up my module and add it to app. Should I be adding the controller to the app:
app.controller('AdminContentController',
or should this belong to the module 'admin'. If it should then how should I wire it up?
Based on what you have shared, the the controller should be created on admin module such as
var adminModule=angular.module('admin'); // This syntax get the module
adminModule.controller('AdminContentController',
['$scope', 'entityService', 'gridService', 'gridSelectService', 'localStorageService',
function ($scope, entityService, gridService, gridSelectService, localStorageService) {
$scope.entityType = 'Content';
You could also define the controller in continuation of your admin module declaration.
Yes that would work angular.module('admin') works as a getter. So you'll get the same module in each file.

Angularjs dependency injection in resolve

I would like to use proper dependency injection in MyCtrl1to inject the fields of the MyCtrl1.resolve object. I've tried many different combinations of attempting to inject #MyCtrl1.resolve etc. with no luck.
#MyCtrl1 = ($scope, $http, batman, title) ->
$scope.batman = batman.data
$scope.title = title.data
#MyCtrl1.resolve = {
batman: ($http) ->
$http.get('batman.json')
title: ($http) ->
$http.get('title.json')
}
##MyCtrl1.$inject = ['$scope', '$http'] -- commented out because not sure how to inject resolve fields
angular
.module( 'app', [])
.config( ['$routeProvider', '$locationProvider', ($routeProvider, $locationProvider)->
$locationProvider.html5Mode(true)
$routeProvider.when('/', {templateUrl: 'index.html', controller: MyCtrl1, resolve: MyCtrl1.resolve})
$routeProvider.otherwise({redirectTo: '/'})
])
angular.bootstrap(document,['app'])
Resolve is a property of a route and not a controller. Controllers would be injected with dependencies defined on a route level, there is no need to specify resolve properties on a controller.
Taking one of your examples (transformed to JavaScript), you would define your controller as always, that is:
MyCtrl1 = function($scope, $http, batman, title) {
$scope.batman = batman.data;
$scope.title = title.data;
}
and then the resolve property on a route:
angular.module('app', []).config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true)
$routeProvider.when('/',{templateUrl: 'index.html', controller: MyCtrl1, resolve: {
batman: ['$http', function($http) {
return $http.get(..).then(function(response){
return response.data;
});
}],
title: ['$http', function($http) {
return //as above
}]
}});
$routeProvider.otherwise({redirectTo: '/'});
}]);
If you want to minify the code using resolve section of routing you need to use array-style annotations - I've included this in the example above.

Resources