Gravatar Directive in Angular

Gravatar Directive in Angular

Connect email to global avatar with custom directive

Did you know that Angular components are subsets of directives? Why do we then need the Directive decorator, and why would we use it instead of the Component? Well, directives can extend the behavior of a component by adding behavior to template elements. In this article I’ll show you an example of how we can do that. I will create an attribute directive for Gravatars.

The example code is on GitHub.

What is Gravatar?

First things first, what is Gravatar and why do we want to use it?

Gravatar stands for Globally Recognized Avatar. Millions of people and websites use it. If you create an account with Gravatar, you can upload your picture and connect it with an email.

This means that if you use that same email from Gravatar on another website, they can download your picture from the Gravatar site and use it on their page.

What are Directives?

Through the docs we discover that there are three types of directives:

  1. Components — directives with a template. The bread and butter of Angular.

  2. Structural directives — change the DOM layout by adding and removing DOM elements. (NgFor, NgIf)

  3. Attribute directives — change the appearance or behavior of an element, component, or another directive. This is the kind we are going to be creating.

The Goal

The final product will be a material card where the gravatar is placed in the header. When we write our email in the input field, we will see our connected picture as the avatar.

To get started let’s create an account with Gravatar.

Gravatar Account

For our example, I have created an account that you also can use for testing. Alternatively, you can go to gravatar.com and create your account.

We can now use the email to get the Alf-gravatar downloaded to the application.

The Directive

Now its time to start with the directive. To scaffold the file, we can use the CLI generate command:

ng generate directive gravatar

We usually use the Component decorator, but this time we use the Directive one. With this decorator, we can add our custom behaviors to elements in the DOM.

An Attribute directive changes the appearance or behavior of a DOM element.

In the selector property, we define the directive’s CSS attribute selector, [appGravatar]. It’s the brackets that make it an attribute selector. Now we can add appGravatar to the elements that we want to give the behavior defined in the directive.

In our example, we are adding new behavior to the image in the header.

<img mat-card-avatar appGravatar>

The image tag already has an Angular Material attribute directive mat-card-avatar. This changes the image to behave as an avatar within the header. By adding our directive, we are building on this behavior.

The Email

When the email in the input changes we want to update the gravatar. The ngModel binds the email string in the text field to the ‘gravatarEmail’ variable.

<input matInput [(ngModel)]="gravatarEmail">

Then we add an email property to the image element and bind ‘gravatarEmail’ to it.

<img mat-card-avatar appGravatar [email]="gravatarEmail" />

Now we have added the property binding for the email. So for every value change in the input, we are sending the value to the directive.

To make it simple let’s make the input field a setter that updates the avatar every time the value changes.

@Input() set email(value: string) {
  this.updateGravatar(value);
}

Now that we have set up, so the email is sent from the text field to the directive, let’s see what we have to do to our email string to download our image and show it in the header.

Like this blog post? Share it on Twitter! 🐦

The Gravatar

Now we need to download the image from our Gravatar account. This is done by creating an URL with the help of our email.

All URLs on Gravatar are based on the use of the hashed value of an email address.

To create the correct hash, we need to do three things:

  1. Trim leading and trailing whitespace from an email address

  2. Force all characters to lower-case

  3. md5 hash the final string

The first two steps are easy:

email.trim().toLowerCase()

However, how do we create the hash?

Hashing

We need to use MD5 to create the hashed value to use in the URL.

The MD5 message-digest algorithm is a widely used hash function producing a 128-bit hash value.

I used the npm package ts-md5, but there are many other md5 packages out there. So we npm i ts-md5and import it into the file:

import { Md5 } from 'ts-md5/dist/md5';

Now we can call the hashing function to create the hash:

const emailHash = Md5.hashStr(email.trim().toLowerCase());

Image Request

Now that we have the hash we are ready to request our image.

The most basic image request URL looks like this:

[https://www.gravatar.com/avatar/HASH](gravatar.com/avatar/HASH)

We need to set this URL in the src property of the image element. We do not want to manipulate the DOM element directly. In Angular we can instead do this by using:

  • ElementRef — a wrapper around a native element inside of a View.

  • Renderer2 — base class to implement custom rendering, use this when direct DOM manipulation is necessary.

Inject these to get a reference to the element and the renderer.

constructor(private el: ElementRef, private renderer Renderer2) {}

Now set the src attribute in the native element to the URL through the renderer:

this.renderer.setAttribute(this.el.nativeElement, 'src', '//www.gravatar.com/avatar/' + emailHash);

The complete code:

So now the directive is working!

Default Avatar

There are some possible improvements to our directive.

What happens when an email address has no matching Gravatar image?

If we don’t find the email, then we can show a fallback picture. By default, this will be the Gravatar logo. However, there are plenty of options if we don’t want to set our default.

mp, identicon, monsterid, wavatar, retro, robohash & blankmp, identicon, monsterid, wavatar, retro, robohash & blank

We do so by supplying the URL with the d= or default= parameter with our choice. I have chosen wavatar, and the URL is then:

`//www.gravatar.com/avatar/${emailHash}?d=wavatar`

And now if we write the wrong email, we will get a random wavatar.

In conclusion, this was meant to be a fun example to get you started with attribute directives. I hope you enjoyed it and got some inspiration to create more directives in the future.

The example code from this article is on GitHub.

Call to Action

I always enjoy feedback so please 👏, 📝 and tweet 🐦. Follow me on Twitter and Medium for blog updates.

Did you find this article valuable?

Support Michael Karén by becoming a sponsor. Any amount is appreciated!