How can I call controller on ui-router resolve? - angularjs

This is what my ui-router looks like:
.state('colleague', {
url: "/colleague",
templateUrl: "views/colleague.html",
resolve: {
typeEmployee: function ($q, $timeout) {
var deferred = $q.defer();
$timeout(function () {
deferred.resolve('manager');
}, 200);
return deferred.promise;
}
,
controller: 'colCtrl'
}
})
The issue is that I can't go to the collegue page:
<a ui-sref="colleague">colleague</a>
This is the controller code:
function colCtrl() {
debugger;
console.log('type of employee is:', typeEmployee);
if (typeEmployee === 'colleague') {
console.log('not allowed to view this');
}
if (typeEmployee === 'manager') {
console.log('allowed to view this');
}
}
app.controller('colCtrl', colCtrl);
When I grab the code from the controller and paste this directly into the router it works. What do I need to fix in the code so I can use 'controller:colCtrl' in my router?

You are using controller inside the resolve. You should move that to top level of state config object.
.state('colleague', {
url: "/colleague",
templateUrl: "views/colleague.html",
controller: 'colCtrl', // Notice its same level as resolve
resolve: {
typeEmployee: function ($q, $timeout) {
var deferred = $q.defer();
$timeout(function () {
deferred.resolve('manager');
}, 200);
return deferred.promise;
}
}
})
Here is working plunkr with your example.

Problem is that, you need to mention the Controller as a variable, not as a string.
i.e.
controller: colCtrl
not
controller: 'colCtrl'

Related

AngularJS UI router: Block view

Right now i am making an AngularJS+UI router install application. But i have a problem, the problem is, that i want to disable access to the views, associated with the install application. I want to do it in resolve in the state config.
But the problem is i need to get the data from a RESTful API, whether the application is installed or not. I tried making the function, but it loaded the state before the $http.get request was finished.
Here was my code for the resolve function:
(function() {
var app = angular.module('states', []);
app.run(['$rootScope', '$http', function($rootScope, $http) {
$rootScope.$on('$stateChangeStart', function() {
$http.get('/api/v1/getSetupStatus').success(function(res) {
$rootScope.setupdb = res.db_setup;
$rootScope.setupuser = res.user_setup;
});
});
}]);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/404");
$stateProvider.state('db-install', {
url: "/install/db",
templateUrl: 'admin/js/partials/db-install.html',
controller: 'DBController',
resolve: {
data: function($q, $state, $timeout, $rootScope) {
var setupStatus = $rootScope.setupdb;
var deferred = $q.defer();
$timeout(function() {
if (setupStatus === true) {
$state.go('setup-done');
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}
}
})
.state('user-registration', {
url: "/install/user-registration",
templateUrl: "admin/js/partials/user-registration.html",
controller: "RegisterController"
})
.state('setup-done', {
url: "/install/setup-done",
templateUrl: "admin/js/partials/setup-done.html"
})
.state('404', {
url: "/404",
templateUrl: "admin/js/partials/404.html"
});
}]);
})();
EDIT:
Here is what my ajax call returns:
Try this way:
$stateProvider.state('db-install', {
url: "/install/db",
templateUrl: 'admin/js/partials/db-install.html',
controller: 'DBController',
resolve: {
setupStatus: function($q, $state, $http) {
return $http.get('/api/v1/getSetupStatus').then(function(res) {
if (res.db_setup === true) {
$state.go('setup-done');
return $q.reject();
}
return res;
});
}
}
})
Then inject setupStatus in controller:
.state('setup-done', {
url: "/install/setup-done",
templateUrl: "admin/js/partials/setup-done.html",
controller: ['$scope', 'setupStatus', function ($scope, setupStatus) {
$scope.setupdb = setupStatus.db_setup;
$scope.setupuser = setupStatus.user_setup;
}]
})

Maximum call stack size exceeded using angular ng-view

I want to redirect after login to /dashboard
$scope.submit = function (user) {
if ($scope.loginForm.$valid) {
UserService.login(user).then(
function (result) {
$location.path('/dashboard');
}, function (reason) {
$scope.msg = "username or password is not correct";
});
$scope.reset();
}
};
in app.js I want to create my menu dynamically and show dashboard.html
$routeProvider
.when('/dashboard', {
templateUrl: 'views/dashboard.html',
abstract:true,
resolve: {
menu: function (MenuService) {
return MenuService.getMenu();
}
},
controller: function ($scope, menu) {
$scope.menu = menu;
$scope.oneAtATime = true;
}
})
and in dashboard I use ng-view to load my template
<div class="content">
<div class="container">
<ng-view></ng-view>
</div>
but it catch "Maximum call stack size exceeded" error.
THE MenuService servie return promise
factory('MenuService', function ($q, $http) {
var getMenu = function () {
var deferred = $q.defer();
$http.post('/menu', 1).
success(function (data) {
deferred.resolve(data);
}).
error(function (data, status) {
deferred.reject(status);
});
return deferred.promise;
};
return{
getMenu: getMenu
}
})
I changed the MenuService.getMenu() to this:
$routeProvider
.when('/dashboard', {
templateUrl: 'views/dashboard.html',
abstract:true,
resolve: {
menu: function (MenuService) {
MenuService.getMenu().then(function(result){
return result;
});
}
},
controller: function ($scope, menu) {
$scope.menu = menu;
$scope.oneAtATime = true;
}
})
and now dashboard is loaded but without menu. then method is called after dashboard.html loading!!!!
when I remove ng-view every thing work perfectly.
What is my problem?
thank you
Basically you need to do change in your custom resolve service code. Currently your controller promise has receiving chain promise, so you should return a promise instead of return chain promise.
Code
$routeProvider
.when('/dashboard', {
templateUrl: 'views/dashboard.html',
abstract:true,
resolve: {
menu: function (MenuService) {
return MenuService.getMenu();
}
},
controller: function ($scope, menu) {
menu.then(function(data){
$scope.menu = data;
});
$scope.oneAtATime = true;
}
})

Loading controller on demand using AngularJS and RequireJS

I'm using Angular UI-router and trying to download/load controller when the routing changes. I used resolve and category, the data.data returns the js file content as string. I'm not sure to make the controller available to angular. Please help
My module.js contains below routing code
state("privacy", {
url: "/privacy",
controllerProvider: function ($stateParams) {
return "PrivacyController";
},
resolve: {
category: ['$http', '$stateParams', function ($http, $stateParams) {
return $http.get("js/privacy.js").then(function (data) {
return data.data;
});
} ]
},
templateUrl: localPath + "templates/privacy.html"
})
The below controller exist in "js/privacy.js"
socialinviter.controller("PrivacyController", function ($scope) {
$scope.me = "Hellow world";
});
I also tried with require js but I'm getting error "http://errors.angularjs.org/1.2.16/ng/areq?p0=PrivacyController&p1=not%20aNaNunction%2C%20got%20undefined"
resolve: {
deps: function ($q, $rootScope) {
var deferred = $q.defer(),
dependencies = ["js/privacy"];
require(dependencies, function () {
$rootScope.$apply(function () {
deferred.resolve();
});
deferred.resolve()
})
return deferred.promise;
}
}
I have resolved the issue and I thought the solution would be helpful for others
Step 1: On your config, include the parameter $controllerProvider
mytestapp.config(function ($stateProvider, $controllerProvider)
Step 2: telling angular to register the downloaded controller as controller, add the below inside the config
mytestapp.config(function ($stateProvider, $controllerProvider) {
mytestapp._controller = mytestapp.controller
mytestapp.controller = function (name, constructor){
$controllerProvider.register(name, constructor);
return (this);
}
......
Step 3: Add the resolve method as below
state("privacy", {
url: "/privacy",
controller: "PrivacyController",
resolve: {
deps : function ($q, $rootScope) {
var deferred = $q.defer();
require(["js/privacy"], function (tt) {
$rootScope.$apply(function () {
deferred.resolve();
});
deferred.resolve()
});
return deferred.promise;
}
},
templateUrl: "templates/privacy.html"
})

Loading data for controller in Angular.js with resolve and $resource

I'm trying to load a job by Id from the API and pass it to the controller.
.when('/jobs/edit/:id', {
templateUrl: 'partials/jobs/edit',
controller: 'JobCtrl',
resolve: function($routeParams, Job){
var jobId = $routeParams.id;
return {
job: function(){
return Job.get({ id: jobId});
}
};
}
})
Controller:
angular.module('App')
.controller('JobCtrl', function ($scope, Job, $location, $routeParams) {
$scope.newJob = data.job; //does not work
$scope.errors = {};
$scope.save = function (form) {
//...
};
});
Model:
angular.module('App')
.factory('Job', function ($resource) {
return $resource('/api/jobs/:id', {
id: '#id'
}, { //parameters default
update: {
method: 'PUT'
}
});
});
How do I get the data in the controller? My resolve block in the route is not even being executed.
Edit: this page has lots of examples of different types of resolving:
http://phillippuleo.com/articles/angularjs-timing-multiple-resource-resolves-ngroute-and-ui-router
It seems like you resolve implementation is incorrect.
You could try to change router like:
.when('/jobs/edit/:id', {
templateUrl: 'partials/jobs/edit',
controller: 'JobCtrl',
resolve: {
job: function (Job, $routeParams) {
return Job.get({id: $routeParams.id});
}
}
})
And get resoled data in controller by including Job into dependencies:
angular.module('App')
.controller('JobCtrl', function ($scope, job, $location, $routeParams) {
// job is resolved here
$scope.job = job;
$scope.newJob = {};
$scope.errors = {};
$scope.save = function (form) {
//...
};
});
UPDATED
If you want to use JobCtrl either for creating and editing, you can return null in resoled job for new-job-page. It means: There aren't any job yet, till you create one.
.when('/jobs/new', {
templateUrl: 'partials/jobs/new',
controller: 'JobCtrl',
resolve: {
job: function () {
return null;
}
}
})

AngularJS+ Firebase can't get data preloaded on route change

var testApp = angular.module('testApp', ['firebase'])
.config(['$routeProvider','$locationProvider',function
($routeProvider,$locationProvider)
{
$routeProvider
.when('/', {
templateUrl: '/views/main.html',
controller: 'MainCtrl'
})
.when('/test', {
templateUrl: '/views/test.html',
controller: testCrtl,
resolve:
{
firedata: function($q,angularFire){
var deffered = $q.defer();
var ref = new Firebase('https://shadowfax.firebaseio.com/items');
ref.on('value', function(result){
deffered.resolve(result.val());
});
return deffered.promise;
}
}
})
.otherwise({
redirectTo: '/'
});
// $locationProvider.html5Mode( true );
}]);
angular.module('testApp')
.controller('MainCtrl', ['$scope','$routeParams','$rootScope', function ($scope,$routeParams,$rootScope) {
$scope.load = function(){ return false;}
$rootScope.$on('$routeChangeStart', function(next, current) {
$scope.load = function(){ return true;}
});
}]);
testApp.controller('TestCtrl',['$scope','$timeout','Fire','firedata','testCrtl']);
var testCrtl = function ($scope,$timeout,Fire,firedata) {
$scope.items=firedata;
};
In the code above, why is the value of $scope.items=firedata; null? Please explain how can I perform a Google-like route change to preload data for the controller? This example works like John Lindquist explains, but when I use Firebase's native JS library, I can't get the data preloaded.
Also, using the Firebase angularFire library doesn't help, because it uses $scope as a parameter and it's not possible to pass $scope to the resolve function.
You should be able to use angularFireCollection to preload data:
.when('/test', {
templateUrl: '/views/test.html',
controller: testCrtl,
resolve: {
firedata: function(angularFireCollection){
return angularFireCollection('https://shadowfax.firebaseio.com/items');
}
}
})

Resources