Create Observable by using non-observable Input() property
Jul 21, 2017 · 1 min read
Example:
Case: we have a component, list of items:
@Component({
selector: 'todo-list',
template: `<todo-item
*ngFor="let item of items$ | async"
[todo]="item"></todo-item>`
})
export class TodoListComponent implements OnInit {
public items$: Observable<Todo[]>;
constructor(private todoService: TodoService) { }
ngOnInit() {
this.items$ = this.todoService.getTodoItems();
}}
When you use *ngFor for an Observable of array and then you need create an Observable using related data in @Input() property in child component, your components can look:
@Component({
selector: 'todo-item',
template: `
Category: {{categoryName$ | async}}: {{todoText$ | async}}`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TodoItemComponent implements OnInit {readonly todo$ = new ReplaySubject<Todo>(1);public todoCategoryName$: Observable<TodoCategory>;@Input() todo: Todo;constructor(private todoService: TodoService) { }ngOnChanges(changes: SimpleChanges) {
if(changes.todo) {
this.todoCategoryName$ = this.todo$
.switchMap(todo => { return this.todoService.getCategory(todo.categoryId) })
.pluck('name');
}
}}
The problem in this solution that we always recreate Observable whenever @Input() todo changes. We can use @Input() todo as setter to ReplaySubject property and can create Observables in ngOnInit by one:
@Component({
selector: 'todo-item',
template: `Category: {{categoryName$ | async}}: {{todoText$ | async}}`,
})
export class TodoItemComponent implements OnInit { readonly todo$ = new ReplaySubject<Todo>(1); public todoCategoryName$: Observable<TodoCategory>; @Input() set todo(value: Todo) {
this.todo$.next(value);
} constructor(private todoService: TodoService) { } ngOnInit() { this.todoCategoryName$ = this.todo$
.switchMap(todo => {
this.todoService.getCategory(todo.categoryId)
})
.pluck('name');
}}
ReplaySubject ensure that we receive last passed value(doesn’t matter when we subscribe to Observable) and don’t receive initial value as BehaviorSubject.
Full example you can find here:
https://gist.github.com/amikitevich/9bd22d3a0bf88f1d9833e1611752ce86
