Skip to content

Commit

Permalink
feat: display a simple hidden input (#6)
Browse files Browse the repository at this point in the history
* feat: hidden component

* refactor: move button to input folder

* feat: service to fetch Widgets

* refactor: force layout to be loaded from example

* refactor: replace widget with type

* feat: set name on widget control

* refactor: convert div container to template

* refactor: remove formControl until its ready

* fix: error being thrown in demo

* fix: lint error for unused variable

* fix: missed _id renaming to id

* fix: logic error in parsing examples

* test: adds missing test cases
  • Loading branch information
jscharett authored Jun 30, 2019
1 parent 8f3f877 commit 0c44ac1
Show file tree
Hide file tree
Showing 29 changed files with 243 additions and 42 deletions.
4 changes: 1 addition & 3 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@
"styles": [
"projects/demo/src/styles.scss"
],
"scripts": [
"node_modules/ace-builds/src-min/ace.js"
]
"scripts": []
},
"configurations": {
"production": {
Expand Down
1 change: 1 addition & 0 deletions projects/demo/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
<ng-template #showForm>
<jsf-json-schema-form
[schema]="jsonFormSchema"
[layout]="jsonFormLayout"
></jsf-json-schema-form>
<!-- loadExternalAssets="true"
[form]="jsonFormObject"
Expand Down
7 changes: 5 additions & 2 deletions projects/demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class AppComponent implements OnInit {
formActive = false;
jsonFormValid = false;
jsonFormSchema: JSONSchema7;
jsonFormLayout: Array<any>;
jsonFormStatusMessage = 'Loading form...';
// jsonFormObject: any;
// jsonFormOptions: any = {
Expand Down Expand Up @@ -100,9 +101,10 @@ export class AppComponent implements OnInit {
}
if (params.example) {
this.selectedExample = params.example;
this.jsonLoader.examples.subscribe((examples: Array<any>) => {
this.jsonLoader.examples.subscribe((examples: Array<{set: string; examples: Array<{name: string}>}>) => {
this.selectedExampleName = examples
.find((data: any) => data.set === [this.selectedSet])
.find((data: any) => data.set === this.selectedSet)
.examples
.find((data: any) => data.file === this.selectedExample).name;
});
}
Expand Down Expand Up @@ -221,6 +223,7 @@ export class AppComponent implements OnInit {
// Parse entered content as JSON
const jsonFormObject = JSON.parse(newFormString);
this.jsonFormSchema = jsonFormObject.schema;
this.jsonFormLayout = jsonFormObject.layout;
this.jsonFormValid = true;
this.formActive = true;
} catch (jsonError) {
Expand Down
7 changes: 6 additions & 1 deletion projects/demo/src/assets/examples/ngx/simple-array.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@
},
"data": {
"items": [ "Item 1", "Item 2", "Item 3", "Item 4" ]
}
},
"layout": [{
"key": "items",
"type": "hidden",
"name": "simpleItems"
}]
}
1 change: 1 addition & 0 deletions projects/demo/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

import 'brace';
import 'brace/mode/json';

if (environment.production) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[ {
"key": "comment",
"type": "textarea"
"type": "textarea",
"name": "control"
} ]
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<form (ngSubmit)="submitForm()">
<div *ngFor="let layoutItem of layoutService.layout; trackBy: trackByFn;">
<jsf-select-widget [layoutNode]=layoutItem></jsf-select-widget>
<jsf-select-widget [layoutNode]="layoutItem"></jsf-select-widget>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { TestBed } from '@angular/core/testing';

import { JsonSchemaFormService } from './json-schema-form.service';
import { Widget } from './widget-library';

describe('JsonSchemaFormService', () => {
class TestWidget extends Widget {}

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
Expand All @@ -15,4 +18,12 @@ describe('JsonSchemaFormService', () => {
const service: JsonSchemaFormService = TestBed.get(JsonSchemaFormService);
expect(service).toBeTruthy();
});

it('should set controlName on widget', () => {
const service: JsonSchemaFormService = TestBed.get(JsonSchemaFormService);
const widget: TestWidget = new TestWidget(service);
widget.layoutNode = {name: 'widget', id: '1', key: 'key', options: {}};
service.initializeControl(widget);
expect(widget.controlName).toBe('widget');
});
});
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { Injectable } from '@angular/core';
import { Widget } from './widget-library';

@Injectable()
export class JsonSchemaFormService {
private x = false;

initializeControl(ctx: any, bind = true): boolean {
// TODO

return this.x;
initializeControl(control: Widget, bind = true): void {
control.controlName = control.layoutNode.name;
}

updateValue(ctx: any, value: any): void {
// TODO
this.x = value;
this.x = !this.x;
}
}
5 changes: 1 addition & 4 deletions projects/ngx-json-schema-form/src/lib/layout-item.data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Widget } from './widget-library';

export interface LayoutItem {
id: string;
options: any;
Expand All @@ -10,8 +8,7 @@ export interface LayoutItem {
// dataType?;
items?: Array<any>;
key?: string;
// name?;
name?: string;
// recursiveReference?;
type?: string;
widget?: typeof Widget;
}
3 changes: 1 addition & 2 deletions projects/ngx-json-schema-form/src/lib/layout.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ describe('LayoutService', () => {
service.layout = basicJSONLayout;
expect(service.layout).toEqual([{
id: jasmine.any(String),
key: basicJSONLayout[0].key,
options: {},
type: basicJSONLayout[0].type
...basicJSONLayout[0]
}]);
}));

Expand Down
2 changes: 1 addition & 1 deletion projects/ngx-json-schema-form/src/lib/layout.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class LayoutService {
const newNode: LayoutItem = {
id: uniqueId(),
options: {},
...pick(layoutItem, ['key', 'type'])
...pick(layoutItem, ['key', 'type', 'name'])
};
// Dropped code to push invalid props into options
// Dropped code to convert widget to type
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div #widgetContainer></div>
<ng-template #widgetContainer></ng-template>
Original file line number Diff line number Diff line change
@@ -1,25 +1,83 @@
import { CommonModule } from '@angular/common';
import { Component, ComponentRef, NgModule } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { JsonSchemaFormService } from '../../../json-schema-form.service';

import { WidgetLibraryService } from '../../widget-library.service';

import { SelectWidgetComponent } from './select-widget.component';

describe('SelectWidgetComponent', () => {
let component: SelectWidgetComponent;
let fixture: ComponentFixture<SelectWidgetComponent>;
let newComponent: ComponentRef<any>;

@Component({
selector: 'jsf-component',
template: '<div>Hello World</div>'
})
class TestComponent {}

@NgModule({
declarations: [ TestComponent ],
entryComponents: [ TestComponent ],
imports: [ CommonModule ]
})
class TestModule {} // tslint:disable-line

beforeEach(async () => {
const mockFormService: JsonSchemaFormService = jasmine.createSpyObj('JsonSchemaFormService', {
initializeControl: true
});
const mockWidgetService: WidgetLibraryService = jasmine.createSpyObj('WidgetLibraryService', {
getWidget: TestComponent
});

return TestBed.configureTestingModule({
declarations: [ SelectWidgetComponent ]
declarations: [ SelectWidgetComponent ],
imports: [ TestModule ],
providers: [{
provide: JsonSchemaFormService,
useValue: mockFormService
}, {
provide: WidgetLibraryService,
useValue: mockWidgetService
}]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(SelectWidgetComponent);
component = fixture.componentInstance;
component.layoutNode = {id: '0', options: {}, type: 'hidden'};
const original = component.widgetContainer.createComponent;
spyOn(component.widgetContainer, 'createComponent').and.callFake((...args) => {
newComponent = original.apply(component.widgetContainer, args);

return newComponent;
});
fixture.detectChanges();
});

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

it('should instantiate widget', () => {
expect(newComponent.componentType).toEqual(TestComponent);
});

it('should set properties', () => {
expect(newComponent.instance.layoutNode).toEqual(component.layoutNode);
expect(newComponent.instance.layoutIndex).toEqual(component.layoutIndex);
expect(newComponent.instance.dataIndex).toEqual(component.dataIndex);
});

it('should update component when input changes', () => {
component.dataIndex = [1 + 1];
component[`ngOnChanges`]();
expect(newComponent.instance.dataIndex).toEqual(component.dataIndex);
});
});
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import {
Component, ComponentFactoryResolver, ComponentRef, Input,
Component, ComponentFactoryResolver, ComponentRef,
OnChanges, OnInit, ViewChild, ViewContainerRef
} from '@angular/core';

import { LayoutItem } from '../../../layout-item.data';
import { JsonSchemaFormService } from '../../../json-schema-form.service';

import { Widget } from '../../widget';
import { WidgetLibraryService } from '../../widget-library.service';

@Component({
selector: 'jsf-select-widget',
styleUrls: ['./select-widget.component.css'],
templateUrl: './select-widget.component.html'
})
export class SelectWidgetComponent implements OnInit, OnChanges {
@Input() layoutNode: LayoutItem;

export class SelectWidgetComponent extends Widget implements OnInit, OnChanges {
private newComponent: ComponentRef<any>;
@ViewChild('widgetContainer', { read: ViewContainerRef }) widgetContainer: ViewContainerRef;

constructor(private readonly componentFactory: ComponentFactoryResolver) { }
constructor(private readonly componentFactory: ComponentFactoryResolver,
private readonly widgetLibraryService: WidgetLibraryService,
jsf: JsonSchemaFormService) {
super(jsf);
}

ngOnInit() {
this.updateComponent();
Expand All @@ -36,9 +41,10 @@ export class SelectWidgetComponent implements OnInit, OnChanges {
}

private createComponent() {
if (!this.newComponent && this.layoutNode && this.layoutNode.widget) {
// TODO: What if layoutNode were to change? The form would be incorrect.
if (!this.newComponent && this.layoutNode && this.layoutNode.type) {
this.newComponent = this.widgetContainer.createComponent(
this.componentFactory.resolveComponentFactory(this.layoutNode.widget as any)
this.componentFactory.resolveComponentFactory(this.widgetLibraryService.getWidget(this.layoutNode.type) as any)
);
}
}
Expand Down
11 changes: 8 additions & 3 deletions projects/ngx-json-schema-form/src/lib/widget-library/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { ButtonComponent } from './button/button.component';
import { ButtonComponent } from './input/button/button.component';
import { HiddenComponent } from './input/hidden/hidden.component';

import { SelectWidgetComponent } from './container/select-widget/select-widget.component';

export const BASIC_WIDGETS = [
ButtonComponent, SelectWidgetComponent
ButtonComponent, HiddenComponent,
SelectWidgetComponent
];

export { Widget } from './widget';

export { ButtonComponent } from './button/button.component';
export { ButtonComponent } from './input/button/button.component';
export { HiddenComponent } from './input/hidden/hidden.component';

export { SelectWidgetComponent } from './container/select-widget/select-widget.component';
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<button
[attr.readonly]="options?.readonly ? 'readonly' : null"
[attr.aria-describedby]="'control' + layoutNode?._id + 'Status'"
[attr.aria-describedby]="'control' + layoutNode.id + 'Status'"
[class]="options?.htmlClass || ''"
[disabled]="controlDisabled"
[name]="controlName"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, inject, TestBed } from '@angular/core/testing';

import { JsonSchemaFormService } from '../..';
import { JsonSchemaFormService } from '../../..';

import { ButtonComponent } from './button.component';

Expand Down Expand Up @@ -32,7 +32,7 @@ describe('ButtonComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ButtonComponent);
component = fixture.componentInstance;
component.layoutNode = {};
component.layoutNode = {id: '0', options: {}};
fixture.detectChanges();
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Component } from '@angular/core';

import { JsonSchemaFormService } from '../../json-schema-form.service';
import { JsonSchemaFormService } from '../../../json-schema-form.service';

import { Widget } from '../widget';
import { Widget } from '../../widget';

@Component({
selector: 'jsf-button',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<input
[id]="'control' + layoutNode.id"
[name]="controlName"
type="hidden">
Empty file.
Loading

0 comments on commit 0c44ac1

Please sign in to comment.