Binding: Selects

Data-binding select elements with Aurelia.

Introduction

A <select> element can serve as a single-select or multiple-select "picker" depending on whether the multiple attribute is present. The binding system supports both use cases. The samples below demonstrate a variety scenarios, all use a common series of steps to configure the select element:

  1. Add a <select> element to the template and decide whether the multiple attribute should be applied.
  2. Bind the select element's value attribute to a property. In "multiple" mode, the property should be an array. In singular mode it can be any type.
  3. Define the select element's <option> elements. You can use the repeat or add each option element manually.
  4. Specify each option's value via the model property: <option model.bind="product.id">${product.name}</option> You can use the standard value attribute instead of model, just remember- it will coerce anything it's assigned to a string.

Select Number


    export class App {
      constructor() {
        this.products = [
          { id: 0, name: 'Motherboard' },
          { id: 1, name: 'CPU' },
          { id: 2, name: 'Memory' },
        ];

        this.selectedProductId = null;
      }
    }
  

    export class App {
      products = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      selectedProductId = null;
    }
  

    export interface IProduct {
       id: number;
       name: string;
    }

    export class App {
      products: IProduct[] = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      selectedProductId: number = null;
    }
  

    <template>
      <label>
        Select product:<br/>
        <select value.bind="selectedProductId">
          <option model.bind="null">Choose...</option>
          <option repeat.for="product of products"
                  model.bind="product.id">
            ${product.id} - ${product.name}
          </option>
        </select>
      </label>
      Selected product ID: ${selectedProductId}
    </template>
  

Select Object


    export class App {
      constructor() {
        this.products = [
          { id: 0, name: 'Motherboard' },
          { id: 1, name: 'CPU' },
          { id: 2, name: 'Memory' },
        ];

        this.selectedProduct = null;
      }
    }
  

    export class App {
      products = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      selectedProduct = null;
    }
  

    export interface IProduct {
       id: number;
       name: string;
    }

    export class App {
      products: IProduct[] = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      selectedProduct: IProduct = null;
    }
  

    <template>
      <label>
        Select product:<br/>
        <select value.bind="selectedProduct">
          <option model.bind="null">Choose...</option>
          <option repeat.for="product of products"
                  model.bind="product">
            ${product.id} - ${product.name}
          </option>
        </select>
      </label>

      Selected product: ${selectedProduct.id} - ${selectedProduct.name}
    </template>
  

Select Object with Matcher

You may run into situations where the object your select element's value is bound does not have reference equality with any of the objects your option element model properties are bound to. The select's value object might "match" one of the option objects by id, but they may not be the same object instance. To support this scenario you can override Aurelia's default "matcher" which is a equality comparison function that looks like this: (a, b) => a === b. You can substitute a function of your choosing that has the right logic to compare your objects.


    export class App {
      constructor() {
        this.products = [
          { id: 0, name: 'Motherboard' },
          { id: 1, name: 'CPU' },
          { id: 2, name: 'Memory' },
        ];

        this.productMatcher = (a, b) => a.id === b.id;

        this.selectedProduct = { id: 1, name: 'CPU' };
      }
    }
  

    export class App {
      products = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      productMatcher = (a, b) => a.id === b.id;

      selectedProduct = { id: 1, name: 'CPU' };
    }
  

    export interface IProduct {
       id: number;
       name: string;
    }

    export class App {
      products: IProduct[] = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      productMatcher = (a, b) => a.id === b.id;

      selectedProduct: IProduct = { id: 1, name: 'CPU' };
    }
  

    <template>
      <label>
        Select product:<br/>
        <select value.bind="selectedProduct" matcher.bind="productMatcher">
          <option model.bind="null">Choose...</option>
          <option repeat.for="product of products"
                  model.bind="product">
            ${product.id} - ${product.name}
          </option>
        </select>
      </label>

      Selected product: ${selectedProduct.id} - ${selectedProduct.name}
    </template>
  

Select Boolean


    export class App {
      constructor() {
        likesTacos = null;
      }
    }
  

    export class App {
      likesTacos = null;
    }
  

    export class App {
      likesTacos = null;
    }
  

    <template>
      <label>
        Do you like tacos?:
        <select value.bind="likesTacos">
          <option model.bind="null">Choose...</option>
          <option model.bind="true">Yes</option>
          <option model.bind="false">No</option>
        </select>
      </label>
      likesTacos: ${likesTacos}
    </template>
  

Select String


    export class App {
      constructor() {
        this.products = ['Motherboard', 'CPU', 'Memory'];
        this.selectedProduct = '';
      }
    }
  

    export class App {
      products = ['Motherboard', 'CPU', 'Memory'];
      selectedProduct = '';
    }
  

    export class App {
      products: string[] = ['Motherboard', 'CPU', 'Memory'];
      selectedProduct: string = '';
    }
  

    <template>
      <label>
        Select product:<br/>
        <select value.bind="selectedProduct">
          <option value="">Choose...</option>
          <option repeat.for="product of products"
                  value.bind="product">
            ${product}
          </option>
        </select>
      </label>
      Selected product: ${selectedProduct}
    </template>
  

Multiple Select Numbers


    export class App {
      constructor() {
        this.products = [
          { id: 0, name: 'Motherboard' },
          { id: 1, name: 'CPU' },
          { id: 2, name: 'Memory' },
        ];

        this.selectedProductIds = [];
      }
    }
  

    export class App {
      products = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      selectedProductIds = [];
    }
  

    export interface IProduct {
       id: number;
       name: string;
    }

    export class App {
      products: IProduct[] = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      selectedProductIds: number[] = [];
    }
  

    <template>
      <label>
        Select products:
        <select multiple value.bind="selectedProductIds">
          <option repeat.for="product of products"
                  model.bind="product.id">
            ${product.id} - ${product.name}
          </option>
        </select>
      </label>
      Selected product IDs: ${selectedProductIds}
    </template>
  

Multiple Select Objects


    export class App {
      constructor() {
        products = [
          { id: 0, name: 'Motherboard' },
          { id: 1, name: 'CPU' },
          { id: 2, name: 'Memory' },
        ];

        selectedProducts = [];
      }
    }
  

    export class App {
      products = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      selectedProducts = [];
    }
  

    export interface IProduct {
       id: number;
       name: string;
    }

    export class App {
      products: IProduct[] = [
        { id: 0, name: 'Motherboard' },
        { id: 1, name: 'CPU' },
        { id: 2, name: 'Memory' },
      ];

      selectedProducts: IProduct[] = [];
    }
  

    <template>
      <label>
        Select products:
        <select multiple value.bind="selectedProducts">
          <option repeat.for="product of products"
                  model.bind="product">
            ${product.id} - ${product.name}
          </option>
        </select>
      </label>

      Selected products:
      <ul>
        <li repeat.for="product of selectedProducts">${product.id} - ${product.name}</li>
      </ul>
    </template>
  

Multiple Select Strings


    export class App {
      constructor() {
        this.products = ['Motherboard', 'CPU', 'Memory'];
        this.selectedProducts = [];
      }
    }
  

    export class App {
      products = ['Motherboard', 'CPU', 'Memory'];
      selectedProducts = [];
    }
  

    export class App {
      products: string[] = ['Motherboard', 'CPU', 'Memory'];
      selectedProducts: string[] = [];
    }
  

    <template>
      <label>
        Select products:
        <select multiple value.bind="selectedProducts">
          <option repeat.for="product of products"
                  value.bind="product">
            ${product}
          </option>
        </select>
      </label>
      Selected products: ${selectedProducts}
    </template>