Wednesday, July 24, 2013

Responsive Layout with AngularJS

Context

Over the last month or so, I have been diving into the maelstrom of web development. That being said, I'm new to JS, AngularJS and HTML5 in general. I have found it considerably hard-going to determine the "best" path to comprehensively learn the trade of developing a web application. The purpose of this post is to submit a question/idea about one particular aspect that is still not clear to me and get feedback/direction from more experienced developers.


The Problem (with Media Queries)

One of the first concepts I came across that started to put my concerns about designing for the browser at ease was responsive design. The concept is great, but the practice is dissatisfying to me. In trivial cases (static web pages), changing the styles of my components based on screen sizes demonstrably does the trick, but when I started to try to apply this approach to even simple applications, it quickly felt very wrong. Showing/hiding components from a style sheet is, to me, supplementing content-structure changes. Additionally, using logical expressions in a style sheet seems off the wall and out of nowhere. The problem boils down to this for me: I cannot look at my template and tell what content will be present and when. That's a red flag to me that my application is going to get difficult to manage quickly.


HTML is the Template

AngularJS allows you to realistically treat your HTML markup as your template. A significant result of this is that you can look at your template and see how it will become your view into your data model. So far, there is no need to refer to a style-sheet in order to understand what your view will be. So, can we leverage the flexibility AngularJS gives us to prevent this awkwardness? Yes, I'm confident there is a way. Do I know the best way? No, but I have an idea.


A (better?) Solution

As soon as I start hiding and showing elements from my style-sheet, I think that indicates structure change, which should be the template's job. So, What if we had a HTML component that indicated what its contents would be based on its width, for example... Something like:



Ignore the "resp-div" for the moment, I'll get to that, but notice how breakpoints are described on the element and corresponding templates are also identified here. The benefit here, I think, is that you can tell from looking at the template what the contents of that div will be at different break points. If this is more appropriate than putting this info into the styles, how could we achieve this?

Angular provides a tool called a Directive which:
...are a way to teach HTML new tricks
To make this work, we'd need that div to behave the way it describes itself. This can be done with a very simple directive:



I tried to comment the code well, but let me describe what this is doing. The directive defines a component that will change its contents based on which break-point its width falls within. It defines a small set of breakpoints (in this case small and med) and corresponding templates that can be passed via the attrs argument of the link() function. When the (window) width changes, checkBreak() is called and checks if we have entered a new break-point. When a new break-point is hit, the scope.template value changes, triggering the ng-include directive to insert the corresponding template into its element (a div). It's very simple and very re-usable. I can use it on any container and even include a "default" template when no breakpoints are satisfied. So I can use the exact ideal syntax I proposed earlier:



I can simply change the break-point or template values in the HTML tag and the Directive will respond appropriately. Additionally, my Directive could have better, more robust parameters for breakpoints, but I think these two demonstrate the concept. 

Now my styles can be applied to the appropriate templates and I never have to look at my style-sheets to determine the structure of my view. 


Notes

A couple things are not ideal:

  • I'm not sure how to trigger on the element itself's width changes, so I had to inject the $window and bind to its resize changes.
  • I'm not sure if clientWidth is the appropriate value to check


Nothing is preventing "view/small.html" and "view/med.html" from sharing and using some of the same components, so we have not painted ourselves into the corner of having to rewrite different templates for different screen sizes. We are just composing them differently. Now, I can look at "view/small.html" and tell which components are included, instead of always including every component and using CSS to hide and show them when necessary.

Note that this allows you to have a responsive layout within sub components and not only based on window size.


Conclusion

Ok, so there are my thoughts. I'm really hoping to get guidance and feedback on this. I apologize in advance if this has already been covered, I have been able to find little discussion concerning AngularJS and Responsive Design.

3 comments:

  1. If you cant find anything on google then maybe its because css fits itself nicely to responsive design. However said you are in fact creating a m-dot and normal site using the angular way. I think you might be giving yourself a maintenance headache as you will have three places to change any html code etc. One of the strong points of responsive design is you have one html template and one css to control the breakpoints. A good idea however I cannot see the merits of using this in practice...

    ReplyDelete
    Replies
    1. I briefly mentioned that, using AngularJS, small.html and med.html can each include the same sub-components (using ng-include for example), so there is no need to duplicate code, but for different breakpoints, you can compose those elements appropriately. This is what showing and hiding elements via css fakes. The problems are:
      A) you just downloaded a bunch of HTML you may not need
      B) you have to refer to the "stylesheet" to determine the structure of your application, which is clearly not ideal; we're not talking about styles anymore, we're talking about structure.

      So if html re-use is actually achievable this way, are there other benefits of media queries over this approach?

      I'm not sure what m-dot is, but I'll look into it, thanks.

      Thanks for your input!

      Delete
  2. This is interesting.. I will have to look at it harder to understand it. What I want to do is not have HTML hidden that I am not using attached to scope/controller that is sucking out resources..

    ReplyDelete