Proposed Angular’s WebPage structure

posted in: AngularJS | 6

Guideline on creating pages on AngularJS. This applies for angularizing per page and not a SPA.

Basic Structure
The basic idea is to have **one Main Controller** which will have in the scope all the common models and functions that will be used troughout the entire page. In Angular, if you have a child controller, that controlller’s scope will use prototypal inheritance with the MainCtrl. This means that the scope of the child controller will have all the models and functions from the MainCtrl.

Then, the page will have one controller per each main “view”. For example, if you have a page with 5 tabs, each of this tabs is a main view. Each view is different from the other. This views will actually be `ng-view` which means that they will be resolved by `$routeProvider`. So, each time you click on a tab, it actually changes the URL (for example `/properties/spaces`), once that URL changes, the controller defined in the `$routeProvider` will be used together with the template defined. This controller will be the view controller and will inherit from the main Controller.

Inside each view, we’ll be using directives for the different components of the page. If some of this components is reusable (can be used in another page/view), it **MUST** be defined with an isolated scope and it’ll receive via HTML attributes the parameters it needs to work. This ensures that the directive isn’t coupled to the parent as it doesn’t inherit the parent scope, which makes it easy to reuse it.
If the directive we’re using is only to organize code and will not be reused in another view, we **CAN** inherit the parent scope (not making it isolated). However, if you want, you can make them isolated anyway.

Using this basic structure, we leverage scope inheritance and binding to get things done. If you modify a model in a directive, as it was inherited from the parent scope (or given to the directive via attribute if it’s isolated), the parent controller and the view from that controller will actually get notified when this happend and the HTML will be modified by itself.

If we need to also be notified of this changes, we can use the `$scope.$watch` function to watch some model for changes and get notified. This is exactly what the template uses to update itself.
If we were to use events, we wouldn’t have this bidirectional binding, which makes creating with angular MUCH less useful.


Let’s view an example of an app with this configuration.
First, the main HTML will look something like this:

In here you can see we define the MainCtrl and then we define the ng-view to be used with the RouteProvider

Now, let’s see the app.js the app definition:

Here we define for each URL the HTML to be used and the template for that URL.
We then must define all of this controllers remembering that all we set in the MainCtrl will be visible in the rest.
Now, let’s see an example of a directive, in the firstTab.html we have the following:

The first tab controller changes the searchText property of the query model. The query model is inherited from the MainCtrl. The MainCtrl is watching this query object for changes. Once it changes, it fetches some information from the server, and sets that in the valuesData property of the data model. This `data.valuesData` is being sent as a parameter to the pie directive, so as soon as it changes, the directive will be watching it. Let’s see the code of the directive.

In here we define an isolated scope. We set that the data HTML attribute will actually contain a scope variable name and that it’ll create a bidirectional asociation with it. This way, we can actually use a model from the parent scope, without inehriting the whole scope. Then, we set that the `type` attribute is just a string to be set in our current scope.
Then, we watch the data for changes. If it changes and it’s either undefined or it has no data, we hide the pie element. Otherwise, we show it and we plot it using the data.

  • Martin Gontovnikas
    • Jacob Gillespie

      Thought the same thing myself when I first read this – looks like it’s the same author in both places, so no plagiarism here…

  • tromex

    Hello, I’m building my first app (SPA) with this great framework and want to ask you some questions:

    - In my design I also used the MainController approach to control the general state, and handle general errors like $routeChangeError to show messages to the users. My question is: Is better to have the data model (different from application general state) in your MainController OR to define it using a service or factory and call it in each view?

    - My second question is: In your directive ‘pie’ your are using a dependency called ‘$element’ but I can’t see it defined in the ‘ng’ module.

    - Finally I see that you’re using a controller to define the $watch of your directive, this really confused me, I thought this should be defined in the link function. When should I use a controller function and when a link function in a directive?

    Greets from Mendoza, Argentina ;)

    • Martin Gontovnikas

      Hey :).

      1) It depends on each case. If you’re using this models eveywhere, in directives, etc. I’d recommend using a model as a factory or service and inject it on each view

      2) $element is the element itself (DOM element). You’ll be able to inject it without any problem and in there call any method to that element. It’s already wrapped with jqLite or jQuery

      3) In this case you can use either the link or controller. Ideally link is only used when this HTML is linked to the DOM. I try to add behaviour to controller instead of the link, but both will work.

      I hope this helps you :)

      • tromex

        Ok, thanks for your reply :D

  • finestglasses j.

    For the internet vendors casually health professional prescribed cups, you’re going to get these kind of Designer Glasses at means affordable prices than these with the physical retail stores.