I have this simple HTML select to implement dropdown in Angular2 (TS) as shown below
<select id="pageSize" (change)="onPageSizeChanged($event, pagination.pageSize)">
<option value="10">10</option>
<option value="20">20</option>
<option value="50">50</option>
</select>
The previously selected value is kept in pagination.pageSize
variable. And on change of this I wanted to open a dialog box and wait for users response. If user, clicks cancel I want to revert the selection to the previously selected options.
onPageSizeChanged(event, oldValue) {
const response = window.confirm("Are you sure you want change the page size? Your edits will be lost?");
if (response) {
//... some code ...
} else {
//... here I want to revert the selection to previously selected option
}
}
Tried lot of different things but of no luck.
Please help, I am loosing my mind over this simple thing. I must be doing something stupid.
Tries #1 - Didn't work (Plunk - https://embed.plnkr.co/ILi12O/)
<select id="pageSize" [ngModel]="pageSize" (ngModelChange)="onPageSizeChanged($event, pagination.pageSize)">
<option value="10">10</option>
<option value="20">20</option>
<option value="50">50</option>
</select>
onPageSizeChanged(event, oldValue) {
const response = window.confirm("Are you sure you want change the page size? Your edits will be lost?");
if (response) { //go ahead so something }
else { this.pageSize = oldValue; }
}
Add ngModelChange
to track the model changes. Keep the change if the dialog confirms for the next change, otherwise set back the value. Local template variable (#select) make a little easier to track. I made changes based on your plunker:
HTML:
<select #select id="pageSize" [ngModel]="pageSize" (ngModelChange)="select.value = onPageSizeChanged($event)">
TypeScript:
onPageSizeChanged(event) {
const response = window.confirm("Are you sure you want change the page size? Your edits will be lost?");
console.log(this.pagination.pageSize)
if (response) {
this.pageSize = event;
this.pagination.pageSize = event;
}
else{
this.pageSize = this.pagination.pageSize;
}
return this.pagination.pageSize;
}
demo
https://plnkr.co/edit/RR8XgZW2KIcYTnxo7Iju?p=preview
You could do something like this in your component.html file...
Add a template reference variable #pageSize on your select element
and on (change), set the value of that variable (pageSize.value) equal to your onChangeSize method that we'll create next. Pass the pageSize.value to this onChangeSize method like this: (change) = "pageSize.value = onChangeSize(pageSize.value)
this gives us...
<select id="pageSize" #pageSize
(change)="pageSize.value = onChangeSize(pageSize.value)">
<option value="10">10</option>
<option value="20">20</option>
<option value="50">50</option>
</select>
and in your component.ts file, create a method which takes that value & if the user confirms the change, we simply return that value right back. If the user rejects the change, we return the default value instead.
export class MathComponent implements OnInit {
defaultInput: number = 10;
userInput: number = this.defaultInput;
constructor() { }
ngOnInit() {
}
onChangeSize(pageSize: HTMLSelectElement) {
const response = window.confirm("Are you sure you want change the page size? Your edits will be lost?");
if (response) {
return pageSize;
} else {
return this.defaultInput;
}
}
}
https://plnkr.co/edit/RR8XgZW2KIcYTnxo7Iju?p=preview
For Select controls whose (ngModelChange)
method includes asynchronous code (async/await, Promise, rxjs Observable), pre Angular 6 code may use the following solution.
<select
id="{{ user.emailAddress }}"
class="form-control role-select"
aria-label="Dropdown"
[disabled]="busy"
[(ngModel)]="user.role"
(ngModelChange)="editUserRole(user)"
>
<option *ngFor="let role of (roles | async)" [value]="role">
{{ role }}
</option>
</select>
In the contorller
public async editUserRole(user: IUser) {
if (user.role === SubscriptionUserRole.DATA_DEFAULT && !this._hasAtLeastOneOtherAdmin(user)) {
// Execute on the next app.tick cycle. Pre V6, the HTML Element value is not updated until after ngModelChange.
// This may not be needed in Angular V6.
// zone.js and ngZone intercept async operations to trigger UI updates. Hence, no need to call app.tick.
setTimeout(() => {
user.role = SubscriptionUserRole.DATA_ADMIN;
}, 0);
this.errorMessage = 'At least one user should be DataAdmin';
return;
}
// Continue change operation like database update here.
}
I suppose that in some scenarios the delayed updated could pose a problem.
This delay may not be necessary in Angular 6+ due to the change where the FormControl is updated prior to the ngModelChangeCall.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With