Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

Edit form in angular

Suggested Videos
Part 56 - Angular route loading indicator | Text | Slides
Part 57 - Angular canactivate guard example | Text | Slides
Part 58 - Passing data between components in angular | Text | Slides

In this video we will discuss editing and updating data in Angular. To set the expectations right, we will be updating data on the client side. We will discuss persisting the data to a database table in our upcoming videos when we implement the server side service.


We are going to modify "Create Employee Form" so it supports both 
  • Creating a new employee
  • Editing and updating an existing employee

Changes in Root Module file (app.module.ts) : Change the path in the following route from "create" to "edit/:id"

Existing Route

{
  path: 'create',
  component: CreateEmployeeComponent,
  canDeactivate: [CreateEmployeeCanDeactivateGuardService]
}

Updated Route to support both creating a new employee and editing an existing employee. If the id route parameter value is 0, then the form will be used to create a new employee. If the id value is not 0, then the form will be used to edit an existing employee.

{
  path: 'edit/:id',
  component: CreateEmployeeComponent,
  canDeactivate: [CreateEmployeeCanDeactivateGuardService]
}

Changes in create-employee.component.html : The value attribute of email and phone radio buttons is set to Email and Phone respectively to match with the employee data. Otherwise when we select to edit an existing employee, his saved contact preference value will not be bound to the correct radio button. The change is bolded and italicized.

<div class="form-group" [class.has-error]="contactPreference.invalid
        && contactPreference.touched">
    <label class="control-label">Contact Preference</label>
    <div class="form-control">
        <label class="radio-inline">
            <input type="radio" required #contactPreference="ngModel"
                   name="contactPreference" value="Email"
                   [(ngModel)]="employee.contactPreference"> Email
        </label>
        <label class="radio-inline">
            <input type="radio" required #contactPreference="ngModel"
                   name="contactPreference" value="Phone"
                   [(ngModel)]="employee.contactPreference"> Phone
        </label>
    </div>
    <span class="help-block" *ngIf="contactPreference.errors?.required
                                        && contactPreference.touched">
        Contact Preference is required
    </span>
</div>

The required attribute value is updated to include capital E in Email for the validation to work correctly.

<div class="form-group" [class.has-error]="email.invalid">
    <label for="email" class="control-label">Email</label>
    <input id="email" [required]="contactPreference.value=='Email'"
           type="text" class="form-control" [(ngModel)]="employee.email"
           #email="ngModel" name="email"
           pattern="^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$">
    <span class="help-block" *ngIf="email.errors?.required">
        Email is required
    </span>
    <span class="help-block" *ngIf="email.errors?.pattern && email.touched">
        Email is Invalid
    </span>
</div>

The required attribute value is updated to include capital P in Phone for the validation to work correctly.

<div class="form-group" [class.has-error]="phoneNumber.invalid">
    <label for="phoneNumber" class="control-label">Phone Number</label>
    <input id="phoneNumber" [required]="contactPreference.value=='Phone'"
           #phoneNumber="ngModel" class="form-control" type="text"
           name="phoneNumber" [(ngModel)]="employee.phoneNumber">
    <span class="help-block" *ngIf="phoneNumber.errors?.required">
        Phone Number is required
    </span>
</div>

The value attribute of male and female radio buttons is set to Male and Female respectively to match with the employee data. Otherwise when we select to edit an existing employee, his saved gender value will not be bound to the correct radio button. The change is bolded and italicized.

<div class="form-group"
    [class.has-error]="gender.invalid && gender.touched">
    <label class="control-label">Gender</label>
    <div class="form-control">
        <label class="radio-inline">
            <input type="radio" name="gender" required #gender="ngModel"
                   value="Male" [(ngModel)]="employee.gender"> Male
        </label>
        <label class="radio-inline">
            <input type="radio" name="gender" required #gender="ngModel"
                   value="Female" [(ngModel)]="employee.gender"> Female
        </label>
    </div>
    <span class="help-block" *ngIf="gender.errors?.required && gender.touched">
        Gender is required
    </span>
</div>

Notice, I have included ngIf to show the "Image Preview" button and the image, only if there is a value in the photoPath field. This avoids unnecessary 404 errors in the browser console.

<div class="form-group">
    <button type="button" (click)="togglePhotPreview()" class="btn btn-primary"
            *ngIf="employee.photoPath !=='' && employee.photoPath !==null">
        {{previewPhoto ? "Hide " : "Show " }} Preview
    </button>
</div>

<div class="form-group">
    <img [src]="employee.photoPath" height="200" width="200"
    *ngIf="previewPhoto && employee.photoPath !=='' && employee.photoPath !==null"/>
</div>

Changes in create-employee.component.ts :  Change ngOnInit() and saveEmployee() employee methods as shown below. Also please do not forget to include the following panelTitle property.

panelTitle: string;

// Subscribe to route parameter changes and react accordingly
ngOnInit() {
  this._route.paramMap.subscribe(parameterMap => {
    const id = +parameterMap.get('id');
    this.getEmployee(id);
  });
}

saveEmployee(empForm: NgForm): void {
  const newEmployee = Object.assign({}, this.employee);
  this._employeeService.save(newEmployee);
  empForm.reset();
  this._router.navigate(['list']);
}

private getEmployee(id: number) {
  // If the id is 0, we want to create a new employeeSo we intialise the employee 
  // property with an Employee object with all properties set to nullThe template 
  // is bound to this employee property so all the form fields are displayed blank, 
  // to enter details of a new employee we want to create
  if (id === 0) {
    this.employee = {
      id: null,
      name: null,
      gender: null,
      contactPreference: null,
      phoneNumber: null,
      email: '',
      dateOfBirth: null,
      department: null,
      isActive: null,
      photoPath: null
    };
    // Resetting the form, resets any previous validation errors
    this.createEmployeeForm.reset();
    this.panelTitle = 'Create Employee';
  } else {
    // If the Id is not 0, then retrieve the respective employee using the employee 
    // service. Copy the values into a new object and assign that object as the value 
    // for the employee property. Otherwise the employee property holds a reference 
    // to the employee object in the array in the EmployeeService. This means any 
    // changes we make on the form are automatically saved, without we explicitly
    // saving by clicking the Save button.
    this.employee = Object.assign({}, this._employeeService.getEmployee(id));
    this.panelTitle = 'Edit Employee';
  }
}

Changes in employee.service.ts : Change save() method as shown below

save(employee: Employee) {
  if (employee.id === null) {
    // reduce() method reduces the array to a single value. This method executes
    // the provided function for each element of the array (from left-to-right)
    // When we implement the server side service to save data to the database
    // table, we do not have to compute the id, as the server will assing it
    const maxId = this.listEmployees.reduce(function (e1, e2) {
      return (e1.id > e2.id) ? e1 : e2;
    }).id;
    employee.id = maxId + 1;

    this.listEmployees.push(employee);
  } else {
    const foundIndex = this.listEmployees.findIndex(e => e.id === employee.id);
    this.listEmployees[foundIndex] = employee;
  }
}

Changes in display-employee.component.html : Bind editEmployee() method to the click event of the "Edit" button

<button class="btn btn-primary" (click)="editEmployee()">Edit</button>

Changes in display-employee.component.ts : Include the following editEmployee() method

editEmployee() {
  this._router.navigate(['/edit', this.employee.id]);
}

Changes in app.component.html : Change the "Create" menu item to point to our new route "edit/0".

<li>
    <a routerLink="edit/0">Create</a>
</li>

Next Video : Delete operation in Angular

angular crud tutorial

No comments:

Post a Comment

It would be great if you can help share these free resources