Angular2 Dropdown revert to previously selected option
Asked Answered
L

3

5

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; }  
} 
Leitmotiv answered 22/9, 2017 at 6:11 Comment(3)
make use of ngModel and on else set the ngModel that will reflect the selected valueBroussard
No luck. Tried the following <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; } }Leitmotiv
can you update the code with the changeBroussard
D
2

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

Dena answered 22/9, 2017 at 7:19 Comment(1)
One limitation appears to be that if you have an async (promise, rxjs) method call, you are unable to handle the return value using .then or .subscribe in the expression, or using async pipe. Using async pipe on the method you get the error "Cannot have a pipe in an action expression". Using .then or .subscribe results in expression parse errors). Perhaps this works in 6+ due to ngModelChange being called after the formControl is updated.Hoffman
B
2

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

Bosson answered 22/9, 2017 at 9:54 Comment(0)
H
1

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.

Hoffman answered 24/2, 2019 at 17:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.