Showing posts with label Angular. Show all posts
Showing posts with label Angular. Show all posts

Friday, April 29, 2016

Should we use MVC for modern web applications?

MVC is one of the most commonly used design patterns in web applications. It can be used both with server and client side rendering. Frameworks like ASP.NET MVC and Angular adopted the pattern and made the development extremely easy and straight-forward.

Despite its popularity, I claim that the MVC pattern is no longer the best solution for creating rich and modern web applications.

 

MVC – the good parts

Single Page Applications rule the web with different client side rendering frameworks like Angular, Backbone, React and many more. These frameworks made JavaScript development easier-and by doing so made the client “smarter” and the server “dumber” by mostly being responsible for communicating with the client and data persistence. Most of the applications’ logic moved to the client side.

In order to support this transition the MVC pattern has moved to the client by creating controllers that manipulate data (the model) that is presented in the views. This makes a lot of sense, as opposed to using just jQuery for some simple DOM manipulation and handling all the heavy lifting in the server.

So instead of rendering the view in the server for each request, now it’s extremely easy to render it in the client and give the users a faster and cleaner experience.

“Magic tricks” like two-way binding allow applications to respond quickly to different events and change the appearance of the app accordingly.

Let’s have a look at the Angular docs website. We can easily navigate through the different sections in the website while avoiding a trip to the server for rendering the next page.

That is a classic MVC case. It works great for the “simple” apps where most of the page content is static and the user’s changes don’t affect different parts of the page.

 

However, this is not what rich modern applications look like.

Let’s look at this example. What happens when we increase a product’s quantity? 

 

Four different parts of the page change (the header counter, the notification, the quantity of the product and the cart title).

 

Let’s try to implement it using Angular

Obviously I won’t build the entire app in a single view or use a single controller. That’s the worst practice, since it will break the SOLID principles of development by creating a giant controller that is responsible for EVERYTHING. This will become difficult to maintain over time.

I want my code to be highly reusable and simple to use, which I can achieve with components. Angular provides me with directives and, since Angular 1.5, it also provides components. I will create a controller, a directive and a template (view) for each of the following elements: the header, the notification and the quantity counter. In order to notify the other components that a product was added to cart, I can do 2 things:

  1. Use $rootScope and raise an event on it while subscribing to it on the other components.
  2. Use a shared service to pass the data between the components.

 

MVC doesn’t provide us with an out of the box solution for cross components communication. We need to extend it and create workarounds.

Here we saw just a single use case for cross components communication. For an entire application we’ll have many different events that will be managed using shared services or the $rootScope.

 

Does MVC help?

MVC forces us to separate the logic that is in the controller from the view that is just a template. It sounds like good practice, but if you think about it (and don’t kill me right away) maybe that’s actually not so good.

We are creating components, self-existing components that, like it or not, have their logic coupled to their view. You can’t really change the controller without affecting the view, and vice versa.

That’s alright! The components can be “smart”, they can have logic, handle their state and respond to different events and properties in a different way. So if that’s the case, why do we try to extract the logic and make the view dumb?

Why not create components that define their functions, handle state and create the view in a single class – a real reusable component. This component will use actions to trigger events that will be dispatched through the application and notify other components that something has happened, and allow them to respond if it’s necessary. This pattern is called Flux and it’s used widely with the promising new framework React.js.

clip_image002

Flux introduces three new features that create the necessary infrastructure:

  1. Action – A simple class that defines the events that components may trigger.
  2. Dispatcher – A class that dispatches the events from the Action to the different Stores.
  3. Store – A store catches the events, processes them and then fires a completion event that components may subscribe to.

 

Let’s implement the previous example with React and Flux

image

Here’s a basic Flux file structure. You can find all the parts we discussed earlier here.

The + button will call an action, which will trigger “INCREASE” event.

 

The CartStore will respond to the event, calling to the server and actually modifying the product’s quantity.

 

Then the store will fire a “PRODUCT_QUANTITY_WAS_CHANGED” event to notify who ever listens.

Then each component that subscribed to the event will be notified and will act accordingly.

 

What’s the difference?

Nothing mind-blowing really. However, we don’t need to create a controller and separate it from the view and then subscribe and fire events in order to communicate. We build components that are responsible for themselves. They constantly pass events from and to each other, allowing us to easily change existing behavior, add new components and integrate them with the existing events.

The classic Model View Controller separation seems a little bit redundant, hence it must be completely changed for creating rich and modern web applications.

 

Agree? Disagree?

Share your thoughts.

 

* I want to thank Yonatan Mevorach for reviewing this post.

Wednesday, August 19, 2015

Creating Masked Input Directive with TDD–part2

In the previous post we started implementing the masked input directive. We’ve written tests and the implementation of the directive’s controller. Now it’s time to add the directive itself and of course we’ll start form the tests.

Testing the directive means testing it’s interaction with the UI. These are your integration tests. We’ll want to test the controller logic and the way it reflects in the UI.

First we’d like to test that the directive’s isolated scope has the provided “mask” and “skip” values (keep in mind that in a real application you would test the existence of all the DDO values):

image

Some key notes from this test:

1. In order to test a directive we must create a string that represents its DOM (an element which has the directive attribute i.e.).

2. $compile service parses the element’s DOM and executes the directive function with the provided scope. So the “element” variable is now the directive with all its properties and methods.

3. We can access the scope properties using the element’s “ísolateScope” method.

Now let’s define the DDO:

image

Then we’d like to test that the element’s value will have the provided mask value after the DOM compiles.

image

And now with the link function:

image

In order to change the UI (the element’s value property) you have to call to $setViewValue that is a special angular method that is in charge of setting the value property of the directive element (<input type=”text” value=”this one”/>). $render is called for the UI changes to take place.

Now we add the directive to an html file and actually see all the stuff that we were testing. Add an index.html file, include angular and all the client folder except the spec files!

image

Run it:

clip_image002

That’s what I’m talking about!

All that’s left is connecting our tested (TDD baby) controller functionality to every time the user presses a key.

image

I’ve created a keydown event using the private createKeyDownEvent method and fired it.

The implementation:

image

We subscribe to the keydown event, get the new char, call editMask and if successful re-render the UI.

That’s it! You have a functional masked input element which is fully tested.

clip_image002[5]

As you can see, writing TDD with angular is extremely easy and straight forward. If you are not writing tests then you most definitely should! Just begin, it’s worth it.

Have fun TDDing,

Tuesday, August 18, 2015

Creating Masked Input Directive with TDD–Part 1

In the next two posts I’d like to show you three things:
1. What is a “masked input”.
2. How to create a masked input custom angular directive.
3. And the cherry on top – implement it applying TDD!
So what it is “masked input”?
It allows users to easily enter fixed length input where you would like them to enter the data in a certain format (dates, phone numbers, ids, credit card number and more).
Most of forms out there don’t supply the users any hints about the data’s format and make the users guess it (most of the time the input fields will be  blank textboxes). If there’s a format mismatch then the user will receive an error and will try again.
Using masks allowclip_image003 us to show the users the exact format and force them to enter it correctly.
Let’s implement it!
Remember that we’ll do it using TDD.
So first let’s define the desired API:
image
We want to create a custom attribute directive that will have three properties:
1. Mask – the mask that the user will see in the textbox. These values will be replaced by the user’s input as they type.
2. Skip – an array of chars that we want to be left along with the user’s input like ‘/’ in a date textbox – 01/06/1991
3. Ng-model – the associated model from some controller.
Great! Now after we know our goal we can start writing code.
1. Create ASP.NET Web API project
Add the following nuget packages:
- Angularjs.core
- jasmineTest – this is the jasmine.js testing framework for ASP.NET MVC
- angularjs.TypeScript.DefinitelyTyped
- jasmine.TypeScript.DefinitelyTyped
The last two packages include definition files used generally for TypeScript for the 3rd parties intellisense. However I found that even if you don’t write TypeScript there intellisense is pretty helpful.
clip_image002[6]
Now let’s add a Client directory, index.html file, app.module.js, app.controller.js and a InputMask directory (all the angular code is style accordingly the John’s Papa style guide).
clip_image004[6]
2. Enter TDD
Before we implement the controller we’ll add a spec file to test the controller, we will add a basic test, let it fail and only then implement the controller and the module.
Add a form.controller.spec.js file (this is a style guide naming convention, formControllerSpec.js is also fine). Now we’ll add a basic jasmine test for testing that our controller is defined.
image
Nothing special here: we inject the $controller service in order to get our controller, inject it with a new scope and assert that the controller is defined.
Now let’s add all the files into the SpecRunner.cshtml file:
image
I’ve added angular, angular.mocks, the module and the controller.
The test fails since there’s no module or a defined controller– let’s add them.
First the module:
image
I’m using IIFE to prevent my functions getting into the global scope and prevent the tests get to my private methods.
And the controller:
image
I’m using the $inject pattern in order to make sure that my controller parameters won’t get ruined after minifying the code.
Let’s run the test:
clip_image002
Now let’s add another test to validate that the scope works:
image
Notice that even in js tests I still use the AAA pattern. It makes the tests readable, especially when they get complex.
Run and pass:
clip_image002[5]
1. Adding the directive’s controller
The logic regarding the mask’s chars replacement will be inside the controller (the logic regarding the display will be inside the link function. We’ll get there later).
Add an InputMask directory and place the controller and its spec file in it:
clip_image004
And the first test:
image
I’m placing the specs files near the source files so that the specs will be immediately noticed when someone looks at the solution and so that it will be extremely easy to see that a file is lacking its tests.
Add the controller and the test will pass.
Now let’s start adding some functional tests.
Every time a user enters a letter a controller function must be called in order to edit the mask, it will check the current input length – it shouldn’t be longer than the defined mask and it should replace the mask characters while skipping the values provided in the “skip” array.
Let’s go:
image
And the implementation:
image
Replacing the mask as the user enters input:
image
Notice that the controller sets the ngModel with the mask value on its initialization. We’ll provide the mask value for the ngModel before calling for the editMask method from out test.
The implementation:
image
Now let’s add a test and its implementation for the “skip” characters functionality.
Test:
image
Implementation:
image
Pretty straight forward. Notice how the controller doesn’t do any UI logic– just the way it supposed to be.
In a real life application you should add as many test you can for your controllers in order to achieve maximum code and use cases coverage, in this post (which is already quiet long) we’ll stop here and move towards the next topic – testing the directive.

Thursday, April 9, 2015

Improving Angular.js performance using One Time Binding

In the previous post I explained how the $digest loop works and how to increase performance using the ng-model-options directive. In this post we’ll take a look at ‘one time binding’ feature.

As I mentioned before the $digest loop goes through all the registered watches every time in order to check whether they need to be updated. However not all our scope variables and models should have binding or be updated after they have been initialized, for example: a logo path, a title, names, some constant options that we used ng-repeat for them and so on. All those variables should be initialized and not to be updated until a full page refresh.

One time binding is a feature that was introduced along with ng-model-options in Angular 1.3. In order to set that a scope variable should not be updated all you have to do is add :: before the variable name:

<input type="text" ng-model="name" value="text" />
{{::name}}
{{name}}


Adding it before the scope variable tells Angular not to register a watch on the variable and so decreases the amount of watches for the $digest loop to check which leads to increase in the app’s performance.

Enjoy

Improving Angular.js performance using ng-model-options

Every app has a search ability. Some apps wait for the user to hit “Enter” and then send the search string to the server, others (especially when using Angular) bind every user’s key stroke to a request to the server. In my opinion the second option has better user experience since the user starts to receive results while he is typing and most likely will get what he is searching for before he finished typing the whole search string and he is no more required to press another button after he finished typing.

However if you have a large Database and your search request take more than several milliseconds then there is no use to send a request to the server after every keystroke – the user will not get the relevant results. So how do you control when to send the request to the server?

Ng-model-options

Ng-model-options is a directive that was introduced in Angular 1.3. It has some really nice features:

updateOn:

With the updateOn parameter, we can define which events our input should be bound to. For example, if we want our model to be updated only after the user removed the focus of our input element, we can simply do so by applying the ngModelOptions with the following configuration:

<input type="search"
ng-model
="searchQuery"
ng-model-options
="{ updateOn: 'blur' }"/>

Debounce:


debounce defines an integer value which represents a model update delay in milliseconds. Which means, if we take the example mentioned above, that we want to update our model 300 milliseconds after the user stopped typing, we can do so by defining a debounce value of 300 like this:


<input type="search"
ng-model
="searchQuery"
ng-model-options
="{ debounce: 300 }" />

Advanced options: we can configure how the update delay should be done for different events. Controlling the debounce delay for specific events can be done by defining an object instead of a integer value, where keys represent the event name and values the debounce delay. A delay of 0 triggers an immediate model update.

The following code generates a model update delay of 300 milliseconds when the user types into our input, but an immediate update when removing the focus:


<input type="search"
ng-model
="searchQuery"
ng-model-options
="{ updateOn: 'default blur',
debounce: { 'default': 300,
'blur': 0 } }"
>

How does it work?

The ng-model-options controls how the ngModel is updated.

By default Angular automatically registers a watch for every scope variable for updating the binding, the update itself happens due to the $digest loop that is triggered at every key stroke. The $digest loop checks if the model has a new value and if so it updates every model instances in the app without making us add event listeners or manually update the DOM.

As you can see this means that the $digest loop has to go through all the registered watches on the scope at every key stroke and depending on the watches callbacks that can be very expensive. So the debounce triggers the $digest loop after the defined milliseconds allowing the user to type a meaningful search phrase and reduce the amount of the $digest loops.

In the next post we’ll see how ‘one time binding’ also increases our app’s performance.





Ng-Hint – Intellisense for Angular.js

Angular is great. I love it and in my opinion is the best thing that happened to the web development community in the last several years. However as much as I love Angular there is nothing more annoying than searching all other your code while trying to figure out why the #@$% it doesn’t work! And then finally you see it - you forgot a module or misspelled ‘ng-repeat’. If only Angular would have some sort of intellisense what would warn me when I make those mistakes.

Angular-Hint

Is a great library that scans your code and writes warnings to your browser console.

It has several modules:

clip_image002

  • angular-hint-directives - Hints about misspelled attributes and tags, directives and more:
    <ul ng-repaet="point in points">
    <li>{{point}}</li>
    </ul>

The console will show this hint:

clip_image004

  • angular-hint-dom - Warns about use of DOM APIs in controllers. Angular best practice is to avoid using DOM API from the controller so that this code will trigger a warning:

angular.module('sample').controller(function(){
//Accessing the DOM API `document.getElementById()` triggers an AngularHintDOM warning
var list = document.getElementById('list');
var newListItem = document.createElement('div');
newListItem.innerHTML
= 'Item 1';
list.appendChild(newListItem);
});

clip_image005

angular-hint-events - Identifies undefined variables in event expressions. For example if you have a ng-click targeting some function that doesn’t exists in your controller : 

<a ng-click="increments">Count!</a>
$scope.increment = function(){
++$scope.count
};
 The docs say that this code should trigger a hint, unfortunately it didn’t work for me Sad smile – they have an open issue for that.


var myApp = angular.module('myApp', []);

I’ve also included :


<script src="src/angular-messages.js"></script>

which has a module in it. So the console has a warning:

clip_image006

The first warning is a known issue and should be ignored.

This is a great library however is still has some open issues and the worst part is that if you reference the script hint.js it will crash your app Sad smile. They have several open issues addressing this problem. I truly hope that they would fix it soon since it is a great library. Meanwhile you could add the script before you commit your work just to see if there are no warnings and you have applied all the best practices.

Hint: Keep your eye on Angular-Hint!