Custom Elements and Compose View in Aurelia

Custom elements are useful when we have large page content and we need to break the pages into small pieces of components which can be reusable in the other pages also. To create a custom element we just need to create a view template and optionally a view model for it. Using a custom element to a page or another element is to just require it in that page and add a custom html tag for this.

Say we have a page that displays users information users personal info, his address and the blog posts which was posted by them. If we put all the information in a single component it will look like similar as below

<template>
  <div>
    Users Personal Information
  </div>
  <div>
    Users Contact Information
  </div>
  <div>
    Blog Posts
    <ul>
      <li>Post 1</li>
      <li>Post 2</li>
      <li>Post 3</li>
    </ul>
  </div>
</template>

Here its not a large amount of code but definitely it will be very large in real scenarios. There we can refactor this code and break these into 3 components like PersonalInfo, ContactInfo, UserBlogPost then it will look clean and easy to understand and it will be highly maintainable. Basically as a frontend developer you will deal with hundreds of components and composing them. It is conventional to put the reusable pieces of components in a separate folder called components/partials you can use whatever names you like. So I am creating these custom elements in components folder  as like below.

PersonalInfo.html

<template>
  <div>
    Users Personal Information
  </div>
</template>

ContactInfo.html

<template>
  <div>
    Users Contact Information
  </div>
</template>

UserBlogPost.html

<template>
  <div>
    Blog Posts
    <ul>
      <li>Post 1</li>
      <li>Post 2</li>
      <li>Post 3</li>
    </ul>
  </div>
</template>

Create 3 view models for each of these also PersonalInfo.js , ContactInfo.js and UserBlogPost.js.Make a class with the same file name (its optional though but its good to have a view model also). Now we will include them in our main user details page. I am using app.html file for these. See how our app.html look like

<template>
  <require from="./components/PersonalInfo"></require>
  <require from="./components/ContactInfo"></require>
  <require from="./components/UserBlogPost"></require>
  <personal-info></personal-info>
  <contact-info></contact-info>
  <user-blog-post></user-blog-post>
</template>

If you run it you will see the exact same result but our code now looks clean and we can easily reuse them into other pages also. Now see how we require and placed it in the template. we need to require it and specify its relative path don’t need to specify the extension. After requiring it we need to tell where to place it by html tag (hyphened version of the file name). That’s it you now know about custom elements.

Another way to use it by using <compose> attribute. Using compose attribute code will look like these for our app.html file

<template>
  <compose view-model="./components/PersonalInfo"></compose>
  <compose view-model="./components/ContactInfo"></compose>
  <compose view-model="./components/UserBlogPost"></compose>
</template>

Output will be the same. Compose is good when you want to render dynamic element based on some criteria. You can put a variable in the view-model attribute and change the path of the component from parent View Model. That is a difference between compose and custom element.

Now I will show you how you can pass a variable to the child component. Say we have user object with firstName and lastName in our app.js (Parent Component). We want to pass its value to the PersonalInfo component (Child Component). To make it work we need to declare a variable in  PersonalInfo.js and make it bindable properties. see how it do that

PersonalInfo.js

import { bindable } from "aurelia-framework";
export class PersonalInfo {
  @bindable user;
}

And In the child component view template we will display the firstName and lastName info.

PersonalInfo..html

<template>
  <div>
    ${user.firstName }
    ${user.lastName }
  </div>
</template>

Now to pass user object from parent model we need to add an attribute in the html tag for custom element. so the code will be

<template>
  <require from="./components/PersonalInfo"></require>
  <require from="./components/ContactInfo"></require>
  <require from="./components/UserBlogPost"></require>
  <personal-info user.bind="user"></personal-info>
  <contact-info></contact-info>
  <user-blog-post></user-blog-post>
</template>

See user.bind here user is the child component property name (it will be hyphened version of the name) and you have to specify which parent property it will pass as value. You can also bind a function like this way. To know more about custom elements go through their official docs .