Better know a framework #19: what is `model.bind` in Aurelia


#1

Reading through some section of Aurelia docs, you will see some code like this (not exactly the same)

<!-- https://aurelia.io/docs/binding/checkboxes#array-of-objects -->
<input type="checkbox" model.bind="item" checked.bind="selectedItem" />

<!-- or -->
<!-- https://aurelia.io/docs/binding/radios#objects -->
<input type="radio" model.bind="item" checked.bind="selectedItem" />

<!-- or -->
<!-- https://aurelia.io/docs/binding/selects#select-object -->
<select value.bind="selectedItem">
  <option repeat.for="item of activeItems"
          model.bind="item">${item.name}</option>
</select>

You may wonder what model.bind is and why it is needed. Simple answer is: model.bind is a way to associate a value that is not a string to <input/> or <option/> element, as <input/> and <option/> element always convert to string whatever value you assign to their value property. You can test its behavior via copy pasting the following block into your browser console:

let i = document.createElement('input');
i.value = {};
console.log(i.value) // [object Object]

let o = document.createElement('option');
o.value = {};
console.log(o.value) // [object Object]

In two way binding scenarios, Aurelia binding system, upon input event from those <input/> or <select/> elements, will get the value of those elements via element.value and update your view model. And as explained above, property value of <input/> and <option/> are quite problematic when it comes to anything that is not a string. This is where model property is needed. Aurelia will check if model exists and get value from it before it fallback to value property. By having a model.bind binding on those element, a model property will be created, and it can store any value ie. object, array, number…, so you can bind it to anything without worrying about coercion.


#2

Is there any way of giving a hint to the binding of the type of value expected?

public testItem: {name: string, value: number}
<div contenteditable textcontent.two-way="testItem.name" >
<div contenteditable textcontent.two-way="testItem.value">
console.log(testItem) // {name:"abc", value: "5"}

What I would like that happens, is that aurelia somehow knows that testItem.value is of type(number), so that

console.log(testItem) // {name:"abc", value:5}

This keeps catching me out in code far removed from the data input, where I’m expecting a number, but find that I’m dealing with a string instead.


#3

You can employ a value converter:

<div contenteditable textcontent.two-way="testItem.name" >
<div contenteditable textcontent.two-way="testItem.value | number">
import { valueConverter } from 'aurelia-framework';

@valueConverter('number')
export class NumberConverter {
  fromView(val) {
    return Number(val);
  }
}

#4

Duh! Of course!

Thanks


#5

You need toView to support two-way binding. nvm :slight_smile: