15

I'm writing an angular2 application and I'm stuck with something. First of all, I have a select which is bind to a formControl :

export class MyComponent implements OnInit {

  profilesBy: Observable<any[]>;
  myControl = new FormControl();

  constructor(public http: Http) {
    this.profilesBy = this.myControl.valueChanges
      .map(text => new formatQuery(text.value))
      .switchMap(body => this.getGroupBy(body, this.url), (_, res)=> res.json().aggregations.group_by_type.buckets);
  }
}  

so, myControl is the formControl, and profilesBy is an Observable of an array.
The formatQuery just format a body for the query using the value of the select and getGroupBy return an http request (ie : http.post(url, body) ... ).
Then I assign the response : res.json().aggregations.group_by_type.buckets
But don't give too much thought about this.

Here is my template :

<md-card>
    <h4>Profiles group by :
        <select [formControl]="myControl">
            Some options ...
        </select>
    </h4>

    <div *ngFor="let profile of profilesBy | async">
        <strong>{{profile.key}} :</strong> {{profile.doc_count | number:'1.0-2'}}
    </div>
</md-card>

And it works just fine when the user selects a value, it triggers the valueChanges and chains the actions!

So I'm happy with it. I think this is an elegant way to do so, instead of using ngOnChanges()

Now here is where I can't find a way to make it works. Basically, I want to initialize the select with a value and trigger (without any user action) the valueChange

I tried to used [(ngModel)] : <select [formControl]="myControl" [(ngModel)]="selectedGroupBy"> but it didn't trigger the it.

Last, I tried to make the call myself in the method ngOnInit()

this.getGroupBy(new formatQuery(this.selectedGroupBy.value), this.url)
       .subscribe((response) => {
         this.profilesBy = response.json().aggregations.group_by_type.buckets;
       });

But I got a Array instead of an Observable of Array! What do I miss? How can I make it work?


Possible solution using startWith

this.profilesBy = this.myControl.valueChanges
      .startWith(DEFAULT)
      .map(text => new formatQuery(text.value))
      .switchMap(body => this.getGroupBy(body, this.url), (_, res)=> res.json().aggregations.group_by_type.buckets);
BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
ByJC
  • 213
  • 1
  • 3
  • 9

2 Answers2

15

The possible solution is to use startWith operator:

this.profilesBy = this.myControl.valueChanges
  .startWith(DEFAULT_OPTION)
  .map(text => new formatQuery(text.value))
  .switchMap(body => ...);
Sergey Sokolov
  • 2,709
  • 20
  • 31
  • 4
    But startWith is added in every new Observable from triggered from valueChanges, how to do only once? – I.Boras Nov 12 '21 at 16:36
6

To change the value of a formControl programatically, you just have to call the setValue() method:

setValue(value: any, {onlySelf, emitEvent, emitModelToViewChange, emitViewToModelChange}?: {
    onlySelf?: boolean,
    emitEvent?: boolean,
    emitModelToViewChange?: boolean,
    emitViewToModelChange?: boolean
  }) : void

Set the value of the form control to value.

so for your case : this.myControl.setValue(foo) should trigger the valueChanges.

n00dl3
  • 21,213
  • 7
  • 66
  • 76
  • Hi @n00dl3, Thank you for your answer. I can't make it work though. constructor(public http: Http) { this.profilesBy = this.myControl.valueChanges //.startWith(this.groupBy[0]) .map(text => new formatQuery(text.value)) .switchMap(body => this.getGroupBy(body, this.url), (_, res)=> res.json().aggregations.group_by_type.buckets); } ngOnInit() { this.myControl.setValue(this.groupBy[0]); } – ByJC Dec 15 '16 at 16:18
  • Well I can't edit my previous comment ... Do you know why it did not work ? – ByJC Dec 15 '16 at 16:20
  • 2
    This should be the answer – avoliva Jan 13 '17 at 02:00