Wednesday, 11 September 2019

Angular - custom lookup form component

@angular/cli - 8.2.0

Most of our application requirements are fulfilled using standard HTML elements. However, we may sometimes need to stretch ourselves when we are working for large enterprise applications. In such cases, reusability becomes a strong factor which determines ease of development. Today's use case is one such custom requirement.

This article speaks about creating an Angular component which acts as a lookup - an input field with a search button. The button opens up a modal window, which shows a list of values from which the user may select one. Additionally, this new component should also angular-form-ready, which means, it should be capable enough to be registered as a template-driven or reactive form element.

Let's first talk about the component itself.

The app-lookup component takes in a couple of inputs - formConfig and lookupConfig. A sample implementation is shown below:

When user clicks on the search button, a modal window opens with data fetched from server (in my case a simple promise). Use selects a record and clicks select. The data gets populated on the input form.

If allowUnlistedValue is set as true, the user will be able to enter a value which does not exist in the list, and the value will be accepted. If not, then the form element will return empty value.

So this is all about the component. Now we need to extend this component so that Angular recognizes this as a valid form element. Since this element is of input type, I have implemented the interface ControlValueAccessor. This interface needs to implement 3 methods - writeValue, registerOnChange and registerOnTouched. The writeValue methods is the one which is responsible to writing your value to the view from your model. registerOnChange is used to propagate changes from your model to the view.

Once your TS class is set up with these methods, you need to set up a NG_VALUE_ACCESSOR provider to use this component as a form element.

Do note: A much more in-depth set of instructions for creating custom form elements can be found in a blog by Pascal Precht.

And there you go. You have your own angular component ready to be used in a form! You can download the source code from GitHub and play around with the configurations.


Monday, 2 September 2019

Angular - function reference

@angular/cli: 8.2.0

This article demonstrates a powerful mechanism (yet well-known, I am sure) to pass on function references while passing data from one component to another.

This mechanism or idea can be quite helpful if you are planning to build re-usable toolbar components for your application. Reusable toolbars perform the same kind of operation most of the time. But what if, for a rare use-case, you want an existing toolbar button to perform slightly differently?

Let us see the setup here. We have an app-component and an app-toolbar component. The app-toolbar takes in an array of elements and renders some buttons with some actions.

With a usual use-case, each button is meant to perform a known action.

So far, nothing defferent from the usual. But let's say, I want to perform a more complex operation during Delete operation, for which it might be difficult to write a reusable piece of code.

For such use cases, I would pass on a method from the calling component, where I have all the logic available. Not just that, I would also have to pass on the AppComponent class reference, bound to the method, so that the correct method from the correct TypeScript class gets executed.

Now when I click on Delete button, I see that my AppComponent class' method gets executed.

You can download the source from GitHub.


Tuesday, 9 April 2019

Angular - scope of services

@angular/cli: 7.3.7

Services are a powerful tool in Angular when it comes to storing data or application state. This article is a quick refresher on the various scopes supported by an Angular service.

In order to allow a service to be used, it needs to be declared in the provider section of a module or component.

However, depending on the place where the service is registered, its scope varies accordingly. Let us see how:

a) Service registered in AppModule.ts: This is the root module of your application, and a service registered here holds its state throughout the application. Any value changed here is accessible from any component in the AppModule. This is primarily done for storing data on a global scale, e.g., login state or  client token, etc.

b) Service registered in your custom module: The state of the service holds so long the application navigates to any of the router links registered in this module's router.

c) Service registered in a component: As seems obvious, the scope of this service instance is till the specific component is in use. The state is lost when we navigate away from this component. We register a service on a component only when we need specific functionalities for a component, which does not depend on application state.

We will see a quick demo to illustrate this behaviour.

This sample application has two components (one and two). Two services (LocalService and GlobalService) are in use. The LocalService is defined at the OneComponent, and the GlobalService is defined at AppModule.

GlobalService in AppModule, LocalService in OneComponent

Each service has a variable, which we would update from the OneComponent.

Variables in both services updated

Now the variables in both the services are updated. No problem with that. Let's navigate to the "two" component and come back to "one".

LocalService reset, GlobalService retained
We see that the variable in LocalService has been reset to its original value, while the variable in GlobalService has retained its value.

This is expected since the GlobalService was defined in AppModule and it holds its state throughout the life-cycle of the application. The LocalService was defined in OneComponent, and its state was lost the moment we navigated to a different component.

You can download the source from GitHub.


Thursday, 4 April 2019

Angular - a pipe demo

@angular/cli: 7.3.7

I was working with an interesting UI requirement, and I ended up with developing a sweet little pipe. Before I go into that, I'd describe the use case.

I have a model which has a trip plan name, and a list of locations. I am supposed to display each trip plan as a bootstrap list item. The list item should have the plan name as a list header, and the locations as a list-item-text.

Now of course, keeping in mind the small form factor, you need to ensure that when the number of locations grow in size, they should be fitted nicely into the screen.

Imagine I have an array of locations such as ['New Delhi', 'Kolkata', 'Chennai', 'Mumbai', 'Bangalore', 'Hyderabad']. I simply cannot display all of them on the screen, and going on to the next line is certainly not a great user experience. But what if the user could specify a max length, and beyond that the strings would be shortened with a "and 3 more..." or "and 5 more..."?

As an example: ['New Delhi', 'Kolkata', 'Chennai', 'Mumbai', 'Bangalore', 'Hyderabad'] gets shortened to Mumbai, Kolkata and 4 more..

To implement this, I have used a pipe, which works against a string array. It uses two methods to shorten - bestfit and sequential.

* 'bestfit': This means that that array will be sorted in ascending order of length of array items and maximum number of items will be fitted in the output string.
* 'sequential': This means that the array will be taken as is, and the first n possible items will be fitted.

Take a look at the text-shorten.pipe.ts file and play around with the 2 methods.

Source Code: GitHub