How to increase Angular UI with Rxjs ?

Overview

Hi , I want to share my experience in the Rxjs and angular to show how to use better in the special condition for example : when user has slow network and meanwhile before reach response , user gives up and want to select another item

What’s Observable and Rxjs ?

There are many story in the medium to explained Observable and kind of operators and etc to learn and use ,But in this section I want to have a glance to observable and switchMap quickly.

If you have not idea that what’s observable ,it’s good to read this perfect story for reach better vision about observable

https://medium.com/angular-in-depth/learn-to-combine-rxjs-sequences-with-super-intuitive-interactive-diagrams-20fce8e6511

After creating new angular project ,create a component as product to generate their product items

we have not api for http call because of that we use mock data

For start we run this commands to create component and service

ng g c product /// for generate component 
ng g s product /// for generate service

After this we implement sample component to show item of foods in the Dom and because we have not api call , I used a sample data in the service that exported as observable for using in the component like following code

/**
* product service
* for selected item and return sample data
*/
@Injectable({
providedIn: 'root'
})
export class ProductService {

/**
* @ignore
*/
constructor() {
}

/**
*
* @param food:get Food data and return with 2000 delay to simulate request
*/
selectedFood(food: FoodItem): Observable<any> {
return of({
...food
}).pipe(delay(2000));
}

/**
* getItemProduct method to return sample repsonse
*/
getItemProduct(): Observable<FoodItem[]> {
return of([
{
id: 0,
name: 'Taco Pizza',
image: 0,
ingredient: 'A Quad Cities original : taco-seasoned crumbled sausage, red sauce, mozzarella, and cheddar. Topped with lettuce, tomatoes, and taco-seasoned chips.',
price: '1000',
},
{
id: 1,
name: 'Sausage Pizza',
image: 1,
ingredient: 'The Quad Cities specialty : crumbled sausage, Roots pizza sauce, and mozzarella.',
price: '2000',
},
{
id: 2,
name: 'Rick Ortiz’s Antique Taco Chili Cheese Curd Pizza',
image: 2,
ingredient: 'Chorizo chili, cheddar curds, Chihuahua cheese, mozzarella, pickled jalapeños & onions, avocado cream, tortilla strips, black olives, and scallions.',
price: '2000',
}
]);
}
}

With Of from rxjs operator we can return an observable,In the response data I set image as number because I use images in the assets folder with this id,

In the ts file we have following code

/**
* product component class
* to handler click and call service
*/
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.scss']
})
export class ProductComponent implements OnInit, OnDestroy {
/**
* a subject for start new observable
*/
foodObservable: Subject<any> = new Subject<any>();
/**
* status of food
*/
statusFood = FoodStatus;
/**
* item list
*/
itemList: FoodItem[];

/**
*
* @param productService:For use product service
*/
constructor(private productService: ProductService) {
}

/**
* In the first rendering we create an observable to start
*/
ngOnInit(): void {
this.getProductItem();
this.foodObservable.pipe(
tap((food: FoodItem) => {
this.itemList.forEach((item: FoodItem) => {
if (item.id === food.id) {
item.status = FoodStatus.Loading;
} else {
item.status = null;
}
});
}),
switchMap((food: FoodItem) => {
return this.productService.selectedFood(food);
}),
tap(() => {
this.itemList.forEach((item: FoodItem) => {
item.status = null;
});
})
).subscribe((result: FoodItem) => {
this.itemList.forEach((item: FoodItem) => {
if (item.id === result.id) {
item.status = FoodStatus.Successful;
} else {
item.status = null;
}
});
});
}

/**
* get product item from service
*/
getProductItem(): void {
this.productService.getItemProduct().subscribe((data: FoodItem[]) => {
this.itemList = data;
});
}

/**
* get food item from template and call next foodObservable
* @param item:food item
*/
handlerClick(item: FoodItem): void {
item.selected = true;
this.itemList.forEach((foodItem) => {
if (foodItem !== item) {
foodItem.selected = false;
}
});
this.foodObservable.next(item);
}

/**
*
* @param index:index
* @param food:food item
*/
trackByFoodId(index: number, food: FoodItem): number {
return food.id;
}

/**
* for unsubscribe the observable to clean it after done.
*/
ngOnDestroy(): void {
this.foodObservable.next();
this.foodObservable.complete();
}
}

The important part of this , is switch map ,The UI result is :

But Go Back to our code let’s do it :

At the first we create a Subject but what’s That ?

In the short vision I can say :Subject is another Observable type but has different action ,with Subject we can trigger event outside of constructor ,

what does it mean? it means when we create a observable we should subscribe it to use this stream but in the subject we can use by calling .next()

and for destroy this for avoid memory leak, we should call next and complete

in the ngOnDestroy

ngOnDestroy is like reture function in the useEffect react to avoid memory leak

What about trackBy?

In the react we used id of item or the i created by foreach, in the map and foreach to set to the JSX because it helps to rendering and change detection TrackBy it’s like that

But what was Problem in UI ?

when user want to select an item in the normally situation We do not notice anything but when user network is going to be slow (like slow 3G in the devtool ) and in this specific time user want to select another item or change his/her choice ,but we did not receive response from server and loading and request go to freezing .Opps what happened !

By switch map we can cancelled previous request and try new one , Just Like that, easy :)

In this following GIf we see loading label gone for previous item when we are in the loading status , In the real http call, we can see result better

Thanks for reading this story , Good Luck :)

Front-end Developer , mountain and astronomy lover

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store