How to convert this computed property from classic to native?

How to convert this classic syntax(isNameChanged - property) to native class? is is possible? or any other workaround for this?

In hbs,

<Input @value="first_name">
<Input @value="last_name">
<button {{action "save">Save</button>
<button {{action "back"> Back </button>

In controller,

import Controller from '@ember/controller';

export default Controller.extend({
  isNameChanged: computed('first_name',  'last_name', {
    set(key, value) {
      return value;
    },
    get() {
      return true;
    }
 });

actions:{
  save() {
      //saveRecord Method
  }
  back() {
     if(isNameChanged) {
        //Throw name Change error, Please save the name, before back.
      }
    this.send('goBack');
   }
});

Hi @M_D, just as a note I reformatted your post to put the code in code blocks (triple backticks at the start and end) for readability.

There are a lot of ways you could rewrite this. For example my preference is to create my own Input component which uses one-way binding, so i have more control over how the updates work.

That said the most straightforward way to do this might be something like:

  @tracked _first_name;
  @tracked _last_name;
  @tracked isNameChanged = false;

  get first_name() {
    return this._first_name;
  }
  set first_name(value) {
    this._first_name = value;
    this.isNameChanged = true;
  }

  get last_name() {
    return this._last_name;
  }
  set last_name(value) {
    this._last_name = value;
    this.isNameChanged = true;
  }

Is there any other methods, if I have more than 10 input field, need 10 get set separately. Is anything possible by computed like classic?

Not directly. The computed version is basically using an observer pattern which is against the autotracking/octane model.

In that case I’d recommend writing your own one-way-bound input component, and hooking into its change/update action to set both attributes.

A minimal version would look something like the below. Note that for brevity I’m using some helpers from ember-composable-helpers as well as the set helper from ember-set-helper. These could be easily adapted to not need those helpers.

Input component

// components/my-cool-input.hbs
<input
  value={{readonly @value}}
  type={{@type}}
  disabled={{@disabled}}
  autocomplete={{@autocomplete}}
  min={{@min}}
  max={{@max}}
  step={{@step}}
  minlength={{@minlength}}
  maxlength={{@maxlength}}
  multiple={{@multiple}}
  placeholder={{@placeholder}}
  {{on "change" (optional @onChange))}}
  {{on
    "input"
    (pick "target.value" (optional @onChange)))
  }}
  {{on "click" (optional @onClick)}}
  {{on "focus" (optional @onFocus)}}
  {{on "blur" (optional @onBlur)}}
  {{on "keyup" (optional @onKeyUp)}}
  {{on "keydown" (optional @onKeyDown)}}
  {{on "keypress" (optional @onKeyPress)}}
  {{on "mouseup" (optional @onMouseUp)}}
  {{on "mousedown" (optional @onMouseDown)}}
  ...attributes
/>

Controller

  ...
  @tracked first_name;
  @tracked last_name;
  @tracked isNameChanged = false;
  ...

Template

<MyCoolInput
  @value={{this.first_name}}
  @onChange={{queue
    (set this "first_name")
    (set this "isNameChanged" true)
  }}
/>
<MyCoolInput
  @value={{this.last_name}}
  @onChange={{queue
    (set this "last_name")
    (set this "isNameChanged" true)
  }}
/>
... and so on

If you didn’t want to use queue/set you could just drop an action on the controller like:

  @action
  inputChanged(attribute, value) {
    this[attribute] = value;
    this.isNameChanged = true;
  }

and then in the template:

<MyCoolInput
  @value={{this.last_name}}
  @onChange={{fn this.inputChanged "last_name"}}
/>
...