How to do nested views in AngularJS (Hint: Don’t)

Starting to use AngularJS in November was an eye-opening experience. Angular does application architecture like would have done but with a level of polish and refinement that I could never have achieved.

That said there was an issue I encountered early that also comes up from time to time on the AngularJS mailing list, namely that of nested views. Angular has facilities to watch the location/history and control an ngView directive in response, but it only supports one ngView per app. How could you build a nicely structured application with that when you have nested levels of hierarchy?

It took my a while to realize that I was think in the wrong direction, coming from a Backbone project and doing years of Rails development.

Views are not what you use to structure your application!

In fact, views are more of a crutch, a shortcut, to create structures similar to traditional websites, only with angular as a driver. When developing a web application, the way to deal with complex interfaces is to use, in combination:

  1. Scope objects/variables that store your desired view state explicitly
  2. ngSwitch directives on this view state
  3. Directives to include custom templates/perform complex DOM manipulation behavior

Stop thinking of your application in terms of views that need to be loaded. That kind of thinking aligns better with imperative frameworks but doesn't work well in angular.

Think instead of components that fulfill a particular purpose. Define the components as directives, passing objects into your components, manage view state explicitly using simple objects or single variables in your scope. Angular is declarative and data-driven at its heart. Therefore decisions over what to display belong in the directives really, either as part of your linking functions or as ng-switch directives in the templates. They should never be managed in a controller although that seems to be what many people instinctively try to do when getting started with angular.

Defining multiple views that are manipulated imperatively goes against the core concept of angular.

Those approaching angular with concepts from other JS frameworks will have a hard time realizing the full power of Angulars clean separation of concerns.

UPDATE: I've written a follow up to this Article here

10 Responses to “How to do nested views in AngularJS (Hint: Don’t)”

  1. Maximilian says:

    Thank you! Very helpful article to help me transition from Backbonejs/Marionettejs to angular!

  2. Zoga says:

    Great article! This is something that confused me too since I also come from rails/backbone world. Thanks!

  3. nik says:

    great work here… doing what you explain in a very elegant way : https://github.com/angular-ui/ui-router

  4. Maximilian says:

    @Jan: what is your opinion about https://github.com/angular-ui/ui-router
    Your advice is not to use nested view, ui-router is doing nested views?

  5. rtinfow says:

    Not many options when you are swiping from one view to an updated view of the same template. The swipe transition requires two concurrent views.

  6. Jan says:

    I was referring to ngViews. What you describe has nothing o do with ngView really.

    @Maximilian: If you want/need traditional “views”, ui-router is definitely an improvement over the built-in router, but as I said, I consider that a flawed approach for complex apps.

  7. jeme says:

    I don’t really get this post…

    You say that one should do: “3. Directives to include custom templates/perform complex DOM manipulation behavior”… instead…

    But… knowing the inside of ng-view/routing and ui-router, this is exactly what they do, sort of anyways… The difference is just that it allows for using different templates which happens to be defined from the outside… And the “DOM” manipulation behavior should solely be defined by the directives making up that template, not the attached to that “view”…

    In one way or the other you will have to bind an particular “application state” (and there by view state) up on an url, unless you don’t wan’t to leverage bookmarking, history and deep-linking (which is one of the most awesome things about web-applications), and projects like UI-Router makes that much easier to manage IMO…

    The only alternative I see is that you begin to handle either “location changed” or “route changed” your self, and do all the the things those project in your own code, but I really need a good example to be convinced that that isn’t much harder to maintain… (Having been in something similar)…

    I’m intrigued by the idea, but I can’t see how you won’t just end up with something similar… So a more in depth post with a through example would be great. After all, more thoughts on the same problem is always welcome…

  8. Jan says:

    Thanks for your feedback.
    I will try to write a follow-up post to go into more detail and give an example.
    But let me quickly address your first point/question:

    The main idea I tried to get across is that people should stop thinking of their apps as a collection of pages, or view, nested or not.

    Only making full use of directives leverages the full power of AngularJS or similar approaches because they let you split up the app in reusable components at a much finer level than the page/view.

    I see that this got a bit lost in my argument, which I admittedly not spent much time on. It was originally a gut-response to a post on the AngularJs mailing list.
    At that time ui-router did not exist or I did not know it yet and the builting routing/ngView was really confusing the hell out of a lot of people.
    Or course, with the way the router attaches controllers etc. to a view you can achieve much of the same you do with nested directives.
    The outcome might be similar, but the model behind it is slightly different.

    See, this is a quote from ui-routers documentation: “A state describes (via the controller / template / view properties) what the UI looks like and does at that place.”
    There’s only so much state you can attach to a URL, and blindly following this path might lead newcomers to believe that this is all they can really control.

  9. jeme says:

    Well I will be looking forward to reading that… Especially because to me there is no difference between a view and any other directives in angular. (The implementation between e.g. ng-include and ng-view is also stunningly similar with largely only the source of the template to differ and a view allows a controller)

    That said, the term “view” and “nested-view” is probably misplaced here, but I guess it will be what people can best recognize and understand in comparison, and I guess that rises allot of confusion about “what they really are” and how they can be used…

    But all that you can do in a template included by e.g. ng-include you can do in a template a “view”…

  10. Jan says:

    I’ve written a follow-up now: http://jan.varwig.org/archive/angularjs-views-vs-directives

    Please continue the discussion there