34

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?

2 Answers 2

59

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;
  }
Sign up to request clarification or add additional context in comments.

9 Comments

Hence it's good to put these things on stack overflow, it's my main source for docs anyway.
pascal also wrote about this subject, including a plunk: blog.thoughtram.io/angular/2016/10/13/…
Updated link to the angular.io doc section: angular.io/guide/template-syntax#two-way-binding---
Updated updated link to the angular.io doc section: angular.io/guide/two-way-binding
|
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;

2 Comments

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!
That was my intent :) Thanks for the comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.