Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular: set selected value for <select>

I have data set for my <select> loaded asynchronously. I use hot observable, as the data can change in time. The problem is I am unable to set selected value and also Angular does not point to first element by itself (there is no value set until user does it). I'm trying to subscribe to my own observable 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();
    }
  }
}
like image 751
Daniel Kucal Avatar asked Jan 30 '23 00:01

Daniel Kucal


1 Answers

You subscribe to your observable twice. Async pipe does it internally after your subscription.

When subscribe method is being executed it executes subscribe function

observer => this.observer = observer

and overrides this.observer property so it will have effect only for async pipe(last subscriber)

I would use share operator to solve it

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

Plunker Example

To see why this.observer is overrided 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 mentioned early async pipe subscribes to observable internally

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

like image 177
yurzui Avatar answered Feb 02 '23 16:02

yurzui