lit / lit-element

LEGACY REPO. This repository is for maintenance of the legacy LitElement library. The LitElement base class is now part of the Lit library, which is developed in the lit monorepo.
https://lit-element.polymer-project.org
BSD 3-Clause "New" or "Revised" License
4.49k stars 318 forks source link

property's 'hasChanged' Option is false, but, updated with other changed property #1098

Closed jerrynim closed 3 years ago

jerrynim commented 3 years ago

Hello. i am using LitElement property 'hasChanged' Option. i don't want to change property 'myProp1'. so, i wrote with 'hasChanged(newVal,oldVal)=>{ return false;}'

and this is my code

import { LitElement, html, customElement, property } from "lit-element";

@customElement("lit-tomato")
class Tomato extends LitElement {
  @property({
    hasChanged: (newVal, oldVal) => {
      return false;
    },
  })
  myProp1 = "original-myProp1";
  @property({ attribute: true }) myProp2 = "myProp1";

  changeProperties() {
    this.myProp1 = "changed-different-name";
    this.myProp2 = "changed-myProp2";
  }

  updated(changedProperties) {
    changedProperties.forEach((oldValue, propName) => {
      console.log(`${propName} changed. oldValue: ${oldValue}`);
    });
    console.log({ ...this });
  }

  render() {
    return html`
      <style></style>
      <h1>Hello ${this.myProp1}</h1>
      <h1>Hello ${this.myProp2}</h1>
      <button @click="${this.changeProperties}">changeProperties</button>
    `;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "lit-tomato": Tomato;
  }
}

i expected to property 'myProp1' never change. but result image

and console output is image

'myProp1' hasChagned always return false, but changed with other property changing. if i don't change 'myPropr2' 'myProp1' is not changed.

so, i think it is bug. so i made issue.

sorvell commented 3 years ago

The hasChanged method does not prevent the property value from changing, it merely prevents the set from being considered as a change that should trigger an update. If you'd like to create a property that shouldn't change or validate before changing, you should create your own accessor, for example:

_myProp1 = "original-myProp1";
@property({reflect: true}) // note you can still install property options if desired, 
// but it's not necessary unless you want to customize how attributes are handled.
get myProp1() {
  return this._myProp1;
}

set myProp1(value) {
  if (value === /* some acceptable value */) {
    const oldValue = this.myProp1;
    this._myProp1 = value;
    this.requestUpdate('myProp1', oldValue);
  }
}

Hope that resolves the issue. Please feel free to re-open if you have further questions.