Home > Mobile >  How to pass data, when ngModel is removed?
How to pass data, when ngModel is removed?

Time:05-20

I am using MatDialog and I need to work with the value of the input field and also want to validate it.

<input matInput [(ngModel)]="name" formControlName="name">
data: {name: this.name, animal: this.animal},

Well, this gives me this warning:

It looks like you're using ngModel on the same form field as formControlName. Support for using the ngModel input property and ngModelChange event with reactive form directives has been deprecated in Angular v6 and will be removed in a future version of Angular.

For more information on this, see our API docs here:
https://angular.io/api/forms/FormControlName#use-with-ngmodel

Now I have changed it to:

<input matInput formControlName="name">
data: {name: this.formMain.get('name')?.value, animal: this.animal},

That works for my name input field. But I have another input field (animal), which is inside the dialog and looks like this:

<input matInput [(ngModel)]="data.animal" formControlName="animal">

Now when I remove ngModel, then how can I make it work?

See the full code on StackBlitz.

CodePudding user response:

This is about two separate subjects: -

  1. Reactive Forms versus template driven Forms
  2. Passing Data to a MatDialogRef

There is a lot of info out there around reactive forms and the use of "formControlName" instead of [(ngModel])

https://blog.angular-university.io/introduction-to-angular-2-forms-template-driven-vs-model-driven/

Passing data to a MatDialogRef can be confusing but you should have a constructor like this in your dialog component: -

  constructor(public dialogRef: MatDialogRef<SomeDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any) {}

Then in you code to initiate this dialog: -

// some code to get the correct animal and set 'this.animal' ??
this.dialog.open(SomeDialogComponent, {
      data: { name: this.formMain.get('name')?.value, animal: this.animal }
    });

So in your dialog component you get reference the "received" data via the injected values.

  ngOnInit(): void {
    console.log(this.data?.animal);
  }

CodePudding user response:

Okay let's see :)

We have different possibilities to get the input text values in angular. Currently you are using two way data binding, which means that the [] around ngModel is the path from TypeScript value to HTML template. The () goes vice versa, it updates the value in the TypeScript according to the changes you made in the HTML.

So of course we might remove ngModel and get the value of the variable manually into the input with something like:

<input [value]="data.animal" #form>

Still we are missing the other way around, so probably we should add a button or similar and just use a (click) event to update the variable in the TypeScript file after changes in the html.

<button (click)="updateValue(form.value)">Clickme</button>

After creating the function this should work fine.

Of course there is another possibility using ViewChild references. So first define the reference like previously.

<input type="text" id="form" name="form" #form>

Then in the TypeScript file we declare the reference to the ViewChild.

@ViewChild('form', {static: true}) formElement: ElementRef;
mydata:string="";
constructor(formElement: ElementRef){
  this.formElement = formElement;
}

Then mydata will contain the string entered into the input field. The value can also be set again on the input field as default.

You could as well use the native html API with something like document.getElementById and fetch the value of the input, but I will omit this at this point as I would think that the other possibilities are convenient enough.

If you want yo use formControlName there is also a possibility.

<form [formGroup]="nameForm">
<p>
   <input type="text" id="name" name="name" formControlName="name">
</p>
</form>

And in the TypeScript file we can access the input like.

constructor( private formBuilder: FormBuilder) {
 this.nameForm = this.formBuilder.group({
   name: ''
 });
}
onClick() {
  this.myusername=this.nameForm.get('name')?.value;
  console.log('it does nothing', this.nameForm.get('name'));
}

Or you could just use the blur event on the input and send the value using the $event pipeline.

<p><input type="text" (blur)="blurEvent($event)">

Will be accessed like

blurEvent(event: any) {
  this._value = event.target.value;
}

Hope this helps.

CodePudding user response:

Short Explanation

You are just passing non existing data to the MatDialog's close output.

The data.animal you are referring to in the template is just the data sent from the caller to the MatDialog. That is why it is injected into it. At the point of injection your answer doesn't exist yet. And you are binding the input field to your FormGroup, not the MAT_DIALOG_DATA.

In the original code ngModel was bound straight to the MAT_DIALOG_DATA, so there this wasn't an issue.

Option 1: Pass the data from the Form, not the MatDialog

All u need to change is this line, in dialog-overview-example-dialog.html:

<button mat-button [mat-dialog-close]="formDialog.value.animal" cdkFocusInitial>

Simple as that, you were very close. Here is the fix on Stackblitz.

Option 2: Set the data on the MatDialog

You can also listen to the changes on your form and set the data value on the MatDialog accordingly like this:

this.formDialog.valueChanges.subscribe(val => {
      this.data.animal = val.animal;
});

Here's an example of that on Stackblitz as well.

Option 3: Create your own function

In template:

<button mat-button (click)="send()" cdkFocusInitial>

In typescript:

send(): void {
    this.dialogRef.close(this.formDialog.value.animal);
}

And another final Stackblitz example for you.

  • Related