dwp
dwp

Reputation: 958

NgModel is not working correctly in Angular 5

I have a problem like this. I am creating a web application with angular 5, Nodejs and MongoDB. To send data to the database I have created an HTML file like this.

<div class="row">
  <div class="col s12 m6">
    <div class="card blue-grey darken-1">
      <div class="card-content white-text">
        <div class="row">
          <div class="col s5">
            <form #employeeForm="ngForm" (ngSubmit)="onSubmit(employeeForm)">
              <input type="hidden" name="_id" #_id="ngModel" [(ngModel)]="employeeService.selectedEmployee._id">
              <div class="row">
                <div class="input-field col s12">
                  <input type="text" name="name" #name="ngModel" [(ngModel)]="employeeService.selectedEmployee.name" placeholder="Enter full name" required>
                  <label>Name :
                    <label class="red-text">*</label>
                  </label>
                </div>
              </div>
              <div class="row">
                <div class="input-field col s12">
                  <input type="text" name="position" #name="ngModel" [(ngModel)]="employeeService.selectedEmployee.position" placeholder="Eg : Snr. Developer">
                  <label>Position :</label>
                </div>
              </div>
              <div class="row">
                <div class="input-field col s12">
                  <input type="text" name="office" #name="ngModel" [(ngModel)]="employeeService.selectedEmployee.office" placeholder="Enter office location">
                  <label>Office :</label>
                </div>
              </div>
              <div class="row">
                <div class="input-field col s12">
                  <input type="text" name="salary" #name="ngModel" [(ngModel)]="employeeService.selectedEmployee.salary" placeholder="Salary per annum">
                  <label>Salary :</label>
                </div>
              </div>
              <div class="row">
                <div class="input-field col s12">
                  <button class="btn btn-custom right" type="button" (click)="resetForm(employeeForm)">Reset</button>
                  <button class="btn btn-custom right" type="submit" [disabled]="!employeeForm.valid">Submit</button>
                </div>
              </div>
            </form>
          </div>
          <div class="col s7">

          </div>
        </div>
      </div>
    </div>
  </div>
</div>

To send data to the backend I have created a method like this in the components.ts file. This the code in that file.

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';

import { EmployeeService } from '../shared/employee.service';
import { Employee } from '../shared/employee';

declare var M: any;

@Component({
  selector: 'app-employee',
  templateUrl: './employee.component.html',
  styleUrls: ['./employee.component.css'],
  providers: [EmployeeService]
})
export class EmployeeComponent implements OnInit {

  constructor(private employeeService: EmployeeService) { }

  ngOnInit() {
    this.resetForm();
    this.refreshEmployeeList();
  }
  resetForm(form?: NgForm) {
    if (form) {
      form.reset();
      this.employeeService.selectedEmployee = {
        _id: '',
        name: '',
        position: '',
        office: '',
        salary: null
      };
    }
  }

  onSubmit(form: NgForm) {
    if (form.value._id === '') {
      this.employeeService.postEmployee(form.value).subscribe((res) => {
        this.resetForm(form);
        M.toast({ html: 'Saved successfully', classes: 'rounded' });
      });
    }
  }

  refreshEmployeeList() {
    this.employeeService.getEmployeeList().subscribe( (res) => {
      this.employeeService.employees = res as Employee[];
    });
  }

  onEdit(emp: Employee) {
    this.employeeService.selectedEmployee = emp;
  }

  onDelete(_id: string, form: NgForm) {
    if (confirm('Are you sure to delete this record ?') === true) {
      this.employeeService.deleteEmployee(_id).subscribe((res) => {
        this.refreshEmployeeList();
        this.resetForm(form);
        M.toast({ html: 'Deleted successfully', classes: 'rounded' });
      });
    }
  }
}

And my service file is like this.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';

import { Employee } from './employee';

@Injectable()
export class EmployeeService {
  selectedEmployee: Employee;
  public  employees: Employee[];
  readonly baseURL = 'http://localhost:3000/employees';

  constructor(private http: HttpClient) { }

  postEmployee(employee: Employee) {
    return this.http.post(this.baseURL, employee);
  }

  getEmployeeList() {
    return this.http.get(this.baseURL);
  }

  putEmployee(emp: Employee) {
    return this.http.put(this.baseURL + `/${emp._id}`, emp);
  }

  deleteEmployee(_id: string) {
    return this.http.delete(this.baseURL + `/${_id}`);
  }

}

My app.module.ts file is like this.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { EmployeeComponent } from './employee/employee.component';


@NgModule({
  declarations: [
    AppComponent,
    EmployeeComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

And my employee model class looks like this.

export class Employee {
  public _id: string;
  public name: string;
  public position: string;
  public office: string;
  public salary: number;
}

When I hit ng serve it is giving me an error like this.

ERROR TypeError: Cannot read property '_id' of undefined
    at Object.eval [as updateDirectives] (EmployeeComponent.html:8)
    at Object.debugUpdateDirectives [as updateDirectives] (core.js:14697)
    at checkAndUpdateView (core.js:13844)
    at callViewAction (core.js:14195)
    at execComponentViewsAction (core.js:14127)
    at checkAndUpdateView (core.js:13850)
    at callViewAction (core.js:14195)
    at execComponentViewsAction (core.js:14127)
    at checkAndUpdateView (core.js:13850)
    at callWithDebugContext (core.js:15098)

Yesterday also I asked this question I think my explanation was not clear. So Today I am asking it with more description. Can someone help me to solve this issue? Thank You Very much.

Upvotes: 0

Views: 892

Answers (2)

Dan Chase
Dan Chase

Reputation: 1042

I hope this helps, but typescript still transpiles to javascript, which really has no way to know that the currentemployee is a class, which is why it says it cannot find the I'd field. However, you can allocate the object which WILL have an I'd field, yet I dont see any place where this is occurring. I think the angular binding is not working because you have only declared, but not initialized the object.

Maybe allocate the employee..

public currentEmployee : Employee = new Employee();

Please forgive any mistakes, just a general idea to show, typing this at 3am on my android in bed unable to sleep.

Upvotes: 0

Prachi
Prachi

Reputation: 3574

Try this, though it will generalize your object, it will work:

In your EmployeeService, declare selectedEmployee as below

selectedEmployee: any = {};

Upvotes: 1

Related Questions