33

I know how to fix my component using a different name for the output value of this component.

Let me share my code

import { Component, Input, Output, EventEmitter } from "@angular/core";
import { TranslationPipe } from "../pipes/translation.pipe";

@Component({
  selector: "msisdn-confirm",
  template: `
    <div class="msisdn-confirm">
      <div>
        <input type="text" [(ngModel)]="m1" />
      </div>
      <div>
        <input type="text" [(ngModel)]="m2" />
      </div>
      <p class="error">{{ message }}</p>
    </div>
  `,
})
export class MsisdnConfirm {
  message: string;
  @Output("mobile") emitter: EventEmitter<string> = new EventEmitter<string>();
  @Input("mobile") set setMobileValue(value) {
    this.msisdn_confirm = this.msisdn = value;
  }

  set m1(value) {
    this.msisdn = value;
    if (this.valid()) {
      console.log("emit" + this.msisdn);
      this.emitter.emit(this.msisdn);
    }
  }

  set m2(value) {
    this.msisdn_confirm = value;
    if (this.valid()) {
      console.log("emit" + this.msisdn);
      this.emitter.emit(this.msisdn);
    }
  }

  get m1(): string {
    return this.msisdn;
  }
  get m2(): string {
    return this.msisdn_confirm;
  }

  msisdn: string;
  msisdn_confirm: string;

  constructor() {}

  private valid(): boolean {
    if (!/06[0-9]{8}/.test(this.msisdn)) {
      this.message = new TranslationPipe().transform(
        "Het mobiele nummer is incorrect, (bijvoorbeeld: 0612345678)"
      );
      return false;
    } else if (this.msisdn != this.msisdn_confirm) {
      this.message = new TranslationPipe().transform(
        "De mobiele nummers komen niet overeen"
      );
      return false;
    }
    this.message = null;
    return true;
  }
}

So this is a very basic component which validates two strings to be a "valid" dutch Mobile number, so a confirm box so to say. Now I can get my value in the parent component by doing something like

(mobile)="myParam = $event"

What I want is to use it like

[(mobile)]="myParam"

This only works for setting though, is this not supported on custom components?

Marin Takanov
  • 1,079
  • 3
  • 19
  • 36
Mathijs Segers
  • 6,168
  • 9
  • 51
  • 75

2 Answers2

57

For this compact syntax to work the input and output need to follow specific naming rules

[(mobile)]="myParam"
  @Output('mobileChange') emitter: EventEmitter<string> = new EventEmitter<string>();
  @Input('mobile') set setMobileValue(value) {
    this.msisdn_confirm = this.msisdn = value;
  }

Renaming inputs and outputs by passing a string parameter to the decorator is discourages. Rather use

  @Output() mobileChange: EventEmitter<string> = new EventEmitter<string>();
  @Input() set mobile(value) {
    this.msisdn_confirm = this.msisdn = value;
  }
Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
18

Another example of Gunter's code above that may help:

export class TaskBook {
  public taskBookID: number;
  public title: String; 
}

Inside component code:

   ....
    <input type="text"  pInputText [(ngModel)]="data!.title" (change)="onDataChange()" />
   ....

 @Component({
  selector: 'taskbook_edit',
  templateUrl: './taskbook_edit.component.html' 
})
    export class TaskbookEditComponent { 

      @Input() data: TaskBook;
      @Output() dataChange = new EventEmitter<TaskBook>();

      constructor() { } 

      onDataChange() { 
        this.dataChange.emit(this.data);
      }  
    }

Outside in calling component:

<taskbook_edit  [(data)]="taskbookObj" ></taskbook_edit>

 public taskbookObj: TaskBook;
davaus
  • 1,145
  • 13
  • 16
  • 3
    Günter's answer was reusing the OP's code, but I think yours is clearer for anyone else still not very familiar with some parts of Angular syntax. Thank you for this example! – Carrm Mar 18 '19 at 16:18
  • 3
    That was my intent :) Thanks for the comment. – davaus Mar 20 '19 at 05:04