im learning angular 18 SSR. I have a render problem when i load data from a graphql service; the load elements (skeletons) are showed using the value loading from a signal converted from a service observable method; the problem is when i render, it shows skeletons and items at same time (when the load data ends, only shows items):
I dont understand why occurs that.
product.service.ts
@Injectable({
providedIn: 'root'
})
export class ProductsService {
private apollo = inject(Apollo);
getProductsPaginated(quantity:number, page:number): Observable<ProductResponse>{
return this.apollo.watchQuery({
query: GET_PRODUCTS,
variables: { quantity, page }
}).valueChanges.pipe(
map(({ data, error }: any) => ({
loading: false,
products: data.productsPaginated.nodes,
error: error
}))
);
}
}
shop.component.ts:
@Component({
selector: 'app-shop',
standalone: true,
imports: [SidebarMenuComponent, ProductCardComponent, ProductCardSkeletonComponent],
templateUrl: './shop.component.html',
styleUrl: './shop.component.css'
})
export default class ShopComponent{
public skeletonProductsLenght = [1, 2, 3, 4, 5, 6];
public productsService = inject(ProductsService);
public productsPaginatedResp =
toSignal(this.productsService.getProductsPaginated(12,1),
{ initialValue: { loading: true, products: [], error: false } });
}
shop.component.html:
<div class="grid md:grid-cols-3 grid-cols-2 gap-6 p-4">
@if(this.productsPaginatedResp()?.loading){
@for(item of skeletonProductsLenght; track item){
<app-product-card-skeleton/>
}
}
@else {
@for (item of this.productsPaginatedResp()?.products; track item.key) {
<app-product-card [product]="item"/>
}
}
</div>
I think it might be due to SSR, you can make the code execute only on the browser using defer
. So that only once the HTML renders and either it will be skeleton or products.
@defer {
<div class="grid md:grid-cols-3 grid-cols-2 gap-6 p-4">
@if(this.productsPaginatedResp()?.loading){
@for(item of skeletonProductsLenght; track item){
<app-product-card-skeleton/>
}
}
@else {
@for (item of this.productsPaginatedResp()?.products; track item.key) {
<app-product-card [product]="item"/>
}
}
</div>
}