Skip to content

Commit

Permalink
feat: allows use in lazy loaded modules
Browse files Browse the repository at this point in the history
The new 'providedIn' syntax does not
work for EventPlugins, which still get registered
in the module.  Therefore, the 'forRoot' syntax is
required to enforce the provider being registered
in the root only
  • Loading branch information
jscharett committed Aug 14, 2019
1 parent d14beb1 commit aef7363
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 66 deletions.
19 changes: 3 additions & 16 deletions projects/demo/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,25 @@
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FormsModule } from '@angular/forms';
import {
MatButtonModule, MatCardModule, MatCheckboxModule, MatIconModule,
MatInputModule, MatMenuModule, MatSelectModule, MatToolbarModule
} from '@angular/material';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule } from '@angular/router';

import { AceEditorModule } from 'ng2-ace-editor';

import { JsonSchemaFormModule } from '../../../ngx-json-schema-form/src/public-api';

import { AppComponent } from './app.component';
import { routes } from './app.routes';
import { RootComponent } from './root.component';

@NgModule({
bootstrap: [ RootComponent ],
declarations: [
AppComponent,
RootComponent
],
imports: [
BrowserModule, BrowserAnimationsModule, FormsModule, HttpClientModule, FlexLayoutModule,
MatButtonModule, MatCardModule, MatCheckboxModule, MatIconModule,
MatInputModule, MatMenuModule, MatSelectModule, MatToolbarModule,
RouterModule.forRoot(routes),
BrowserModule, BrowserAnimationsModule, HttpClientModule,

AceEditorModule,
RouterModule.forRoot(routes),

JsonSchemaFormModule
JsonSchemaFormModule.forRoot()
]
})
export class AppModule { }
12 changes: 8 additions & 4 deletions projects/demo/src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { Route } from '@angular/router';

import { AppComponent } from './app.component';

export const routes: Array<Route> = [
{ path: '', component: AppComponent },
{ path: '**', component: AppComponent }
{
loadChildren: './demo/demo.module#DemoModule',
path: ''
},
{
loadChildren: './demo/demo.module#DemoModule',
path: '**'
}
];
10 changes: 10 additions & 0 deletions projects/demo/src/app/demo/demo-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { routes } from './demo.routes';

@NgModule({
exports: [ RouterModule ],
imports: [ RouterModule.forChild(routes) ]
})
export class DemoRoutingModule { }
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ import { RouterTestingModule } from '@angular/router/testing';

import { cold, getTestScheduler } from 'jasmine-marbles';

import examples from '../assets/examples/examples.json';
import example from '../assets/examples/ngx/simple-array.json';
import examples from '../../assets/examples/examples.json';
import example from '../../assets/examples/ngx/simple-array.json';

import { AppComponent } from './app.component';
import { routes } from './app.routes';
import { JsonLoaderService } from './json-loader.service';
import { JsonLoaderService } from '../json-loader.service';

describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
let app: AppComponent;
import { DemoComponent } from './demo.component';
import { routes } from './demo.routes';


describe('DemoComponent', () => {
let fixture: ComponentFixture<DemoComponent>;
let component: DemoComponent;

beforeEach(async () => {
const jsl: JsonLoaderService = jasmine.createSpyObj('JsonLoaderService', {
Expand All @@ -29,7 +31,7 @@ describe('AppComponent', () => {

return TestBed.configureTestingModule({
declarations: [
AppComponent
DemoComponent
],
imports: [ MatMenuModule, RouterTestingModule.withRoutes(routes) ],
providers: [{
Expand All @@ -41,46 +43,46 @@ describe('AppComponent', () => {
});

beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;
fixture = TestBed.createComponent(DemoComponent);
component = fixture.debugElement.componentInstance;
fixture.detectChanges();
});

it('should create the app', () => {
expect(app).toBeTruthy();
it('should create the component', () => {
expect(component).toBeTruthy();
});

it(`should not activate form when empty string`, () => {
expect(app.formActive).toBeFalsy();
app.generateForm('');
expect(app.formActive).toBeFalsy();
expect(component.formActive).toBeFalsy();
component.generateForm('');
expect(component.formActive).toBeFalsy();
});

it(`should activate form`, () => {
expect(app.formActive).toBeFalsy();
app.generateForm('{}');
expect(app.formActive).toBeTruthy();
expect(component.formActive).toBeFalsy();
component.generateForm('{}');
expect(component.formActive).toBeTruthy();
});

it(`should not activate form when bad json`, () => {
expect(app.formActive).toBeFalsy();
app.generateForm('{a:}');
expect(app.formActive).toBeFalsy();
expect(app.jsonFormStatusMessage).toContain('JavaScript parser returned');
expect(component.formActive).toBeFalsy();
component.generateForm('{a:}');
expect(component.formActive).toBeFalsy();
expect(component.jsonFormStatusMessage).toContain('JavaScript parser returned');
});

it('should fetch example and generate form', () => {
spyOn(app, 'generateForm');
app.loadSelectedExample();
spyOn(component, 'generateForm');
component.loadSelectedExample();
getTestScheduler().flush();
expect(app.generateForm).toHaveBeenCalledWith(JSON.stringify(example));
expect(component.generateForm).toHaveBeenCalledWith(JSON.stringify(example));
});

it('should navigate to the loaded example', fakeAsync(() => {
const router: Router = TestBed.get(Router);
const location: Location = TestBed.get(Location);
router.initialNavigation();
app.loadSelectedExample('ngx', 'b', 'c', 'd');
component.loadSelectedExample('ngx', 'b', 'c', 'd');
tick();
expect(location.path()).toBe('/?set=ngx&example=c');
}));
Expand All @@ -89,7 +91,7 @@ describe('AppComponent', () => {
const layout = {onClick: 'alert("Cats");'};
spyOn(console, 'warn');
spyOn(window, 'alert');
app.onClick(layout);
component.onClick(layout);
expect(console.warn).toHaveBeenCalledWith(layout);
expect(window.alert).toHaveBeenCalledWith('Cats');
});
Expand All @@ -98,7 +100,7 @@ describe('AppComponent', () => {
const event = {};
spyOn(console, 'warn');
spyOn(window, 'alert');
app.onClick(event);
component.onClick(event);
expect(console.warn).toHaveBeenCalledWith(event);
expect(window.alert).not.toHaveBeenCalled();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { Observable } from 'rxjs';

import { JSONSchema7 } from 'json-schema';

import { LayoutItem } from '../../../ngx-json-schema-form/src/lib/layout-item.data';
import { LayoutItem } from '../../../../ngx-json-schema-form/src/lib/layout-item.data';

import { JsonLoaderService } from './json-loader.service';
import { JsonLoaderService } from '../json-loader.service';

const sets = {
// asf: 'Angular Schema Form:',
Expand All @@ -32,10 +32,10 @@ const sets = {
])
],
selector: 'app-demo',
styleUrls: ['./app.component.scss'],
templateUrl: './app.component.html'
styleUrls: ['./demo.component.scss'],
templateUrl: './demo.component.html'
})
export class AppComponent implements OnInit {
export class DemoComponent implements OnInit {
// examples: any = {ngx: {}};
// languageList: any = ['en', 'fr'];
// languages: any = {
Expand Down
32 changes: 32 additions & 0 deletions projects/demo/src/app/demo/demo.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FormsModule } from '@angular/forms';
import {
MatButtonModule, MatCardModule, MatCheckboxModule, MatIconModule,
MatInputModule, MatMenuModule, MatSelectModule, MatToolbarModule
} from '@angular/material';

import { AceEditorModule } from 'ng2-ace-editor';

import { JsonSchemaFormModule } from '../../../../ngx-json-schema-form/src/public-api';

import { DemoRoutingModule } from './demo-routing.module';
import { DemoComponent } from './demo.component';

@NgModule({
declarations: [ DemoComponent ],
imports: [
CommonModule,
DemoRoutingModule,
FormsModule, FlexLayoutModule,

MatButtonModule, MatCardModule, MatCheckboxModule, MatIconModule,
MatInputModule, MatMenuModule, MatSelectModule, MatToolbarModule,

AceEditorModule,

JsonSchemaFormModule
]
})
export class DemoModule { }
14 changes: 14 additions & 0 deletions projects/demo/src/app/demo/demo.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Routes } from '@angular/router';

import { DemoComponent } from './demo.component';

export const routes: Routes = [
{
component: DemoComponent,
path: ''
},
{
component: DemoComponent,
path: '**'
}
];
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { EventManager } from '@angular/platform-browser';
import { ElementDataStorageService } from './element-data-storage.service';

export interface Data {
/** Data associated with an HTML Element */
data: any;
}
/** Event wrapper for piggybacking data on an event */
Expand All @@ -14,9 +15,7 @@ export type DataEvent<T> = Data & T;
* "associated" with an element by means of the ElementDataStorageService. If no data is
* present, then the event handler will not be fired.
*/
@Injectable({
providedIn: 'root'
})
@Injectable()
export class DataEventPluginService {
/** Event manager used to get the ngZone */
manager: EventManager;
Expand Down
22 changes: 14 additions & 8 deletions projects/ngx-json-schema-form/src/lib/json-schema-form.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { ModuleWithProviders, NgModule } from '@angular/core';
import { EVENT_MANAGER_PLUGINS } from '@angular/platform-browser';

import { WidgetLibraryModule } from './widget-library/widget-library.module';
Expand All @@ -10,11 +10,17 @@ import { JsonSchemaFormComponent } from './json-schema-form.component';
@NgModule({
declarations: [ JsonSchemaFormComponent ],
exports: [ JsonSchemaFormComponent, WidgetLibraryModule ],
imports: [ CommonModule, WidgetLibraryModule ],
providers: [{
multi: true,
provide: EVENT_MANAGER_PLUGINS,
useClass: DataEventPluginService
}]
imports: [ CommonModule, WidgetLibraryModule ]
})
export class JsonSchemaFormModule { }
export class JsonSchemaFormModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: JsonSchemaFormModule,
providers: [{
multi: true,
provide: EVENT_MANAGER_PLUGINS,
useClass: DataEventPluginService
}]
};
}
}
2 changes: 1 addition & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"no-tautology-expression": true,
"no-this-assignment": true,
"no-unbound-method": false,// Currently a bug which doesn't allow for jasmine tests
"no-unnecessary-class": [true, "allow-empty-class"],
"no-unnecessary-class": [true, "allow-empty-class", "allow-static-only"],
"no-unsafe-any": false,// Appears to be buggy
"no-unsafe-finally": true,
"no-unused-expression": true,
Expand Down

0 comments on commit aef7363

Please sign in to comment.