Hey,
I’ve been coding with AngularJS for some time. I still like BackBone very much, but I’ve come to understand that BackBone is very simple and minimalistic. You gotta do most of the job, which is not very productive. AngularJS is a very productive framework that lets you organize the code if you know what you’re doing. However, it’s very easy to fuck it up and end with the same (or worse) spaghetti code that you wanted to avoid by adding and MVC (not really :P) framework.
So, let’s get down to business. After trying different approaches, I’ve come with the approach that best suits me and I think it’ll suit most of you guys as well.
So, what would be a very good example of this.
You go to the URL / and you get a page in the following way:
Then, you login and you go to /sports and you get:
Then, you go to /players and you get:
So, this example covers most of the different approaches and pages of a regular WebApp. So, how would we approach this?
1) The first thing we need to do is define the URL router and the controllers. We’d have one main controller for each
var module = angular.module('basicsite',
['ngResource']).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/',
{templateUrl: '/js//views/main.html', controller: 'MainCtrl'}).
when('/sports',
{templateUrl: '/js/views/sports.html', controller: 'SportsCtrl'}).
when('/players',
{templateUrl: '/js/views/players.html', controller: 'PlayersCtrl'}).
otherwise({redirectTo: '/'});
}]);
2) Now, you have the main routes, templates and controllers defined. As you can see, Footer is used in several pages and is always the same. Header is used in several pages and is almost the same. It just changes if user is logged in or not. As we want to use the footer several times and we don’t want to define it so many times, we’re going to define a directive for it. This directive has its template and it can have a controller in case it needs it. Otherwise, we can just have a link method that will be run when added to other HTML.
module.directive('footer', function () {
return {
restrict: 'A', //This menas that it will be used as an attribute and NOT as an element. I don't like creating custom HTML elements
replace: true,
templateUrl: "/js/directives/footer.html",
controller: ['$scope', '$filter', function ($scope, $filter) {
// Your behaviour goes here :)
}]
}
});
<div>
<p>
This is the footer. Yeah baby. Coyrhing and all of that!
</p>
</div>
3) Almost same things happen with Header. We’re going to use this in many places but it has some differences. For this cases, I use AngularUI ui-if directive which is awesome, as that’s exactly what we want. Depending on something we show one content or another. Check it out clicking here
module.directive('header', function () {
return {
restrict: 'A', //This menas that it will be used as an attribute and NOT as an element. I don't like creating custom HTML elements
replace: true,
scope: {user: '='}, // This is one of the cool things :). Will be explained in post.
templateUrl: "/js/directives/header.html",
controller: ['$scope', '$filter', function ($scope, $filter) {
// Your behaviour goes here :)
}]
}
});
<div>
<p>
This part of the hader is always here
</p>
<p ui-if="user">
User is logged in :D
</p>
<p ui-if="!user">
Hey buddy, log in! Be cool
</p>
</div>
Here, there are 2 important things to note. First the scope attribute, where we put user: “=”. What does this mean? This will add the user to out scope ($scope.user). It will create a bidirectional asociation with the value supplied in the HTML as a parameter. If the user doesn’t put anything, it will be asumed that the name of the parent scope variable is user (Don’t do this, it’s impossible to understand :)). What does this mean in english?
If you put <div header user=”userModel”> in the template HTML for the controller, it will mean that $scope.user in the Header directive will be always the same as $scope.userModel in the Controller. If one of them changes, the other will change. This is really cool! So, then, we can actually check if this $scope.user exists or not in our template with ui-if. And as it’s a bidirectional asociation, if $scope.userModel changes from being undefined to a user (He’s logged in somehow), the hader will change automatically. This is freaking awesome! Binding rules
4) All we need to do now is create the main templates for each controller using our directives.
<div>
<div header></div>
<div class="main-content">
<p>
Here it's this page specific content :)
</p>
</div>
<div footer></div>
</div>
<div>
<div header user="player"></div>
<div class="main-content">
<p>
Here it's this page specific content :)
</p>
</div>
<div footer></div>
</div>
<div>
<div header user="userModel"></div>
<div class="main-content">
<p>
Here it's this page specific content :)
</p>
</div>
</div>
And we finished. We’ve an app up and running with a header, a footer and specific content for each page. Now, every time we add a page, all we need to do is just create the controller, create the template and add the header and footer if needed and that’s it.
I’ve not put it in this example, but what if the directive and the controller need to talk? One way is the scope: “=” that I showed here. Other way is through events. This way, they can talk but they’re not coupled which is really cool.
So, what do you guys think about this approach? What do you think about angular?