Extending HTML the Aurelia.io Way

Originally published at: http://www.sitepoint.com/extending-html-aurelia-io-way/

Teaching the old dog HTML new tricks is a major focus of today’s modern JavaScript frameworks. Be it by following potential standards like WebComponents, creating custom Directives or by extending existing classes, chances are high that your framework of choice provides a means to extend HTML’s markup itself. In a previous article, written by Brad Barrow, you were introduced to a new player: Aurelia. This article will build upon Brad's article and code and show you how to create custom elements as well as custom attributes by following Aurelia’s conventions.

The complete code for this article can be found on our GitHub repo and you can see a demo of what we are going to build here (please allow some time for the app to initialize).

Why the Need for More Markup?

Before jumping straight into the action let’s first understand the potential use case for creating new components. To do so we will take a conceptual look at the introductory example as shown in the figure below. We have two pages, represented by a ViewModel (VM) and a View, showing funny pictures and gif videos. Each of those has a repeated list which itself renders posts containing an image and a text block.

Diagram depicting flow of Aurelia Reddit Client

Aurelia Reddit Client conceptual diagram

By looking at the View we can see that data acquisition, as well as rendering, is tightly coupled in one VM/View pair.

<template>
  <ul class="list-group">
    <li class="list-group-item" repeat.for="p of posts">
      <img src.bind="p.data.thumbnail" />
      <a href="http://reddit.com${p.data.permalink}">
        ${p.data.title}
      </a>
    </li>
  </ul>
</template>

This might not be a problem with a simple example, but can turn into a major drawback as the system grows and more and more requirements are gathered.

Enhancing Existing Elements with Custom Attributes

Imagine we get a request to provide a popover for each of the funny pages posts. In order to do that we could easily wire up Bootstrap’s feature directly into the markup by placing the necessary data- attributes followed by an initialization inside our FunnyVM. But what if we suddenly need to do it on the other page as well? Providing the feature by declaring a custom attribute can make our lives much easier. These are particularly useful in following scenarios:


  • Wrapping existing plugins

  • Shortcuts for common bindings such as style or class

  • Altering existing HTML elements / custom elements without direct code access

Now let’s get our hands dirty and see what it takes to build our first custom attribute.

Creating the popover

Let’s start by looking at what we’d like to achieve. The new attribute popover should accept parameters for the placement, title and content of the popover. The placement is fixed to the right, so a simple string as value is enough. For the other two properties we’re going to use Aurelia’s data binding to map the iterated values. In order to load the file we make use of Aurelia’s require feature. The from attribute contains the relative path to the resource to be imported.

<require from="./popover"></require>    
...
<img src.bind="p.data.thumbnail"
     popover="placement: 'right';
              title.bind: p.data.url;
              content.bind: p.data.title" />

In order to make that happen, we start by creating a new JavaScript file in the src folder called popover.js. The custom attribute, like all other Aurelia constructs, is a simple exported ES6 class rather than a collection of functions passed into a predefined API (as many legacy frameworks do).

import {customAttribute, bindable, inject} from 'aurelia-framework';
import $ from 'bootstrap';
import bootstrap from 'bootstrap';
...

Compared to other frameworks, Aurelia declares constructs by describing them via metadata. But instead of using static functions or complicated APIs, Aurelia leverages cutting edge ES7 Decorators to achieve that. We’re going to import the necessary decorators from the package aurelia-framework. As for the control itself, we will use the Popover JavaScript control provided by Twitter Bootstrap. So we import the jQuery handle $ as well as bootstrap in order to initialize Bootstraps’ JavaScript code.

The next step is to apply the previously mentioned metadata so that Aurelia knows what it gets when it loads the file. By attaching the customAttribute decorator we name our component with the given value. The bindable decorator on the other hand is declaring a property which our View can bind to. We simply repeat this decorator for each available property.

@inject(Element)
@customAttribute('popover')
@bindable('title')
@bindable('content')
@bindable('placement')
export class Popover {
...

Continue reading this article on SitePoint

Great Job. I've been looking for a good example of building Aurelia components - this one is very well done

Thanks

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.