• 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

Binding An Aurelia Form To An Object Model

Aurelia 1 · July 13, 2016

Whilst working on a cool little Pokemon focused Aurelia app using the Aurelia CLI I encountered a scenario I didn’t immediately know the answer too. I wanted an object which represents my form elements and their values are bound to this object.

I then had a submit button which I wanted to only enable when all fields on the object had been filled out. At first I tried an @observable and couldn’t get it to work, then I had an epiphany: what about a computed getter?

The only caveat with this approach is you need to know your object properties up front if you want to avoid dirty-checking. I knew what each input would be bound too, so this wasn’t going to be an issue.

Below is literally the code copied and pasted from my app, this is what I am using:

import {computedFrom} from 'aurelia-framework';

export class MyViewModel {
    currentSighting = {
        name: null,
        cp: null,
        latitude: null,
        longitude: null
    }; 

    @computedFrom('currentSighting.name', 'currentSighting.cp', 'currentSighting.latitude', 'currentSighting.longitude')
    get sightingIsSubmittable() {
        let currentSighting = this.currentSighting;

        return (currentSighting.name && currentSighting.cp && currentSighting.latitude && currentSighting.longitude);
    }   
}
<template>
    <form submit.delegate="handleSightingSubmit($event)">
        <input type="text" value.bind="currentSighting.name" placeholder="Please select from the list">
        <br>
        <input type="text" value.bind="currentSighting.cp">
        <br>
        <input type="text" value.bind="currentSighting.latitude" readonly>
        <br>
        <input type="text" value.bind="currentSighting.longitude" readonly>

        <input type="submit" disabled.bind="!sightingIsSubmittable">
    </form>
</template>

One thing you’ll notice is all of my input elements are bound to properties on the currentSighting object. This keeps everything nice and neat, it also allows me to post if off to the server in a JSON request.

Look at the submit button at the bottom of the form, notice the line disabled.bind="!sightingIsSubmittable" we are binding to our getter and because we are using computeds in the form of computedFrom we eliminate any dirty checking so it’s only updated when something changes on our object.

Lastly we also inverse the boolean value provided from the better as we want false to enable the button and true to disable it. That is really all there is to it. Now you can make things in your app work off of multiple values and their specific values.

Just try to not abuse computeds. In this instance it makes sense to use a getter and computeds, but in some cases, there might be a better way.

Dwayne

Leave a Reply Cancel reply

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Michael
Michael
6 years ago

If you really want to avoid dirty-checking, then it’s totally possible to solve this without “knowing” all the properties on the model object.

The MultiObserver from this post: http://eisenbergeffect.bluespire.com/aurelias-adaptive-binding/ , can be used to observe a bunch of named properties on an object (which is good if you want to observe a select few properties, and/or the object is not a pure Model, like a ViewModel). Though this could be fairly easily modified to take a model only (or have an “overload”):

import {inject, BindingEngine} from ‘aurelia-framework’;

@inject(BindingEngine)
export class MultiObserver {
constructor(bindingEngine) {
this.bindingEngine = bindingEngine;
}

observe(object, callback) {
let properties = Object.getOwnPropertyNames(object);
let subscriptions = [], i = properties.length, propertyName;
while(i–) {
propertyName = properties[i];
subscriptions.push(this.bindingEngine.propertyObserver(object, propertyName).subscribe(callback));
}

return {
dispose: () => {
while(subscriptions.length) {
subscriptions.pop().dispose();
}
}
}
}
}

0
Jens Petter Abrahamsen
Jens Petter Abrahamsen
6 years ago

In your getter, why do you create a local variable:

let currentSighting = this.currentSighting;

instead of using the global (this.) version in the if?

0
Hans
Hans
6 years ago

Very helpful! Wondering if you could include a mention (or example!) of how you’d handle the situation where some of your form fields are arrays? I guess @computedFrom wouldn’t help much there?

0

Primary Sidebar

Popular

  • Thoughts on the Flipper Zero
  • I Joined Truth Social Using a VPN and Editing Some HTML to Bypass the Phone Verification
  • How To Install Eufy Security Cameras Without Drilling or Using Screws
  • How To Get The Hash of A File In Node.js
  • The Most Common iPhone Passcodes (and how to guess them)
  • Wild Natural Deodorant Review
  • NBN Box Installed Inside of Garage, Where Do You Put The Modem?
  • Improving The Coopers Australian Pale Ale Extract Tin (and other tips)
  • Neural DSP Reveal Details About the Long-Awaited Quad Cortex Desktop Editor
  • How To Paginate An Array In Javascript

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