Angular: set selected value for <select>

I have a dataset for mine <select>

loaded asynchronously. I use hot observables as the data can change over time. The problem is that I cannot set the selected value, and also Angular does not point to the first element by itself (there is no value set until the user does this). I'm trying to subscribe to my own observables and ... it doesn't work, I wonder why? How can I solve this problem?

PLNKR: https://plnkr.co/edit/uDmTSHq4naYGUjjhEe5Q

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
    </div>
    <select [(ngModel)]="selectedValue">
      <option *ngFor="let value of (values$ | async)"
              [value]="value">{{ value }}
      </option>
    </select>
  `,
})
export class App implements OnInit, OnDestroy {
  public name: string;
  public selectedValue: string = '';
  public values$: Observable<Array<string>> = new Observable(observer => this.observer = observer);
  protected observer: Subscriber<Array<string>>;
  protected subscription: Subscription;

  constructor() {
    this.name = `Angular! v${VERSION.full}`
  }

  ngOnInit() {
    this.subscription = this.values$.subscribe((values) => {
      console.log('never fired...');
      this.selectedValue = values[0];
    });

    setTimeout(() => {
      this.observer.next(['some', 'test', 'data']);
    });
  }

  ngOnDestroy() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
}

      

+3


source to share


3 answers


You subscribe to your watched twice. The Async channel does this inside your subscription.

When the subscribe

method is executed , it executes the subscribe

function

observer => this.observer = observer

      

and overrides the property this.observer

so it will only act for the async pipe (last caller)

I would use an operator share

to solve it

new Observable(observer => this.observer = observer).share();

      



Plunger example

To see why is being this.observer

overridden, just run this code

let myObserver;   

const observable$ = new Rx.Observable(function subscribe(observer) {
  console.log('subscribe function has been called');
  myObserver = observer;
}); 

observable$.subscribe(function next1() { console.log('next1'); });
observable$.subscribe(function next2() { console.log('next2'); });
observable$.subscribe(function next3() { console.log('next3'); });

myObserver.next();

      

jsbin.com

As I said, early async pipe subscribes internally observable

https://github.com/angular/angular/blob/4.3.x/packages/common/src/pipes/async_pipe.ts#L23

+5


source


You must use

[ngValue]="value" 

      

instead of [value]

Assigned value



public selectedValue: string = 'test';

      

HTML should be changed as

<select [(ngModel)]="selectedValue">
  <option *ngFor="let value of values$ | async"
          [ngValue]="value">{{ value }}
  </option>
</select>

      

Updated Plunker

+1


source


You have to bind it to ngValue:

  <div>
      <h2>Hello {{name}}</h2>
    </div>
    <select [(ngModel)]="selectedValue">
      <option *ngFor="let value of (values$ | async)"
              [ngValue]="selectedValue">{{ value }}
      </option>
    </select>

      

+1


source







All Articles