Manage Attribute Dependencies in a Getter

An attribute in HTML turns into a property assignment in JavaScript. In both cases, the order of assignment is not guaranteed. To check for the existence of other attributes, use a getter.

Use a getter reference in the template. Don’t use the @api getter, and don’t use an @api setter that relies on a value from another @api property.

Let’s assume we have a datatable component that displays a check mark on selected rows. We have two separate attributes rows and selectedRows, which have a dependency on the other.

<template>
  <c-datatable selected-rows="1,2" rows="1,2,3,4"> </c-datatable>
</template>

Since the order in which the attributes are received isn’t guaranteed, use getters to check the dependency.

export default class Datatable extends LightningElement {
  @track state = {};

  @api
  get rows() {
    return this.state.rows;
  }

  set rows(value) {
    this.state.rows = value;

    // Check to see if the rows have
    // been marked as selected.
    if (this.state.selectedRows && !this.selectedRowsSet) {
      this.markSelectedRows();
      this.selectedRowsSet = true;
    }
  }

  @api
  set selectedRows(value) {
    this.state.selectedRows = value;

    // If rows haven’t been set,
    // then we can't mark anything
    // as selected.
    if (!this.state.rows) {
      this.selectedRowsSet = false;
      return;
    }

    this.markSelectedRows();
  }

  get selectedRows() {
    return this.state.selectedRows;
  }

  markSelectedRows() {
    // Mark selected rows.
  }
}

Using getters and setters ensures that the public API contract is easily enforced. A component shouldn’t change the value of a property that’s annotated with @api.

Normalize data in the setter if something depends on that value at set time, for example, to append a CSS class programmatically on an element. Return the original value in the getter. Normalization can also be done in the getter so that the template has access to a value even if the consumer doesn’t set anything.

@track state = {
    selected : false
};

privateSelected = 'false';

@api
get selected() {
    return this.privateSelected;
}
set selected(value) {
    this.privateSelected = value;
    this.state.selected = normalizeBoolean(value)
}