Skip to content

Commit d14beb1

Browse files
committed
fix: Corrects Runtime compiler error
Replaces Angular compiler with Handlerbars. Angular currently prevents the use of its compiler in AOT mode. See angular issue #20156. Closes #11
1 parent ae7133f commit d14beb1

File tree

6 files changed

+64
-52
lines changed

6 files changed

+64
-52
lines changed

package-lock.json

Lines changed: 6 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.1.0-development",
44
"scripts": {
55
"ng": "ng",
6-
"start": "ng serve",
6+
"start": "ng serve --prod",
77
"build": "npm run build:lib && npm run build:demo",
88
"build:lib": "ng build ngx-json-schema-form",
99
"build:demo": "ng build demo --prod --base-href=https://jscharett.github.io/ngx-json-schema-form/",
@@ -45,6 +45,7 @@
4545
"ajv": "^6.10.0",
4646
"brace": "^0.11.0",
4747
"core-js": "^2.5.4",
48+
"handlebars": "^4.1.2",
4849
"json-schema-traverse": "^0.4.1",
4950
"lodash": "^4.17.14",
5051
"lodash-decorators": "^6.0.1",

projects/ngx-json-schema-form/ng-package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"ajv": "Ajv",
88
"json-schema-traverse": "traverse",
99
"lodash": "_",
10-
"lodash-decorators": "lodashDecorators"
10+
"lodash-decorators": "lodashDecorators",
11+
"handlebars/dist/cjs/handlebars": "Handlebars"
1112
}
1213
}
1314
}

projects/ngx-json-schema-form/src/docs/pages/introduction.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ There are numerous attributes that can be set on a widget which are set via the
184184

185185
### Button
186186

187-
There are 4 types of buttons that jsf supports, `button`, `image`, `reset` and `submit`. By default, these will all use the `<input>` tag for display. However, with the exception of `image`, you can specify custom html via the `content` option. This will result in the `<button>` being used for display and the content being inserted. Content can contain simple angular bindings so that you can bind to various properties of the layout. For example:
187+
There are 4 types of buttons that jsf supports, `button`, `image`, `reset` and `submit`. By default, these will all use the `<input>` tag for display. However, with the exception of `image`, you can specify custom html via the `content` option. This will result in the `<button>` being used for display and the content being inserted. Content can contain simple bindings so that you can bind to various properties of the layout. For example:
188188

189189
<div class="panel panel-primary docs">
190190
<div class="panel-heading panel-title">button-layout.json</div>
@@ -221,6 +221,10 @@ will result in
221221

222222
Here you can see we are specifying that the button should contain an image via the `content` options. The template binds to the properties of the `icon` option which results in an image tag being rendered. The `icon` option is also used when redering a simple button of type `image`.
223223

224+
<div class="alert alert-warning">
225+
Note: due to current limitation of Angular AOT compilation, use of the angular compile to transpile content strings into HTML DOM is not possible. Recent Angular changes have restricted the inclusion of the compiler in favor of reducing the file size and load time when in AOT mode. Therefore, Handlebars is currently being imported to handle the compilation of content string to HTML DOM.
226+
</div>
227+
224228
We can also respond to events such as a `click`. To do this, we must first bind an event handler to the jsf component
225229

226230

projects/ngx-json-schema-form/src/lib/json-schema-form.service.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('JsonSchemaFormService', () => {
3131
expect(widget.controlName).toBe('widget');
3232
});
3333

34-
it('should create a runtime component', () => {
34+
it('should convert template to DOM', () => {
3535
const service: JsonSchemaFormService = TestBed.get(JsonSchemaFormService);
3636
const fragment: DocumentFragment = service.compileTemplate('<span>{{ options.title }}</span>', {title: 'hi'});
3737
const div = document.createElement('div');
Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { CommonModule } from '@angular/common';
2-
import {
3-
Compiler, Component, ComponentRef, Injectable, Injector,
4-
ModuleWithComponentFactories, NgModule, NgModuleRef
5-
} from '@angular/core';
1+
// import { CommonModule } from '@angular/common';
2+
import { Injectable } from '@angular/core';
3+
// import {
4+
// Compiler, Component, ComponentRef, Injectable, Injector,
5+
// ModuleWithComponentFactories, NgModule, NgModuleRef
6+
// } from '@angular/core';
7+
8+
import Handlebars from 'handlebars/dist/cjs/handlebars';
69

710
import { Widget } from './widget-library';
811

@@ -13,32 +16,32 @@ export class JsonSchemaFormService {
1316
private x = false;
1417

1518
/** Creates a component with passed in template and associated context */
16-
private static createComponent(template: string, context: {[key: string]: any}): any {
17-
return Component({
18-
selector: `runtime-component-sample`,
19-
template
20-
})(class RuntimeComponent {
21-
options: any = context;
22-
});
23-
}
19+
// private static createComponent(template: string, context: {[key: string]: any}): any {
20+
// return Component({
21+
// selector: `runtime-component-sample`,
22+
// template
23+
// })(class RuntimeComponent {
24+
// options: any = context;
25+
// });
26+
// }
2427

2528
/** Create a module for use with the RuntimeComponent */
26-
private static createModule(component: any, compiler: Compiler): ModuleWithComponentFactories<any> {
27-
@NgModule({ imports: [CommonModule], declarations: [component] })
28-
class RuntimeComponentModule { }
29+
// private static createModule(component: any, compiler: Compiler): ModuleWithComponentFactories<any> {
30+
// @NgModule({ imports: [CommonModule], declarations: [component] })
31+
// class RuntimeComponentModule { }
2932

30-
return compiler.compileModuleAndAllComponentsSync(RuntimeComponentModule);
31-
}
33+
// return compiler.compileModuleAndAllComponentsSync(RuntimeComponentModule);
34+
// }
3235

3336
/** Get a components innerHTML as a document Fragment */
34-
private static getDocumentFragment(componentRef: ComponentRef<any>): DocumentFragment {
35-
const template = document.createElement('template');
36-
template.innerHTML = (<HTMLElement>componentRef.location.nativeElement).innerHTML;
37+
// private static getDocumentFragment(componentRef: ComponentRef<any>): DocumentFragment {
38+
// const template = document.createElement('template');
39+
// template.innerHTML = (<HTMLElement>componentRef.location.nativeElement).innerHTML;
3740

38-
return template.content;
39-
}
41+
// return template.content;
42+
// }
4043

41-
constructor(private readonly compiler: Compiler, private readonly injector: Injector, private readonly moduleRef: NgModuleRef<any>) {}
44+
// constructor(private readonly compiler: Compiler,private readonly injector: Injector, private readonly moduleRef: NgModuleRef<any>) {}
4245

4346
/** Sets a widgets properties upon Widget creation */
4447
initializeControl(control: Widget, bind = true): void {
@@ -58,15 +61,27 @@ export class JsonSchemaFormService {
5861
* @param context - options to use when rendering the template
5962
*/
6063
compileTemplate(template: string, context: {[key: string]: any} = {}): DocumentFragment {
61-
const component: any = JsonSchemaFormService.createComponent(template, context);
62-
const module = JsonSchemaFormService.createModule(component, this.compiler);
63-
const factory = module.componentFactories.find((f) => f.componentType === component);
64-
const componentRef: ComponentRef<any> = factory.create(this.injector, undefined, undefined, this.moduleRef);
64+
const templateTag = document.createElement('template');
65+
templateTag.innerHTML = Handlebars.compile(template)({options: context});
6566

66-
componentRef.hostView.detectChanges();
67-
const fragment = JsonSchemaFormService.getDocumentFragment(componentRef);
68-
componentRef.destroy();
69-
70-
return fragment;
67+
return templateTag.content;
7168
}
69+
70+
// /**
71+
// * Compiles an HTML tempalte and data into a document fragment
72+
// * @param template - HTML template to render
73+
// * @param context - options to use when rendering the template
74+
// */
75+
// compileTemplate(template: string, context: {[key: string]: any} = {}): DocumentFragment {
76+
// const component: any = JsonSchemaFormService.createComponent(template, context);
77+
// const module = JsonSchemaFormService.createModule(component, this.compiler);
78+
// const factory = module.componentFactories.find((f) => f.componentType === component);
79+
// const componentRef: ComponentRef<any> = factory.create(this.injector, undefined, undefined, this.moduleRef);
80+
81+
// componentRef.hostView.detectChanges();
82+
// const fragment = JsonSchemaFormService.getDocumentFragment(componentRef);
83+
// componentRef.destroy();
84+
85+
// return fragment;
86+
// }
7287
}

0 commit comments

Comments
 (0)