简体   繁体   中英

Aurelia: data binding issue with the primary property of a custom attribute

I am learning about Aurelia for a few weeks now and I seem to have a data binding issue with a custom attribute.

I have created the following square custom attribute (based on the examples from the "Templating:Custom Attributes" guide on the Aurelia website ):

square.ts:

import { bindable, autoinject } from "aurelia-framework";

@autoinject
export class SquareCustomAttribute {
  @bindable sideLength = "100px";
  @bindable color = "red";

  constructor(private element: Element) {
    this.sideLengthChanged(this.sideLength);
    this.colorChanged(this.color);
  }

  sideLengthChanged(newValue: string) {
    if (this.element instanceof HTMLElement) {
      this.element.style.width = this.element.style.height = newValue;
    }
  }

  colorChanged(newValue: string) {
    if (this.element instanceof HTMLElement) {
      this.element.style.backgroundColor = newValue;
    }
  }
}

I would like this custom attribute to be usable without explicitly binding it, in which case it should use the default values, like in this consuming view:

app.html:

<template>
  <require from="./square"></require>
  <div square></div>
</template>

The code above works fine. It renders the div as a square with 100px sides and a red background.

Problems arise when I set the color property of SquareCustomAttribute as the primary property (using @bindable 's configuration object parameter) like this:

Updated square.ts:

import { bindable, autoinject } from "aurelia-framework";

@autoinject
export class SquareCustomAttribute {
  @bindable sideLength = "100px";
  @bindable({ primaryProperty: true }) color = "red";

  constructor(private element: Element) {
    this.sideLengthChanged(this.sideLength);
    this.colorChanged(this.color);
  }

  sideLengthChanged(newValue: string) {
    if (this.element instanceof HTMLElement) {
      this.element.style.width = this.element.style.height = newValue;
    }
  }

  colorChanged(newValue: string) {
    if (this.element instanceof HTMLElement) {
      this.element.style.backgroundColor = newValue;
    }
  }
}

For some reason, setting color as the primary property of the custom attribute, the colorChanged callback gets invoked twice now: first by the constructor with the default value and then once more from somewhere in the lifecycle initialization with an empty value.

How can I avoid this second invocation of the colorChanged callback, so that the default value of the primary property of my custom attribute will not be cleared when I do not explicitly supply a binding/value of the square attribute in the consuming view's HTML markup?

You will have to tackle this another way:

import { bindable, autoinject } from "aurelia-framework";

@autoinject
export class SquareCustomAttribute {
  @bindable sideLength;
  @bindable({ primaryProperty: true }) color;

  constructor(private element: Element) {
  }

  sideLengthChanged(newValue: string) {
    if (this.element instanceof HTMLElement) {
      this.element.style.width = this.element.style.height = newValue;
    }
  }
  
  bind(){
    this.sideLengthChanged(this.sideLength ? this.sideLength : "100px");
    this.colorChanged(this.color ? this.color : "red");
  }

  colorChanged(newValue: string) {
    if (this.element instanceof HTMLElement) {
      this.element.style.backgroundColor = newValue;
    }
  }
}

When you declare { primaryProperty: true } , you are basically telling the framework to create a binding on the value of your custom attribute, whether it is filled or not, the framework will map it to your color property. so when you declare <div square></div> , the color property in the bind() lifecycle will be an empty string. As bind() is only invoked once, it's the perfect spot to declare your default values, should they be empty in the beginning.

Example here: https://gist.dumber.app/?gist=b0244ac4078e2a0664b7be0fbcc0b22b

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM