Thursday, December 17, 2015

Aurelia - making custom element global

This isn't anything earth-shattering. In fact, you can probably find almost the exact same thing somewhere else. But part of my purpose in writing this blog is to centralize the knowledge that I have acquired while working on this Aurelia project so that my team can come here to learn. In that spirit, a short post on making resources globally available.

If you have a custom element (or attribute, but I have not yet worked with a custom attribute, weird), you can reference it in your html file with a simple require:

<require from="../components/my-custom-element"></require>

Simple enough, and you can then use the custom element in your view. However, that can get tedious, especially with elements that you use all over your web site. For that, Aurelia provides a very simple mechanism, aurelia.use.globalResources. Simply add it to your main.js chain, passing the path to your view/view-model pair, and you're good:

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging()
    .globalResources('./components/my-custom-element');

  aurelia.start().then(a => a.setRoot());
}

This is great for one or two custom elements, but as your app grows and you centralize more of your look and feel into re-usable custom elements, this can get unwieldy. For that, another method comes into play: aurelia.use.feature. Simply move all of your custom elements into a single folder (you already did that anyways, right?) add an index.js to that folder, and change the above to:

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging()
    .feature('components');

  aurelia.start().then(a => a.setRoot());
}

The index.js file in the components folder has a method configure with a call to globalResources, with all of the custom elements as parameters:

export function configure(aurelia) {
  aurelia.globalResources('./my-custom-element', './some-custom-attribute', './file-loader');

There is no limit on the number of parameters other than a javascript limit on the number of parameters. If you hit that limit, or for more practical reasons, you can have multiple calls to globalResources chained as well:

export function configure(aurelia) {
  aurelia
    .globalResources('./my-custom-element', './some-custom-attribute', './file-loader')
    .globalResources('./more-good-stuff');
}

Currently, I have two folders of features: One contains my custom elements, the other my value converters. Each has its own index.js file and both are referenced in main.js (this is my actual main.js as of this writing):

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging()
    .plugin('aurelia-validation', (config) => { config.useViewStrategy(TWBootstrapViewStrategy.AppendToMessage); })
    .plugin('aurelia-dialog')
    .feature('resources')
    .feature('components');

  aurelia.start().then(a => a.setRoot());

}


One little side note. Don't forget the ./ at the beginning of paths to resources in the same folder. In my experience, nothing bad happens until you are close to deadline, then the templating engine fails to find your resource :-) Actually, it's just the right way to do it, and it will break some things if you omit it.

4 comments:

Josh McCullough said...

Yes! Thank you!

Anonyrock said...

Excellent post.
I am trying to update a section of pluralsight course "Building Applications with Aurelia" with these methods to make custom component globally available to dom. Noting that does work...

none of these methods seem to work:
.globalResources("./resources/nav-menu"); in main.js
.feature("resources") in main.js with an index.js with .globalResources("./nav-menu") in resources folder
.plugin("./resources/nav-menu") in main.js

what am I missing :) ?

Anonyrock said...

*above post swallowed <require> after the word "noting"

bluewater said...

very helpful, thx!