Skip to content

Commit d0f2278

Browse files
author
jgelin
committed
fix: image re-rendering for movie details
1 parent 366ad56 commit d0f2278

File tree

4 files changed

+75
-30
lines changed

4 files changed

+75
-30
lines changed

projects/movies/src/app/pages/movie-detail-page/movie-detail-page.component.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<article class="movie-detail-wrapper">
22
<ng-container *rxLet="movie$; let movie">
3-
<ui-detail-grid [style.opacity]="!!movie ? 1 : 0">
4-
<div detailGridMedia>
3+
<ui-detail-grid [style.opacity]="!!movie ? 1 : 0" [rerenderDetailGridMedia]="movie.imgSrc">
4+
<ng-template #detailGridMedia>
55
<img
66
class="aspectRatio-2-3 fit-cover"
77
[ngSrc]="movie.imgSrc"
@@ -14,8 +14,8 @@
1414
[title]="movie.title"
1515
data-uf="hero-img"
1616
/>
17-
</div>
18-
<div detailGridDescription>
17+
</ng-template>
18+
<ng-template #detailGridDescription>
1919
<header>
2020
<h1 data-uf="header-main">{{ movie.title }}</h1>
2121
<h2 data-uf="header-sub">{{ movie.tagline }}</h2>
@@ -166,7 +166,7 @@ <h3>The Cast</h3>
166166
>&nbsp;Back
167167
</button>
168168
</section>
169-
</div>
169+
</ng-template>
170170
</ui-detail-grid>
171171
<div class="loader" *ngIf="!movie"></div>
172172
</ng-container>

projects/movies/src/app/pages/movie-detail-page/movie-detail-page.component.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {select, selectSlice} from '@rx-angular/state/selections';
2-
import {Location, NgFor, NgIf, NgOptimizedImage} from '@angular/common';
1+
import { select, selectSlice } from '@rx-angular/state/selections';
2+
import { Location, NgFor, NgIf, NgOptimizedImage } from '@angular/common';
33
import {
44
ChangeDetectionStrategy,
55
Component,
@@ -9,21 +9,20 @@ import {
99
ViewChild,
1010
ViewEncapsulation,
1111
} from '@angular/core';
12-
import {filter, map, mergeWith, tap} from 'rxjs';
13-
import {TMDBMovieGenreModel} from '../../data-access/api/model/movie-genre.model';
14-
15-
import {MovieCast, MovieDetailAdapter} from './movie-detail-page.adapter';
16-
import {RxActionFactory} from '@rx-angular/state/actions';
17-
import {RxEffects} from '@rx-angular/state/effects';
18-
import {DetailGridComponent} from '../../ui/component/detail-grid/detail-grid.component';
19-
import {StarRatingComponent} from '../../ui/pattern/star-rating/star-rating.component';
20-
import {MovieListComponent} from '../../ui/pattern/movie-list/movie-list.component';
21-
import {RxLet} from '@rx-angular/template/let';
22-
import {BypassSrcDirective} from '../../shared/cdk/bypass-src.directive';
23-
import {RxFor} from '@rx-angular/template/for';
24-
import {FastSvgComponent} from '@push-based/ngx-fast-svg';
25-
import {RxIf} from '@rx-angular/template/if';
26-
import {RouterLink} from '@angular/router';
12+
import { filter, map, mergeWith, tap } from 'rxjs';
13+
import { TMDBMovieGenreModel } from '../../data-access/api/model/movie-genre.model';
14+
import { MovieCast, MovieDetailAdapter } from './movie-detail-page.adapter';
15+
import { RxActionFactory } from '@rx-angular/state/actions';
16+
import { RxEffects } from '@rx-angular/state/effects';
17+
import { DetailGridComponent } from '../../ui/component/detail-grid/detail-grid.component';
18+
import { StarRatingComponent } from '../../ui/pattern/star-rating/star-rating.component';
19+
import { MovieListComponent } from '../../ui/pattern/movie-list/movie-list.component';
20+
import { RxLet } from '@rx-angular/template/let';
21+
import { BypassSrcDirective } from '../../shared/cdk/bypass-src.directive';
22+
import { RxFor } from '@rx-angular/template/for';
23+
import { FastSvgComponent } from '@push-based/ngx-fast-svg';
24+
import { RxIf } from '@rx-angular/template/if';
25+
import { RouterLink } from '@angular/router';
2726

2827
@Component({
2928
standalone: true,
@@ -87,7 +86,10 @@ export default class MovieDetailPageComponent {
8786
}>
8887
) {
8988
this.effects.register(
90-
this.ui.dialog$.pipe(map((v) => v === 'show'), tap(console.log)),
89+
this.ui.dialog$.pipe(
90+
map((v) => v === 'show'),
91+
tap(console.log)
92+
),
9193
(openDialog) =>
9294
openDialog
9395
? this.trailerDialog?.nativeElement?.showModal()

projects/movies/src/app/pages/person-detail-page/person-detail-page.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<article *rxLet="personCtx$; let personCtx">
22
<ng-container *ngIf="personCtx?.value as person; else loading">
33
<ui-detail-grid>
4-
<div detailGridMedia>
4+
<ng-template #detailGridMedia>
55
<img
66
class="aspectRatio-2-3 fit-cover"
77
[ngSrc]="person.imgSrc"
@@ -14,8 +14,8 @@
1414
[title]="person?.name"
1515
data-uf="hero-img"
1616
/>
17-
</div>
18-
<div detailGridDescription>
17+
</ng-template>
18+
<ng-template #detailGridDescription>
1919
<header>
2020
<h1>{{ person.name }}</h1>
2121
<h2>{{ person.birthday }}</h2>
@@ -39,7 +39,7 @@ <h3>The Biography</h3>
3939
<fast-svg name="back" size="1em"></fast-svg>&nbsp; Back
4040
</button>
4141
</section>
42-
</div>
42+
</ng-template>
4343
</ui-detail-grid>
4444
</ng-container>
4545
<ng-template #loading>
Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,65 @@
11
import {
22
ChangeDetectionStrategy,
33
Component,
4+
ContentChild,
5+
Input,
6+
OnChanges,
7+
SimpleChanges,
8+
TemplateRef,
9+
ViewChild,
10+
ViewContainerRef,
411
ViewEncapsulation,
512
} from '@angular/core';
13+
import { NgTemplateOutlet } from '@angular/common';
614

715
@Component({
816
standalone: true,
917
selector: 'ui-detail-grid',
1018
template: `
1119
<div class="grid--item gradient">
12-
<ng-content select="[detailGridMedia]"></ng-content>
20+
<ng-container
21+
#detailGridMediaOutlet
22+
[ngTemplateOutlet]="detailGridMediaRef"
23+
></ng-container>
1324
</div>
1425
<div class="grid--item media">
15-
<ng-content select="[detailGridDescription]"></ng-content>
26+
<ng-container [ngTemplateOutlet]="detailGridDescription"></ng-container>
1627
</div>
1728
`,
1829
styleUrls: ['./detail-grid.component.scss'],
1930
changeDetection: ChangeDetectionStrategy.OnPush,
2031
encapsulation: ViewEncapsulation.Emulated,
32+
imports: [NgTemplateOutlet],
2133
})
22-
export class DetailGridComponent {}
34+
export class DetailGridComponent implements OnChanges {
35+
@ContentChild('detailGridMedia', { read: TemplateRef })
36+
detailGridMediaRef!: TemplateRef<unknown>;
37+
@ContentChild('detailGridDescription', { read: TemplateRef })
38+
detailGridDescription!: TemplateRef<unknown>;
39+
40+
/**
41+
* Each time a new value is set to the input rerenderDetailGridMedia (any type), rerender the block `detailGridMedia` (usually the img)
42+
* Hacky way to solve issue https://github.com/angular/angular/issues/47813
43+
*/
44+
@Input() rerenderDetailGridMedia: unknown;
45+
@ViewChild('detailGridMediaOutlet', { read: ViewContainerRef })
46+
outletRef!: ViewContainerRef;
47+
48+
ngOnChanges(changes: SimpleChanges): void {
49+
if (
50+
changes['rerenderDetailGridMedia'] &&
51+
!changes['rerenderDetailGridMedia'].isFirstChange()
52+
) {
53+
this.doRerenderDetailGridMedia();
54+
}
55+
}
56+
57+
private doRerenderDetailGridMedia(): void {
58+
if (!this.outletRef) {
59+
return;
60+
}
61+
62+
this.outletRef.clear();
63+
this.outletRef.createEmbeddedView(this.detailGridMediaRef);
64+
}
65+
}

0 commit comments

Comments
 (0)