Tobias
Tobias

Reputation: 349

Data binding inside rxjs observable

Is it possible to bind to data inside an observable and maintain the data in both directions?

For example: I have some kind of dialog where the user can enter some kind of data. And the layout of the dialog gets loaded from a configuration and is inside an observable. The configuration contains which input fields will be shown.
So i tried to use the async pipe inside my dialog template. Rendering the fields works like a charm but i tried to databind to values inside the observable aswell. Each time a close and open the dialog now i get a new observable and loose my data.

To avoid loosing data i subscribe to the observable in my service and write it to a data object:

export class DataService implements OnInit {
  private data: any = {};
  ngOnInit() {
  this.http.get(path).subscribe((myData) => {
    this.data.data = myData;
  }
}

//other code ...

//opening the dialog this way
const dialogRef = this.dialog.open(MyDialogComponent, {
  width: '1200px',
  data: this.dataService.getData()
});

//Using data in the dialog template
<div *ngIf="data.data as myField; else loading">
  <mat-form-field>
    <input #inputText matInput 
      placeholder="{{ myField.name }}" 
      [(ngModel)]="myField.value" 
      name="{{ myField.name }}" 
      matTooltip="{{myField.description}}" 
      [required]="myField.required">
  </mat-form-field>
</div>
<ng-template #loading>
  <mat-spinner mode="indeterminate" diameter="30"></mat-spinner>
</ng-template>

I could also separate data from my model but that would make the processing a lot harder.

Are there any other options to handle requirement? What would be the best practice?

Upvotes: 1

Views: 473

Answers (2)

Fan Cheung
Fan Cheung

Reputation: 11345

Use shareReplay(1) is a cleaner solution and get its value using async pipe, it acts like BehaviourSubject.

export class DataService implements OnInit {
  private data: any = {};
  ngOnInit() {
  this.data.data=this.http.get(path).pipe(shareReplay(1))
}

//other code ...

//opening the dialog this way
const dialogRef = this.dialog.open(MyDialogComponent, {
  width: '1200px',
  data: this.dataService.getData()
});

<div *ngIf="(data.data | async) as myField; else loading">
  <mat-form-field>
    <input #inputText matInput 
      placeholder="{{ myField.name }}" 
      [(ngModel)]="myField.value" 
      name="{{ myField.name }}" 
      matTooltip="{{myField.description}}" 
      [required]="myField.required">
  </mat-form-field>
</div>
<ng-template #loading>
  <mat-spinner mode="indeterminate" diameter="30"></mat-spinner>
</ng-template>

Upvotes: 1

jazza1000
jazza1000

Reputation: 4247

Have you thought of re-broadcasting it in a ReplaySubject?

export class DataService implements OnInit {
private data = new ReplaySubject<any>;
ngOnInit() {
this.http.get(path).subscribe((myData) => {
     this.data.next(myData);
    }
}

public getMyData()    {
     return Observable.of(this.myData);
 }

Upvotes: 1

Related Questions