Skip to content

Commit

Permalink
Merge pull request #83 from agalbulev/feature/multiple-components-lazy
Browse files Browse the repository at this point in the history
Register multiple component in JssModule.forChild method
  • Loading branch information
kamsar authored Dec 12, 2018
2 parents 213bf2c + bed7103 commit 0a1b2fd
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 9 deletions.
52 changes: 52 additions & 0 deletions docs/data/routes/docs/client-frameworks/angular/angular-tips/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,58 @@ If you're using the default code-generated `app-components.module.ts` that's all
export class AppComponentsModule { }
```

You can also load multiple components from one module. This will improve code splitting of your application and will reduce the calls which need to be made for loading application resources by bundling components into loadable groups.

> NOTE: multiple component loading is not compatible with the default code generation. You'll need to turn off code generation and maintain `app-components.module.ts` manually to use this technique.
For lazy-loading with multiple components you need to register two or more components with `JssModule.forChild()` method into lazy-loading module. You need to provide component name and component type.

```js
import { NgModule } from '@angular/core';
import { JssModule } from '@sitecore-jss/sitecore-jss-angular';
import { FirstComponent } from './first.component';
import { SecondComponent } from './second.component';

@NgModule({
imports: [
// secret sauce
JssModule.forChild([
{ name: 'FirstComponent', type: FirstComponent },
{ name: 'SecondComponent', type: SecondComponent }
])
],
declarations: [
FirstComponent,
SecondComponent,
],
})
export class MyModule { }
```

There aren't changes in your component module. If you use multiple components lazy-loading, you need to have same value for `loadChildren` if the components are from same module and also the path value need to be same with component name from lazy-loading module initialization.

```js
@NgModule({
imports: [
AppComponentsSharedModule,
JssModule.withComponents([
// non-lazy components
], [
{ path: 'FirstComponent', loadChildren: './my/my.module#MyModule'},
{ path: 'SecondComponent', loadChildren: './my/my.module#MyModule'},
]),
],
exports: [
JssModule,
AppComponentsSharedModule,
],
declarations: [
// non-lazy components
],
})
export class AppComponentsModule { }
```

## Ensure components are `display: block`

When writing UI components in Angular, the default style for `display` for all new components is `inline`. For components to work as expected in the Experience Editor, set the display style to `display: block;` for all components root elements. I.e:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ export function instanceOfComponentNameAndModule(object: any): object is Compone
export const PLACEHOLDER_COMPONENTS = new InjectionToken<ComponentNameAndType[]>('Sc.placeholder.components');
export const PLACEHOLDER_LAZY_COMPONENTS = new InjectionToken<ComponentNameAndType[]>('Sc.placeholder.lazyComponents');
export const PLACEHOLDER_MISSING_COMPONENT_COMPONENT = new InjectionToken<Type<any>>('Sc.placeholder.missingComponentComponent');
export const DYNAMIC_COMPONENT = new InjectionToken<Type<any>>('Sc.placeholder.dynamicComponent');
export const DYNAMIC_COMPONENT = new InjectionToken<Type<any> | {[s: string]: any}> ('Sc.placeholder.dynamicComponent');
18 changes: 16 additions & 2 deletions packages/sitecore-jss-angular/src/jss-component-factory.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class JssComponentFactoryService {
if (lazyComponent) {
return this.loader.load(lazyComponent.loadChildren)
.then((ngModuleFactory) => {
let componentType = null;
const moduleRef = ngModuleFactory.create(this.injector);
const dynamicComponentType = moduleRef.injector.get(DYNAMIC_COMPONENT);
if (!dynamicComponentType) {
Expand All @@ -68,10 +69,23 @@ export class JssComponentFactoryService {
);
}

if (component.componentName in dynamicComponentType) {
componentType = (dynamicComponentType as {[s: string]: any})[component.componentName];
} else {
if (typeof dynamicComponentType === 'function') {
componentType = dynamicComponentType;
} else {
throw new Error(
// tslint:disable-next-line:max-line-length
`JssComponentFactoryService: Lazy load module for component "${lazyComponent.path}" missing DYNAMIC_COMPONENT provider. Missing JssModule.forChild()?`
);
}
}

return {
componentDefinition: component,
componentImplementation: dynamicComponentType,
componentFactory: moduleRef.componentFactoryResolver.resolveComponentFactory(dynamicComponentType),
componentImplementation: componentType,
componentFactory: moduleRef.componentFactoryResolver.resolveComponentFactory(componentType),
};
});
}
Expand Down
27 changes: 21 additions & 6 deletions packages/sitecore-jss-angular/src/lib.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ModuleWithProviders,
NgModule,
Type,
Provider
} from '@angular/core';
import { ROUTES } from '@angular/router';
import { DateDirective } from './components/date.directive';
Expand Down Expand Up @@ -81,14 +82,28 @@ export class JssModule {
}

/** Instantiates a module for a lazy-loaded JSS component */
static forChild(component: Type<any>): ModuleWithProviders {
static forChild(components: Type<any> | ComponentNameAndType[]): ModuleWithProviders {
const providers: Provider[] = [
{ provide: ROUTES, useValue: [], multi: true },
];

if (Array.isArray(components)) {
const dynamicComponent: {[s: string]: any} = {};

components.forEach((component) => {
dynamicComponent[component.name] = component.type;
providers.push({ provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: component.type, multi: true });
});

providers.push({ provide: DYNAMIC_COMPONENT, useValue: dynamicComponent });
} else {
providers.push({ provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: components, multi: true });
providers.push({ provide: DYNAMIC_COMPONENT, useValue: components });
}

return {
ngModule: JssModule,
providers: [
{ provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: component, multi: true },
{ provide: ROUTES, useValue: [], multi: true },
{ provide: DYNAMIC_COMPONENT, useValue: component },
],
providers,
};
}

Expand Down

0 comments on commit 0a1b2fd

Please sign in to comment.