ngModel in MatDialog not updating model when value entered in dialog

Issue

I’m sure I must be missing something terribly simple but I’ve been thrashing about with this for a full day now…
I have a MatDialog with one text input.
Upon closing the dialog this value needs to be sent to the parent component.
the matDialog receives data from the parent component fine and displays it in the text input.
However, when I type a new value in the input, the model is not updated and therefore the data is never returned.

The MatDialog Component code is below.

import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';

@Component({
  selector: 'app-itemnote-dialog',
  template: 
  `<h4 mat-dialog-title>Add short note for:<br> {{data.description}}</h4>

  <mat-dialog-content>
      <form #inp>
          <mat-form-field>
              <input  matInput ([ngModel])="data.note" [value]="data.note">
          </mat-form-field>
      </form>
  </mat-dialog-content>
  
  <mat-dialog-actions>
      <button class="mat-raised-button primary" (click)="close()">Close</button>
      <button mat-raised-button color="primary" class="mat-raised-button" (click)="save()">Save</button>
  </mat-dialog-actions>`,
  styleUrls: ['./itemnote-dialog.component.css']
})
export class ItemNoteDialogComponent  {
  constructor(public dialogRef: MatDialogRef<ItemNoteDialogComponent>,@Inject(MAT_DIALOG_DATA) public data:any) { 
    console.log(this.data); //logs correct data
  }

  save(){
    console.log(this.data); //logs the same data as in constructor even if changed in dialog text field
    this.dialogRef.close(this.data);
  }
  close(){
    this.dialogRef.close()
  }
}

I have also tried using [matDialogClose]="data.note" and [matDialogClose]="data" on the save button instead of the save function with the same (lack of) result.
I’ve tried injecting the data as private and assigning it to a variable in the dialog component;

@Inject(MAT_DIALOG_DATA) data

this.data = data

but the value of data.note never changes no matter what I’ve tried.

The function calling the dialog is:

public ItemNoteDialog(produce: Produce){
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.data = {description: produce.description, note: produce.note};

    this.dialog.open(ItemNoteDialogComponent, dialogConfig).afterClosed()
    .subscribe(response => {
      console.log("response: " + JSON.stringify(response));
    });
  }

One thing I’m not sure about (though I’ve tried both) is which app.module to import MatDialogModule and ItemNoteDialogComponent as I started with a template which has a submodule – which is the one I am working with.

So right now I have app.module:

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppRoutingModule } from './app.routing';
import { ComponentsModule } from './components/components.module';

import { AppComponent } from './app.component';
import { MatSortModule } from '@angular/material/sort';
import { MatDialogModule } from "@angular/material/dialog";

import { AgmCoreModule } from '@agm/core';
import { AdminLayoutComponent } from './layouts/admin-layout/admin-layout.component';
import { OrderSummaryDialogComponent } from './shared/order-summary-dialog/order-summary-dialog.component';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { ConfirmDialogComponent } from './shared/confirm-dialog/confirm-dialog.component';
import { MatButtonModule } from '@angular/material/button';
import { MatSelectModule } from '@angular/material/select';

import { ItemNoteDialogComponent } from '../app/current-order/itemnote-dialog/itemnote-dialog.component';
import { MatInputModule } from '@angular/material/input';


@NgModule({
  imports: [
    BrowserAnimationsModule,
    FormsModule,
    MatDialogModule,
    ReactiveFormsModule,
    HttpClientModule,
    ComponentsModule,
    RouterModule,
    AppRoutingModule,
    MatSortModule,
    MatButtonModule,
    MatSelectModule,
    MatInputModule,
    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
  ],
  declarations: [
    AppComponent,
    AdminLayoutComponent,
    OrderSummaryDialogComponent,
    ConfirmDialogComponent,
    ItemNoteDialogComponent
  ],
  exports:[MatSortModule, MatDialogModule],
  bootstrap: [AppComponent],
  entryComponents: [OrderSummaryDialogComponent]
})
export class AppModule { }

Note that I have other dialogs which only display data – these are working fine.

There is another module.ts – admin-layout.module.ts which declares the component which is calling the dialog, but I’ve found my dialogs only seem to work properly if they’re in app.module, I have tried putting this in admin-layout.module.ts, this seemed worse and of course I get errors if I put in both.

Here is the current state of admin-layout.module.ts

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AdminLayoutRoutes } from './admin-layout.routing';
import { DashboardComponent } from '../../dashboard/dashboard.component';
import { UserProfileComponent } from '../../user-profile/user-profile.component';
import { TableListComponent } from '../../item-list/table-list.component';
import { TypographyComponent } from '../../typography/typography.component';
import { IconsComponent } from '../../icons/icons.component';
// import { MapsComponent } from '../../maps/maps.component';
import { NotificationsComponent } from '../../notifications/notifications.component';
import { CurrentOrderComponent } from '../../current-order/current-order.component';
import { UpgradeComponent } from '../../upgrade/upgrade.component';
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule } from '@angular/material/input';
import { MatRippleModule } from '@angular/material/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatSelectModule } from '@angular/material/select';
import { MatTableModule } from '@angular/material/table';
import { MatSortModule } from '@angular/material/sort';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatPaginatorModule } from '@angular/material/paginator';
import { PastOrdersComponent } from '../../past-orders/past-orders.component';
import { LoginComponent } from '../../login/login.component';
import {MatDialogModule, MatDialogRef} from '@angular/material/dialog';
import {MatAutocompleteModule} from '@angular/material/autocomplete';
import { CallbackPipe } from '../../pipes/callback/callback.pipe';
import { AccountComponent } from '../../account/account.component';
import { NewsComponent } from '../../news/news.component';
//import { ItemNoteDialogComponent } from '../../current-order/itemnote-dialog/itemnote-dialog.component';



@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(AdminLayoutRoutes),
    FormsModule,
    ReactiveFormsModule,
    MatButtonModule,
    MatRippleModule,
    MatFormFieldModule,
    MatInputModule,
    MatSelectModule,
    MatTooltipModule,
    MatTableModule,
    MatSortModule,
    MatProgressSpinnerModule,
    MatAutocompleteModule,
    MatPaginatorModule,
    MatButtonModule,
    MatSelectModule,
    MatDialogModule
  ],
  declarations: [
    DashboardComponent,
    UserProfileComponent,
    TableListComponent,
    TypographyComponent,
    IconsComponent,
    NotificationsComponent,
    UpgradeComponent,
    CurrentOrderComponent,
    PastOrdersComponent,
    LoginComponent,
    CallbackPipe,
    AccountComponent,
    NewsComponent,
    // ItemNoteDialogComponent
  ],
  providers: []
})

export class AdminLayoutModule {}

Sooo… If someone could give me some indication of where I am going wrong, I’d greatly appreciate it!
Let me know if I’ve missed any crucial info-I’m fairly new to Angular 🙂

Oh, I’ve also tried adding changeDetectorRef in the dialog component which made no difference.

Solution

Try changing:

([ngModel])="data.note"

to:

[(ngModel)]="data.note"

🙂

Answered By – Jojofoulk

Answer Checked By – Pedro (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.