• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

I Like Kill Nerds

The blog of Australian Front End / Aurelia Javascript Developer & brewing aficionado Dwayne Charrington // Aurelia.io Core Team member.

  • Home
  • Aurelia 2
  • Aurelia 1
  • About
  • Aurelia 2 Consulting/Freelance Work

Aurelia Custom Element Using Select2 (tutorial)

Aurelia 1 Tutorials · August 24, 2015

I know, I just can’t keep quiet about Aurelia. But it is one of the most exciting things to happen to Javascript in a long time. So I decided to write up a quick tutorial on creating a custom element in Aurelia for Select 2, which is a popular library for adding custom select elements to your applications.

Prep

Before we begin, you need to have Aurelia installed locally and the development server running. The easiest way to do this is to download the Aurelia Skeleton Navigation project and follow the README instructions. This tutorial assumes you already have an Aurelia project and that you’re not starting from scratch.

Once you have the Skeleton Navigation project downloaded (or your local project) and all dependencies installed, we need to download Select 2. This can be achieved by opening up a terminal window in your project directory and typing jspm install select2 after the download is finished, the needed changes will be made to the config.js and package.json files.

Now we need to make sure we have jQuery installed as well. This can be achieved by typing in your terminal/PowerShell window: jspm install jquery – okay, now we have everything that we need to continue.

Creating our custom element

In the src directory we want to create a folder called resources and in it create two files: custom-select.js and custom-select.html (One is our ViewModel and the other is the View).

In custom-select.js
Let’s focus on the Javascript part of our custom select first. Open up the file custom-select.js and add in the following:

// Aurelia Framework specific functionality
import {bindable, inject, customElement} from 'aurelia-framework';

// Import JSPM modules we installed earlier
import $ from 'jquery';
import 'select2';
import 'select2/css/select2.css!'

@customElement('select2') // Define the name of our custom element
@inject(Element) // Inject the instance of this element
export class CustomSelect {
    @bindable name = null; // The name of our custom select
    @bindable selected = false; // The default selected value
    @bindable options = {}; // The label/option values

    constructor(element) {
        this.element = element;
    }

    // Once the Custom Element has its DOM instantiated and ready for binding
    // to happenings within the DOM itself
    attached() {
        $(this.element).find('select')
            .select2()
            .on('change', (event) => {
                let changeEvent;

                if (window.CustomEvent) {
                    changeEvent = new CustomEvent('change', {
                        detail: {
                            value: event.target.value
                        },
                        bubbles: true
                    });
                } else {
                    changeEvent = document.createEvent('CustomEvent');
                    changeEvent.initCustomEvent('change', true, true, {
                        detail: {
                            value: event.target.value
                        }
                    });
                }
                this.element.dispatchEvent(changeEvent);
            });
    }
}

We are creating our custom element using a decorator called @customElement() then specifying the tagname. This decorates our class with the require metadata Aurelia needs to know this is our custom element and what the element will look like when referenced in the DOM.

We are also using @bindable which allows us to specify properties of our custom element which are bindable. We are using the default use of @bindable but if you read the documentation, you can go deeper and customise many aspects of how a value is bound (one-way, one-time, two-way), callback functions and more.

More notably you can see we are triggering an event on the element itself (at the bottom of the Javascript file above). When I first started with Aurelia I was passing callback functions, with a parameter called callback however, I encountered far too many issues which was a sign that it was not the right way to go about it.

I have been using React.js since it practically debuted and I became used to the concept of passing callback functions. Triggering events on the element is cleaner and allows us to specify a custom event listener on the element itself when we use it.

In custom-select.html
Now we have our ViewModel above defined, lets create the View. This is the easiest part of our custom element. All we are doing is wrapping a select element in the mandatory <template> tags and adding in some binding values to bind to values passed to the custom select element.

<template>
    <select name.bind="name" value.bind="selected" id.bind="name">
        <option repeat.for="option of options" value.bind="option.value">${option.label}</option>
    </select>
</template>

There isn’t really much to explain here. The <template> tags are a requirement. And anything within is our custom element. We then bind to values specified as @bindable on the custom element itself. These are the values that will be passed through from whereever our custom element is being used.

Using our Custom Element

Now that we have our new custom element. We can either globalise it using aurelia.globalResources() (for another post) or we can require it in our required view. For the sake of simplicity, we are going to focus on manually requiring it in our view and using it.

Now to use our newfound custom element, lets assume we have a ViewModel called test-select.js and an accompanying View called test-select.html we will then provide some options for the custom element, a default selected value and a callback for the change event triggered.

test-select.js

export class TestSelect {
    activate() {
        this.selectOptions = [
            {label: 'My Option', value: 'my-value'},
            {label: 'Some Value', value: '1212'},
            {label: 'Select Me!', value: 'fsdf32423_312'},
        ];

        this.defaultSelected = this.selectOptions[0];
    }

    changeCallback(evt) {
        // The selected value will be printed out to the browser console
        console.log(evt.detail.value);
    }
}

test-select.html

<template>
<require from="resources/custom-select"></require>

<select2 name="myCustomSelect" selected.bind="defaultSelected" options.bind="selectOptions" change.delegate="changeCallback($event)"></select2>
</template>

Conclusion

As you can see, custom elements are nothing more than standard ES2015 classes with a @customElement decorator annotating the class. We can then inject the element instance which we can manipulate, using jQuery we find the input element and then apply the Select2 plugin.

Much like our standard ViewModel’s in Aurelia we might be using elsewhere, we have a view (unless we specify otherwise) which has the same name (unless otherwise specified). This is the beauty of Aurelia, everything is class based and through the use of decorators we can tell Aurelia what said piece of code does within our application.

Hopefully this helps you create some custom elements of your own. I realise I didn’t delve too deep in the specifics of everything we have learned here. Fortunately, the documentation explains everything above and more, so I highly advise you make yourself a tea or coffee and read about custom elements here.

If something doesn’t work, I have made an error you want to ask a question: please drop a comment below and I respond pretty quickly.

Dwayne

Leave a Reply Cancel reply

14 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Lesster
Lesster
7 years ago

Thank you so much for this article, it helped me in my learning of Aurelia.

When I implemented your example I kept getting evt.detail.value = undefined. I put a breakpoint on the custom-select.js and found that the “event” didn’t have a “val” property, so i started going through the object properties. I found it on event.delegateTarget.value, I’m not sure if i did something wrong but wanted to post this in case i did and if you didn’t mind shedding some light on this. Thank you again.

0
Deni
Deni
7 years ago

Hello, i have same problem,

evt.detail.value = undefined

How to get value ?

0
Anonymous Guest
Anonymous Guest
7 years ago

I also want a value of this

0
Alexis Argyris
Alexis Argyris
7 years ago

Hi,

Thanks for the great article!

BTW, custom-select.html should probably look like this:

${option.label}

0
Angel
Angel
7 years ago

Hi Dwayne,

This is indeed a wonderful article, but unfortunately there seem to be several issues which I’m unable to solve. I am quite new to Aurelia and probably that’s the reason…

One of them is as stated by others, the fact that the new value of the select is not being passed through to the custom change event.

The other is that the two-way binding for the value attribute is not working. It stays the same as it was in the beginning.

When I don’t change the select into select2 in the attached handler, the two-way binding does work. However, once converted to select2, the selected value is not being updated.

Any ideas?

Thanks.

0
Sid
Sid
6 years ago

Hi, First of all a really great article on custom elements. I’ve tried above steps in my own project , but I’m facing a weird issue. In my case, “options” is not getting binded to my select control and therefore, nothing is getting displayed on the dropdown. Could you please help here?

0
Dwayne
Dwayne
Author
6 years ago

I’ll update this article with the proper and working way of using Select2 with Aurelia.

0
Gregory Dickson
Gregory Dickson
6 years ago

@bindable options = {}; should be @bindable options = [];

0
Bjørn Øyvind Halvorsen
Bjørn Øyvind Halvorsen
6 years ago

Angel said it best:

“The other is that the two-way binding for the value attribute is not working. It stays the same as it was in the beginning.

When I don’t change the select into select2 in the attached handler, the two-way binding does work. However, once converted to select2, the selected value is not being updated.”

Got any fix for that? I realize that the article is like… super old.. but i bet it’s still quite often visited.

0
Gregory Dickson
Gregory Dickson
Reply to  Bjørn Øyvind Halvorsen
6 years ago

Check out this Gist, I used it to get through some issues with the same select2 binding/updating issue:
https://gist.github.com/mujimu/c2da3ecb61f832bac9e0

0
Gregory Dickson
Gregory Dickson
6 years ago

If you are using Select2 version 4.x.x then you need to do this:

https://github.com/aurelia/documentation/issues/202

0
Arun Teja
Arun Teja
5 years ago

could you implement icheck plugin with aurelia

0
Anton Thorn
Anton Thorn
4 years ago

Holy crap! This is awesome! Thank you, Dwayne!

0

Primary Sidebar

Popular

  • I Joined Truth Social Using a VPN and Editing Some HTML to Bypass the Phone Verification
  • Testing Event Listeners In Jest (Without Using A Library)
  • How To Get The Hash of A File In Node.js
  • Thoughts on the Flipper Zero
  • Waiting for an Element to Exist With JavaScript
  • How To Paginate An Array In Javascript
  • How To Mock uuid In Jest
  • How To Decompile And Compile Android APK's On A Mac Using Apktool
  • How To Get Last 4 Digits of A Credit Card Number in Javascript
  • Wild Natural Deodorant Review

Recent Comments

  • CJ on Microsoft Modern Wireless Headset Review
  • Dwayne on Microsoft Modern Wireless Headset Review
  • CJ on Microsoft Modern Wireless Headset Review
  • john on Microsoft Modern Wireless Headset Review
  • Dwayne on Why You Should Be Using globalThis Instead of Window In Your Javascript Code

Copyright © 2023 · Dwayne Charrington · Log in

wpDiscuz