Reputation: 11
I am having an issue with my cancel button in Angular project. Here's the problem, once I click edit on my customers field, two buttons appear: save and cancel. Now save functionality works fine but if I make some changes in some of the input fields and click cancel, it still saves my changes and of course, it shouldn't save. Here's my code:
customer-detail.component.html
<div class="p-2 text-primary">
<h4>Customer Detail</h4>
</div>
<div class="card m-1 p-1" *ngIf="customer">
<div class="card-header text-white bg-info">
<h5 class="card-title">{{ customer.firstName + ' ' + customer.lastName }}
<button (click)= "deleteCustomer()" class="btn btn-danger btn-sm float-right" *ngIf="orders && orders.length == 0">Delete</button>
</h5>
</div>
<div class="card-body bg-light">
<form #form="ngForm">
<h5 class="card-title text-info">Contact Info
<button class="btn btn-sm btn-info float-right" *ngIf="mode=='view'" (click)="mode='edit'">Edit</button>
<div class="btn-group-sm float-right">
<button class="btn btn-sm btn-info" (click)="saveCustomer(form)" *ngIf="mode=='edit'"
[disabled]="form.invalid">Save</button>
<button class="btn btn-sm btn-info" (click)="mode='view'" *ngIf="mode=='edit'">Cancel</button>
</div>
</h5>
<div class="card-text" *ngIf="mode=='view'">
<div class="row ">
<div class="col-6">
<strong>First Name:</strong> {{ customer.firstName}}
</div>
<div class="col-6">
<strong>Last Name:</strong> {{ customer.lastName}}
</div>
</div>
<div class="row">
<div class="col-6">
<strong>Email:</strong> {{ customer.email}}
</div>
<div class="col-6">
<strong>Phone Number:</strong> {{ customer.phoneNumber}}
</div>
</div>
</div>
<div class="card-text" *ngIf="mode=='edit'">
<div class="row ">
<div class="col-2">
<label for="firstName">First Name:</label>
</div>
<div class="col-3">
<input name="firstName" required id="firstName" class="form-control" [(ngModel)]="customer.firstName"
[class.is-invalid]="firstName.invalid && firstName.touched" #firstName="ngModel" />
<span class="text-danger" *ngIf="firstName.invalid && firstName.touched">
First Name is required.
</span>
</div>
<div class="col-1">
</div>
<div class="col-2">
<label for="lastName">Last Name:</label>
</div>
<div class="col-3">
<input type="text" required id="lastName" name="lastName" class="form-control"
[class.is-invalid]="lastName.invalid && lastName.touched" [(ngModel)]="customer.lastName"
#lastName="ngModel" />
<span class="text-danger" *ngIf="lastName.invalid && lastName.touched">
Last Name is required.
</span>
</div>
</div>
<p></p>
<div class="row">
<div class="col-2">
<label for="email">Email:</label>
</div>
<div class="col-3">
<input type="text" required email id="email" name="email" class="form-control"
[class.is-invalid]="email.invalid && email.touched" [(ngModel)]="customer.email" #email="ngModel" />
<span class="text-danger" *ngIf="email.errors?.required && email.touched">
Email is required.
</span>
<span class="text-danger" *ngIf="email.errors?.email && email.touched">
Invalid Email
</span>
</div>
<div class="col-1">
</div>
<div class="col-2">
<label for="phoneNumber">Phone Number:</label>
</div>
<div class="col-3">
<input type="tel" required id="phoneNumber" maxlength="9" pattern="^[0-9\.]+$"
name="phoneNumber" class="form-control" [class.is-invalid]="phoneNumber.invalid && phoneNumber.touched"
[(ngModel)]="customer.phoneNumber" #phoneNumber="ngModel" />
<span class="text-danger" *ngIf="phoneNumber.errors?.required && phoneNumber.touched">
Phone Number is required.
</span>
<span class="text-danger" *ngIf="phoneNumber.errors?.pattern && phoneNumber.touched">
Invalid Phone Number
</span>
</div>
</div>
</div>
</form>
<p></p>
<p></p>
<h5 class="card-title text-info">Orders
<button class="btn btn-sm btn-info float-right" [routerLink]="['/orders/create']"
[queryParams]="{customerId: customer.id}">Add Order</button>
</h5>
<div *ngIf="orders && orders.length == 0">
No Orders.
</div>
<div *ngIf="orders && orders.length > 0 && orderLines">
<table class="table table-sm">
<thead>
<th>Order ID</th>
<th>Order Date</th>
<th>Due Date</th>
<th>Status</th>
<th>Item Count</th>
<th>Order Sum</th>
<th></th>
</thead>
<tbody>
<tr *ngFor="let order of ordersWSum">
<td><a [routerLink]="['/orders/detail', order.id]">{{ order.id }}</a></td>
<td>{{ order.orderDate }}</td>
<td>{{ order.dueDate }}</td>
<td>{{ order.status }}</td>
<td>{{ order.itemCount }}</td>
<td>{{ order.orderTotal }}</td>
<td>
<button class="btn btn-sm btn-info" [routerLink]="['/orders/detail', order.id]">
<i class="fa fa-info-circle"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div>
<a [routerLink]="['/customers', {id: id}]" queryParamsHandling="preserve">
Back to Customer List
</a>
</div> ```
If you want to view live version and see what exactly is the problem, go to <https://customersandorders.netlify.app>. There you will find list of customers, click on one of them and then click edit. Try out cancel button after you made some change in any of four input fields and see for yourself
Upvotes: 1
Views: 8732
Reputation: 1
For cases where buttons are inside the form, using ng-submit and ng-model-options="{ updateOn: 'submit' }" on input fields, then adding 'type=button' attribute to cancel button element (so submit isn't triggered) is a quick solution.
Upvotes: 0
Reputation: 1072
Add type="button"
to your cancel button. Buttons in most/all browsers default to type submit which is submitting your form.
Edit:
Ok based on the link hidden at the bottom of your code block I think you're just misunderstanding what your error is. In the example app you give, if you click save you get an HTTP request and if you click cancel you don't, so the cancel button is not saving your form.
Your issue is that you expect your cancel button to revert any changes made to your fields e.g. forename/surname but you have not actually programmed that to happen. Your form fields are directly bound to your values and your cancel button has nothing that would revert this.
Tl;DR if your fields and inputs are bound to the same value then clicking a cancel button isn't going to magically revert your field values. Either seperate these values and copy the inputs into the fields when you click save, or keep them the same and reload them when you press cancel.
Upvotes: 6
Reputation: 1
This is a really annoying problem, it took me hours to figure out the reason during my first project:
Every button in a form is treatet as type "submit";
In your case, it is a bit complicated to explain but it looks like the Cancel button is calling the action of the Edit button because it is the first function in the form.
Define an ngSubmit in the form, like this:
`<form (ngSubmit)="saveCustomer(form)" #form="ngForm">`
And then, the Edit button will be:
`<button class="btn btn-sm btn-info float-right" *ngIf="mode=='view'" (click)="mode='edit'" type="submit">Edit</button>`
And the Cancel button will be:
<button class="btn btn-sm btn-info" (click)="mode='view'" *ngIf="mode=='edit'" type="button">Cancel</button>
Upvotes: 0