An awesome setup for your AngularJS project (2/3)

This is post #2 of 3 to explain about fsstatic2. Beware: it may change forever how you approach web development. 🙂

So, let us continue.

index.html – How the main application works

Routing

There’s not much to say here, it just applies basic ui-router configuration to make a Single Page Application.

  • fs_main.js is responsible for setting up the routing rules
  • Each route has a template that is as simple as <fsissue></fsissue>
  • The toolbar has some <a ui-sref=”statename”> links on it that activate different routes

More details in the video below

Now, notice that even if we had chosen not to build an SPA, we could still use a similiar structure. For example, instead of having an SPA in the index.html file, we could have more pages, like home.html, issue.html, and so on. The code on such a page, say: home.html, could look like:

<body ng-app="fs_main" layout="column" ng-controller="FSMainCtrl">
  <md-toolbar layout="row">
    <fstoolbar></fstoolbar>
  </md-toolbar>
  <div layout="row" flex>
    <div layout="column" flex id="content">
      <md-content layout="column" flex class="md-padding">
        <fshome></fshome>
      </md-content>
    </div>
  </div>
</body>

 

Can you smell another good practice here? Right…

Good practice #2: Everything is a component.

Our application should be structured as a composition of components, not very different from each other in terms of architecture. In our case I’ve decided that each component is a restrict=”E” directive. The result is a very standardized way of doing things. People on your team will be able to understand each other’s code faster because everything has more or less the same structure.

Mock api

Don’t talk to URL’s directly. Instead, hide your backend URLs behind a stateless Angular service with a bunch of methods that return promises.

Then, make an alternative implementation that pretends to talk to the backend, but actually generate hard-coded data in javascript and resolves promises with $timeout. This takes us to the next good practice:

Good practice #3: Have a mock API.

This will allow you to have an environment where you can switch between a full stack environment and front-end-only environment. This ability will most likely boost the speed on your development process.

Authentication

Does it even make sense talking about authentication if we don’t have a real backend yet? The answer is YES. The front-end plays a big part in the authentication process and we can go and implement the client part beforehand, just like we can do it with anything else, really. We don’t even need a video this time (but you will have to take a look at the code as you keep reading!)

FSAuth’s (fsauth.js) responsibility is to provide information about the current user to the rest of the application. Whoever needs to know if we are authenticated can just call FSAuth.authenticated(). If they need the current username, then FSAuth.user.username. The <fslogin> directive (fslogin.js/fslogin.html) has a viewmodel (FSLoginModel) that is activated in the login screen. When the user fills the login form and hits OK, FSLoginModel.login() will ask our “backend” to authenticate us – FSApi.login(username, password) – and then give FSAuth the currently logged user by invoking FSAuth.set_user().

Now there’s an important detail here. We want the real backend implementation of FSApi.login(u, p) not only to return a json with information about the current user. This particular response also needs to come with a set-cookie header that will tell the browser to store a session variable in a cookie, which will be sent in all subsequent requests. That way, the backend can know who is the user making those requests. This is what is supposed to happen when we call FSApi.whoami() – if the request comes from an authenticated user, this should return that user data, otherwise the response must say something like “Oh, you’re just nobody :-)”.

Now FSAuth, during its initialization (see _check_for_authentication) will call FSApi.whoami() and store the current user in itself if it is authenticated. The current mocked implementation of FSApi.whoami() will always return an authenticated user – this is arbitrary. So if the user refreshes the page, FSAuth will still know who the current user is.

Our main <fstoolbar> (fstoolbar.js/fstoolbar.html) is also dependent on FSAuth. You can notice that the toolbar’s right side will show different content depending on the result of FSAuth.authenticated().

The logout feature is left as an exercise for you to understand alone🙂

So, the only piece missing in our authentication process is the backend. If we have correct, real implementations for FSApi.login(u, p) and FSApi.whoami(), it should work for real.

Template URLs

Anywhere we include a template we have a path prefix before the template URL. For example, the templateURL for the <fslogin> directive is FS.BASE_URL+’login/fslogin.html’.

This will give you more flexibility to move included .js files relative to the main html file. Let me show you.

And don’t forget this also goes for templates included with ng-include.

This is important, so let’s add it as another good practice to our list:

Good practice #4: Plan for some flexibility in your templateURLs.

This can help you have with the dev vs. prod build differences, and it will also save you some trouble when you have to move stuff around.

todo.js – A detailed example of how to make a component

The DOCS page has a <todo> component that illustrates how to make a simple component. This doesn’t relate to any feature in FS, it’s just that I didn’t have a better idea for a sample component.

The main recommendation that I give to everyone using angular is this: do not use the $scope as a model. It’s better to put the model implementation inside a service. Let me show you.

Of course, this is another good practice.

Good practice #5: NEVER use the $scope as a view model. Put your models into services.

I can’t stress enough how important this is. Having your view models inside services allows you to have a much cleaner code as a result of a clear separation of concerns. As a bonus, it also makes your code very easy to right unit tests for.

Your screen needs some AJAX action? No problem, inject an API service into its viewmodel and let the model handle the AJAX for you. Need a loading-please-wait animation? Sure, have a boolean attribute in your model that tells the template when to display it. But keep your distance from the $scope object. Trust me, the less you rely on it, the better off you are.

If you look at the rest of the directives in the src/ folder you can see that I intend to apply this same pattern to all components.

Some other detail that you might have noticed is the way that the code inside the TODOModel is laid out:

var m = {
    newtodo: '',
    adding: false,
    todos: [],
};

angular.extend(m, {
    add: add,
    remove: remove,
});

There’s actually another good practice behind this:

Good practice #6: Let me see the API first.

You can see what TODOModel is supposed… er… to do (:P) after a quick glance on just the snippet above, right? It’s a plain object with those 3 attributes that make up its state, and those two operations that change it. Seeing the attributes and operations at the top allows me to realize faster what are this object’s responsibilities.

All right, this is enough for post #2. In the next and last post we’ll cover.

  • docs.html – A component catalog AND a playground environment.
  • Tests: running and debugging
  • test_todo.js: how to write good tests

One last thing: please repeat with me one last time (out loud is better):

I will never use the $scope as a viewmodel. 

Good.

Just to be sure🙂

3 comentários em “An awesome setup for your AngularJS project (2/3)

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s