Skip to content

Commit e4a87eb

Browse files
committed
feat: added global loading template token
1 parent 4359475 commit e4a87eb

File tree

8 files changed

+118
-19
lines changed

8 files changed

+118
-19
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Component, Input, ChangeDetectorRef } from '@angular/core';
2+
3+
@Component({
4+
template: `
5+
<div class="transloco-loader-template" [innerHTML]="html"></div>
6+
`
7+
})
8+
export class LoaderComponent {
9+
private _html: string;
10+
11+
@Input() set html(html: string) {
12+
this._html = html;
13+
this.cdr.markForCheck();
14+
}
15+
16+
get html() {
17+
return this._html;
18+
}
19+
20+
constructor(private cdr: ChangeDetectorRef) {}
21+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {
2+
ComponentRef,
3+
TemplateRef,
4+
ViewContainerRef,
5+
ComponentFactoryResolver,
6+
Component,
7+
Injector
8+
} from '@angular/core';
9+
import { LoaderComponent } from './loaderComponent.component';
10+
11+
export class TemplateHandler {
12+
constructor(
13+
private template: string | TemplateRef<any> | Component,
14+
private vcr: ViewContainerRef,
15+
private injector: Injector
16+
) {}
17+
18+
public attachView() {
19+
if (this.isTemplateRef(this.template)) {
20+
this.vcr.createEmbeddedView(this.template as TemplateRef<any>);
21+
} else if (this.isComponent(this.template)) {
22+
this.createComponent(this.template);
23+
} else if (this.isHTML(this.template)) {
24+
const loaderCmp = this.createComponent<LoaderComponent>(LoaderComponent);
25+
loaderCmp.instance.html = this.template as string;
26+
}
27+
}
28+
29+
public detachView() {
30+
this.vcr.clear();
31+
}
32+
33+
private createComponent<T>(cmp): ComponentRef<T> {
34+
const cfr = this.injector.get(ComponentFactoryResolver);
35+
const component = cfr.resolveComponentFactory(cmp);
36+
37+
return this.vcr.createComponent(component);
38+
}
39+
40+
private isTemplateRef(template: string | TemplateRef<any> | Component) {
41+
return template instanceof TemplateRef;
42+
}
43+
44+
private isHTML(template: string | TemplateRef<any> | Component) {
45+
return typeof template === 'string';
46+
}
47+
48+
private isComponent(template: string | TemplateRef<any> | Component) {
49+
return typeof template === 'function';
50+
}
51+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { InjectionToken, ComponentRef } from '@angular/core';
2+
3+
export const TRANSLOCO_LOADING_TEMPLATE = new InjectionToken<{ component: ComponentRef<any> | string }>(
4+
'TRANSLOCO_LOADING_TEMPLATE'
5+
);

projects/transloco/src/lib/transloco.directive.ts

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,14 @@ import {
1010
OnInit,
1111
Optional,
1212
TemplateRef,
13-
ViewContainerRef
13+
ViewContainerRef,
14+
ComponentRef,
15+
ComponentFactoryResolver,
16+
Component,
17+
Injector
1418
} from '@angular/core';
19+
import { TemplateHandler } from './templateHandler';
20+
import { TRANSLOCO_LOADING_TEMPLATE } from './transloco-loading-template';
1521
import { switchMap, take } from 'rxjs/operators';
1622
import { Subscription } from 'rxjs';
1723
import { TranslocoService } from './transloco.service';
@@ -33,22 +39,28 @@ export class TranslocoDirective implements OnInit, OnDestroy, OnChanges {
3339
@Input('translocoLoadingTpl') loadingTpl: TemplateRef<any> | undefined;
3440

3541
private langName: string;
42+
private loaderTplHandler: TemplateHandler = null;
3643
// Whether we already rendered the view once
3744
private initialzed = false;
3845

3946
constructor(
4047
private translocoService: TranslocoService,
48+
private injector: Injector,
4149
@Optional() private tpl: TemplateRef<any>,
4250
@Optional() @Inject(TRANSLOCO_SCOPE) private providerScope: string | null,
4351
@Optional() @Inject(TRANSLOCO_LANG) private providerLang: string | null,
52+
@Optional() @Inject(TRANSLOCO_LOADING_TEMPLATE) private defaultLoading: Component | string,
4453
private vcr: ViewContainerRef,
4554
private cdr: ChangeDetectorRef,
4655
private host: ElementRef
47-
) {
48-
}
56+
) {}
4957

5058
ngOnInit() {
51-
this.hasLoadingTpl() && this.vcr.createEmbeddedView(this.loadingTpl);
59+
const tpl = this.getLoadingTpl();
60+
if (tpl) {
61+
this.loaderTplHandler = new TemplateHandler(tpl, this.vcr, this.injector);
62+
this.loaderTplHandler.attachView();
63+
}
5264

5365
const { runtime } = this.translocoService.config;
5466

@@ -58,13 +70,13 @@ export class TranslocoDirective implements OnInit, OnDestroy, OnChanges {
5870
const lang = this.getLang(globalLang);
5971
const scope = this.getScope();
6072
this.langName = scope ? `${lang}-${scope}` : lang;
61-
return this.translocoService._load(this.langName)
73+
return this.translocoService._load(this.langName);
6274
}),
6375
runtime ? source => source : take(1)
6476
)
6577
.subscribe(() => {
6678
const translation = this.translocoService.getTranslation(this.langName);
67-
this.tpl === null ? this.simpleStrategy() : this.structuralStrategy(translation);
79+
this.loadingTpl === null ? this.simpleStrategy() : this.structuralStrategy(translation);
6880
this.cdr.markForCheck();
6981
this.initialzed = true;
7082
});
@@ -82,16 +94,20 @@ export class TranslocoDirective implements OnInit, OnDestroy, OnChanges {
8294
}
8395

8496
private structuralStrategy(data) {
85-
if( this.view ) {
97+
if (this.view) {
8698
this.view.context['$implicit'] = data;
8799
} else {
88-
this.hasLoadingTpl() && this.vcr.clear();
100+
this.loaderTplHandler.detachView();
89101
this.view = this.vcr.createEmbeddedView(this.tpl, {
90102
$implicit: data
91103
});
92104
}
93105
}
94106

107+
private getLoadingTpl(): string | TemplateRef<any> | Component {
108+
return this.loadingTpl || this.defaultLoading;
109+
}
110+
95111
private hasLoadingTpl() {
96112
return this.loadingTpl instanceof TemplateRef;
97113
}
@@ -107,16 +123,16 @@ export class TranslocoDirective implements OnInit, OnDestroy, OnChanges {
107123
* When the user changes the lang we need to update
108124
* the view. Otherwise, the lang will remain the inline/provided lang
109125
*/
110-
if( this.initialzed ) {
126+
if (this.initialzed) {
111127
return globalLang;
112128
}
113129

114-
if( this.inlineLang ) {
115-
return this.inlineLang
130+
if (this.inlineLang) {
131+
return this.inlineLang;
116132
}
117133

118-
if( this.providerLang ) {
119-
return this.providerLang
134+
if (this.providerLang) {
135+
return this.providerLang;
120136
}
121137

122138
return globalLang;

projects/transloco/src/lib/transloco.module.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { NgModule } from '@angular/core';
2+
import { LoaderComponent } from './loaderComponent.component';
23
import { TranslocoDirective } from './transloco.directive';
34
import { TRANSLOCO_PARSER, DefaultParser } from './transloco.parser';
45
import { TranslocoParamsPipe } from './transloco-params.pipe';
56
import { TranslocoPipe } from './transloco.pipe';
67
import { DefaultHandler, TRANSLOCO_MISSING_HANDLER } from './transloco-missing-handler';
78

89
@NgModule({
9-
declarations: [TranslocoDirective, TranslocoParamsPipe, TranslocoPipe],
10+
declarations: [TranslocoDirective, TranslocoParamsPipe, TranslocoPipe, LoaderComponent],
1011
providers: [
1112
{
1213
provide: TRANSLOCO_PARSER,
@@ -17,6 +18,7 @@ import { DefaultHandler, TRANSLOCO_MISSING_HANDLER } from './transloco-missing-h
1718
useClass: DefaultHandler
1819
}
1920
],
20-
exports: [TranslocoDirective, TranslocoParamsPipe, TranslocoPipe]
21+
exports: [TranslocoDirective, TranslocoParamsPipe, TranslocoPipe],
22+
entryComponents: [LoaderComponent]
2123
})
2224
export class TranslocoModule {}

projects/transloco/src/public-api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ export * from './lib/types';
99
export * from './lib/helpers';
1010
export * from './lib/transloco-params.pipe';
1111
export * from './lib/transloco-scope';
12+
export * from './lib/transloco-loading-template';
1213
export * from './lib/transloco-lang';

src/app/lazy/lazy.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<ng-container *transloco="let t; loadingTpl: loading">
1+
<ng-container *transloco="let t">
22
<h1 data-cy="regular">{{ t.title }}</h1>
33
</ng-container>
44

src/app/lazy/lazy.module.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { NgModule } from '@angular/core';
1+
import { NgModule, Component } from '@angular/core';
22
import { CommonModule } from '@angular/common';
33
import { LazyComponent } from './lazy.component';
44
import { RouterModule, Routes } from '@angular/router';
5-
import { TRANSLOCO_SCOPE, TranslocoModule } from '@ngneat/transloco';
5+
import { TRANSLOCO_SCOPE, TranslocoModule, TRANSLOCO_LOADING_TEMPLATE } from '@ngneat/transloco';
66

77
const routes: Routes = [
88
{
@@ -13,7 +13,10 @@ const routes: Routes = [
1313

1414
@NgModule({
1515
declarations: [LazyComponent],
16-
providers: [{ provide: TRANSLOCO_SCOPE, useValue: 'admin-page' }],
16+
providers: [
17+
{ provide: TRANSLOCO_SCOPE, useValue: 'admin-page' },
18+
{ provide: TRANSLOCO_LOADING_TEMPLATE, useValue: 'loading template...' }
19+
],
1720
imports: [CommonModule, RouterModule.forChild(routes), TranslocoModule]
1821
})
1922
export class LazyModule {}

0 commit comments

Comments
 (0)