I am developing an Angular SPA and I am currently in the design phase. I have created a sample architecture which I am planing to use in my SPA but I would get some feedback because I want the architecture to be scalable and maintainable. I have tested this architecture out and it works so far.
My Current Architecture:
- I have "Main" module where my
ngRoute
resides and from there I will control my apps routes. - I have created a separate module for each distinct functionality of my app for example (DashboardCtrl, AdminCtrl, blogCtrl etc)
- As its an SPA and its better to bootstrap only 1 angular app in the html page I bootstrap (
ng-app="mainApp"
) on the front-end. But I add all other modules within the main module as dependencies.
Important:
As its an SPA I am using resolve
property of ngRoute to get the data from the server before loading the view and then passing the resolved data to a specific controller responsible for that functionality.
Main Module:
var app = angular.module('app',['ngRoute','app.blog','routeService']);
app.config(function($routeProvider) {
$routeProvider
// route for the home page
.when('/', {
templateUrl: '/overview.html',
controller: 'mainCtrl'
})
// route for the about page
.when('/blog', {
templateUrl : '/blog.html',
controller : 'blogCtrl',
resolve: {
myDta: function(dataFetch){
return dataFetch.getProposals();
}}
})
// route for the contact page
.when('/bios', {
templateUrl : 'bios.html',
//controller : 'contactController'
});
});
app.run(['$rootScope', function($root) {
$root.$on('$routeChangeStart', function(e, curr, prev) {
if (curr.$$route && curr.$$route.resolve) {
// Show a loading message until promises are not resolved
$root.loadingView = true;
}
});
$root.$on('$routeChangeSuccess', function(e, curr, prev) {
// Hide loading message
$root.loadingView = false;
});
}]);
app.controller('mainCtrl',function($scope){
});
Blog Module:
var blog = angular.module('app.blog',[]);
proposal.controller('blogCtrl', function($scope, myDta){
// This is where I will handle all the logic for blogs. Will have functions calling blog service which will call the server and GET or POST data.
$scope.prop = myDta;
});
HTML:
<html lang="en" ng-app="app">
<script type="text/javascript" src="./js/app.js"></script>
<script type="text/javascript" src="./js/blog.js"></script>
<script type="text/javascript" src="services.js"></script>
Do you think architecture or structure is good enough to put into production? My app is grow slowly as I will adding a lot more functionality so I want to make sure the structure I create is maintainable and scalable.
2 Answers 2
Nop you have something wrong here, if you really expect your code base to grow a lot you should explode the router configuration in each module.
This mean that the module app.blog
should declare itself the route /blog
and so on.
Same for templates, you should at least have a dedicated subfolder for your module to have something like
- blog/blog.html
- bios/bios.html
Because over the time you will have way more than one template by module.
Finaly don't forget that some templates won't depends on functionnality but on components/directive, those should be isolated in specific modules if they aren't specific to only one module.
For production, you usually minify your code to have in the end only one single file to load. This decrease a lot the first loading time of your page.
EDIT : here some example :
app.js
var app = angular.module('app',['ngRoute','app.blog','routeService']);
app.config(function($routeProvider) {
$routeProvider
// route for the home page
.when('/', {
templateUrl: '/overview.html',
controller: 'mainCtrl'
}) // i don' know about this one, maybe move it under blog
// or in another module if it's not specific to blog
.when('/bios', {
templateUrl : 'bios.html',
//controller : 'contactController'
});
});
blog/blogs.js
angular.module('app.blog',['routeService'])
.config(['$routeProvider', function($routeProvider){
// route for the about page
$routeProvider.when('/blog', {
templateUrl : '/blog/blog.html',
controller : 'blogCtrl',
resolve: {
myDta: function(dataFetch){
return dataFetch.getProposals();
}}
})
}])
blog/blog.ctrl.js
angular.module('app.blog').controller('blogCtrl', ...);
Note : Usually every controller / service are splitted in their own file.
Maybe not an complete answer. But what me really helped was the Angular StyleGuide By John Papa.
Overall it's a great start but I have some remarks:
Controller As
Try using controller as syntax. in particular when using nested views. In this way you can reference variables and functions on a specific controller.
<div ng-controller="BookController as book">
{{ book.title}}
</div>
This Keyword
When using controller as syntax the controller needs to use this keyword instead of $scope.
function BookController() {
var vm = this;
vm.title= {};
vm.deleteBook= function() { };
}
Injection
When using minification you will get errors on the injection parameters you need to mannually specify the parameters.
angular
.module('app')
.controller('BookController', BookController);
BookController.$inject = ['books', 'data'];
function BookController(books,data) {}
self executing anonymous functions
Try to give every controller, route, config in a seperated file so you can use self executing anonymous functions. Enclose every controller,route, etc like this example. See this answer for more info.
(function () {
'use strict';
angular.module('app').controller('BookController', BookController);
})();
Explore related questions
See similar questions with these tags.
.component()
and.directive()
and avoid$scope
where possible (since 1.5 its only required for edge cases). And really dont usengController
in your templates at all.