AngularJS - How to separate controllers/modules? - angularjs

I have one application that has two pages.
1 - A list of users
2 - Where I can manage a particular user
In order to organize I create two separated controllers and one module inside the app.js file and put all stuff together (custom filters, directives, factories...)
Now I want to separate things in diferent files (or maybe folders too).
How can I do this?
angular.module('app', []).
controller('listController', function ($scope) {
...
}).
controller('manageController', function ($scope) {
...
}).
factory('Api', ['$resource',
function($resource) {
return {
...
};
}]).
filter('formtaData', function(){
return function(data, modo){
...
}
}).
Other issue is that my controllers have different dependencies and in the actual way I have to include them all in my module (and scripts on the page) even if a page don't need them.

appConfig.js
angular.module('app', [dep1, dep2]);
ListController.js
angular.module('app').controller('listController', function ($scope) {
...
});
DetailsController.js
angular.module('app').controller('manageController', function ($scope) {
...
});
apiService.js
angular.module('app').factory('Api', ['$resource',
function($resource) {
return {
...
};
}]);
formatDataFilter.js
angular.module('app').filter('formtaData', function(){
return function(data, modo){
...
}
});

You can do it in this way
templates/
_login.html
_list.html
_manage.html
app/
app.js
controllers/
ListController.js
ManageController.js
directives/
SomeDirective.js
services/
ApiService.js
AnotherService.js
filters/
FormtaDataFilter.js
In app.js you can write something like this:
app.config(function($routeProvider){
$routeProvider
.when('/list', {
controller: 'ListController',
templateUrl: 'templates/_list.html'
})
.when('/manage', {
controller: 'ManageController.js',
templateUrl: 'templates/_manage.html'
})
.otherwise({redirectTo: '/'});
});

The above answer is correct however I usually assign the angular module to a literal to avoid typing the full name every time.
var angularApp = angular.module('app', [dep1,dep2]);

Related

Angular Js controller not firing with routes

I am having a problem with AngularJS, where suddenly one of my controllers refuse to execure.
I load it with route, and i know the route is loaded as the html page attached is requested and inserted into the ng-view div i have.
My routes
when('/products/', {
templateUrl: 'app/components/products/products.html',
controller: 'productsController'
}).
when('/products/:productId', {
templateUrl: 'app/components/products/product.html',
controller: 'productController'
}).
I did not see any problems in my controller so i tried replacing all content with just a simple console log, and yet it do still not execute.
angular.module('DietPlanApp').controller('productsController',
['$scope', function ($scope) {
console.log('Get my products!');
}]);
My other controller productController workes just fine.
angular.module('DietPlanApp').controller('productController',
['$scope', '$routeParams', '$location', 'productService', 'userService',
function ($scope, $routeParams, $location, productService, userService) {
productService.getProduct(userService.getUserToken(), $routeParams.productId, function (data) {
if(data.result) {
$scope.product = transferToPortionSize(data.product);
} else {
$location.path("/products/");
}
});
$scope.save = function () {
productService.save(userService.getUserToken(), transferToUnitSize($scope.product));
$location.path("/products/");
};
$scope.delete = function () {
productService.deleteProduct(userService.getUserToken(), $scope.product.id);
$location.path("/products/");
};
}]);
And i have verified that the js files for productsController is loaded correctly in the HTML head, in the same way productController is.
It looks like the result of a namespace collision. You are overwriting productsController in public/app/components/users/authController.js.
It was probably the result of a copy/paste that your forgot to rename. That seems like the most likely culprit.
See the screenshot here.

Keeping controllers in different files not working in Angular

I am currently defining my global module in my routes.js, but for some reason the other controllers are not being created and I keep getting errors that say that my main app module 'LiveAPP' is not available. Here is my code:
routes.js
angular.module('LiveAPP', ['ngRoute'])
.config(function($routeProvider, $httpProvider) {
$routeProvider
.when('/', {
templateUrl : '/home.html',
controller : 'mainCtrl'
})
.when('/signup',{
templateUrl : '/signup.html',
controller : 'signUpCtrl'
})
.when('/artist',{
templateUrl : '/artistpage.html',
controller : 'artistCtrl'
})
})
mainCtrl.js
angular.module('LiveAPP')
.controller('mainCtrl', ['$scope','$http', '$location',mainCtrl]);
function mainCtrl($scope,$http,$location){
$scope.somefunc = function(artistname){
dataFactory.ArtistfromSpotify()
.success(function(data, status, headers, config){
console.log(data)
})
}
};
signUpCtrl
angular.module('LiveAPP')
.controller('signUpCtrl', ['$scope','$http',signUpCtrl]);
function signUpCtrl($scope,$http){
$scope.user = {
email:'',
password:''
}
$scope.postreq = function(user){
$http({
method: "post",
url: "/signup",
data:{
user_username:user.email,
user_password:user.password
}
}).success(function(data){
console.log("User posted to the database")
});
};
}
artistCtrl
angular.module('LiveAPP')
.controller('artistCtrl', ['$scope',function($scope){
$scope.myRating =
{number:3}
}])
.directive("rateYo", function() {
return {
restrict: "A",
scope: {
rating: "="
},
template: "<div id='rateYo'></div>",
link: function( scope, ele, attrs ) {
console.log(scope.rating.number)
$(ele).rateYo({
rating: scope.rating.number
});
}
};
});
I was under the impression that I could retrieve the main liveAPP module and add controllers in other files by using angular.model('liveAPP').controller(...) For some reason it's not working. Anyone have any idea?
To elaborate on my comment above, when you re-use the same module across files, you need to load the files in the right order to satisfy dependencies as well as ensure the module is created before being used.
An easy way to avoid this problem is to specify one module per file. For example
mainCtrl.js
(function() {
angular.module('LiveAPP.main', [])
.controller('mainCtrl', ...);
})();
and in your routes.js
(function() {
angular.module('LiveAPP', [
'ngRoute',
'LiveAPP.main'
])
.config(function($routeProvider, $httpProvider) {
$routeProvider.when('/', {
templateUrl: '/home.html',
controller: 'mainCtrl'
})...
});
})();
It's likely that your html file is including the js files in the wrong order. You need to make sure that routes.js appears first in the html.
You need to change signUpCtrl.js to
angular.module('LiveAPP.controller', [])
.controller('signUpCtrl', ['$scope','$http',signUpCtrl]);
and inject LiveAPP.controller to your global module
angular.module('LiveAPP', ['ngRoute', 'LiveAPP.controller'])
You cannot have LiveAPP in more than one module. Make the same updates on all of your controllers and inject that module names in routes.js

RouteProvider uses resolve property from another route definition

I've got stuck with the following route configuration:
app.config(function ($routeProvider) {
$routeProvider
.when('/common/query/:query', {
templateUrl: 'common.html',
controller: 'UsualResultsController',
resolve: {
UsualResults: usualCntrl.performSearch
}
})
.when('/people/query/:query', {
template: 'people.html',
controller: 'PeopleResultsController',
resolve: {
PeopleResults: peopleCntrl.performSearch
}
})
.when('/people/query/:query/department/:department', {
template: people.html',
controller: 'PeopleResultsController',
resolve: {
PeopleResults: peopleCntrl.performSearch
}
})
.otherwise({
redirectTo: '/'
});
});
and it appears that every route switching is resolved with the 'resolve' object from the last definition.
Here is a simplified plunkr.
Actually, I understand that that in routing order matters and all regex paths should be defined after static paths, but couldn't apply it to my situation.
Moreover, I suppose that the last two route definitions could be combined into one, but again I couldn't grasp, how to achieve it.
I'll be grateful for your help, guys!
app.controller does not return the controller, but the module (same as angular.module).
In your example the following:
peopleCntrl.performSearch = function($timeout, $q) { ... };
Will replace the the function defined by:
usualCntrl.performSearch = function($timeout, $q) { ... };
Since both peopleCntrl and usualCntrl refer to the same module object.
While probably not the cleanest solution, it will work if you don't use the same name for the functions.
Another solution would be the following:
var usualCntrl = function UsualResultsController($scope) { ... };
app.controller('UsualResultsController', ['$scope', usualCntrl]);
usualCntrl.performSearch = function($timeout, $q) { ... };
Demo: http://plnkr.co/edit/jx6HYDXggsaq3qMOdF8c?p=preview

When use module to register controllers

I have two functional code to register controller with Angular.
The first code is:
In app.js:
var app = angular.module('myapp', ['...']);
app.config(...
$stateProvider
.state('first', {
url: '/first',
templateUrl: 'first.html',
controller: 'myController1'
}).state('second', {
url: '/second',
templateUrl: 'second.html',
controller: 'myController2'
});
);
In myControllers.js
app.controller('myController1', function(){
...
});
app.controller('myController2', function(){
...
});
The second code is:
In app.js:
var app = angular.module('myapp', ['...', 'myControllers']);
app.config(...
$stateProvider
.state('first', {
url: '/first',
templateUrl: 'first.html',
controller: 'myController1'
}).state('second', {
url: '/second',
templateUrl: 'second.html',
controller: 'myController2'
});
);
In myControllers.js
var myControllers = angular.module('myControllers', []);
myControllers.controller('myController1', function(){
...
});
myControllers.controller('myController2', function(){
...
});
What is the best solution ? why use module to contain several controllers ? Thank you.
A module in Angular is a way to logically package up related code into chunks. These chunks can be composed later (think 3rd party library in other languages).
This is typically how you include external Angular code (from github etc) into your project. The external project creates a module for you to use as a module dependency. This is the angular.module('myApp', ['myDependency']) way.
This is an optional feature, but can be useful on large (or naturally segregated) projects.
If you don't have a need for a module. I'd suggest you use the simpler (first) solution.
Module Documentation.

Controlling multiple views in one controller in AngularJS

Following the MVC pattern, one controller should be able to handle multiple views in AngularJS.
E.g. I have one view for showing all users and one for creating a new user. My $routeProvider (excerpt) looks like this:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/showusers', {
templateUrl: 'partials/showusers.html',
controller: 'userController'
}).
when('/createuser', {
templateUrl: 'partials/showusers.html',
controller: 'userController'
})
}]);
Both views share several methods such as retrieving all user attributes. These shared methods are accessed through a factory.
The userController (excerpt) currently looks like this where Users is a factory:
angular.module('supportModule').
controller('userController', function($scope, Users) {
var init = function(){
$scope.users = Users.getAll();
$scope.attributes = Users.getAttributes();
}
init();
})
The problem is: I don't need to request Users.getAll(); when I'm on the createuser view.
Of course, I could easily parse the route by using $location, the $routeProvider or pure JS and then conditonally call methods - but I figure there is a more elegant and efficient way in Angular :)
Something like in typical MVC frameworks where one controller has many actions - one for each view.
So my question:
How to elegantly call methods based on the view in a controller which controls more than one view?
You could use resolve: when setup $routeProvider to pass values to a controller depending on the matched route.
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/showusers', {
templateUrl: 'partials/showusers.html',
controller: 'userController',
resolve: {
ctrlOptions: function () {
return {
getAllUsers: true,
};
}
}
}).
when('/createuser', {
templateUrl: 'partials/showusers.html',
controller: 'userController',
resolve: {
ctrlOptions: function () {
return {
getAllUsers: false,
};
}
}
})
}]);
and then in the controller, you can inject item specified in resolve: like this:
app.controller('userController', function ($scope, Users, ctrlOptions) {
var init = function () {
if (ctrlOptions.getAllUsers) {
$scope.users = Users.getAll();
}
$scope.attributes = Users.getAttributes();
};
init();
});
Hope this helps.

Resources