Create Observable by using non-observable Input() property

Alexey Mikitevich
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

)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade