Skip to content
This repository was archived by the owner on Aug 25, 2020. It is now read-only.

Added basic layout #96

Merged
merged 5 commits into from
Feb 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/ngx-forms.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { FieldConfig, Field } from "./src/types";
export { NgxFormModule } from "./src/app/app.module";
export { DynamicFormDirective } from "./src/app/dynamic-form/dynamic-form.component";
export { DynamicFormDirective } from "./src/app/dynamic-form/dynamic-form.component";
export { BaseLayout } from './src/app/layouts/base-layout';
4 changes: 2 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class NgxFormModule {
}
}

// TODO: next
// create different default layouts for ngx-forms
// TODO:

// make nav part of group-layout
// individual field layout ????
9 changes: 5 additions & 4 deletions src/app/dynamic-form/dynamic-form.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class TestComponent {
data: {};
dynamicForm: {};
lookups: {};
model: any
}

@NgModule({
Expand Down Expand Up @@ -81,19 +82,19 @@ describe('DynamicFormDirective', () => {


it('should call changes()', () => {
expect(dir.changes).toEqual(dir.form.valueChanges);
expect(dir.changes).toEqual(dir.formGroup.valueChanges);
});

it('should call valid()', () => {
expect(dir.valid).toEqual(dir.form.valid);
expect(dir.valid).toEqual(dir.formGroup.valid);
});

it('should call value()', () => {
expect(dir.value).toEqual(dir.form.value);
expect(dir.value).toEqual(dir.formGroup.value);
});

it('should call value()', () => {
expect(dir.rawValue).toEqual(dir.form.getRawValue());
expect(dir.rawValue).toEqual(dir.formGroup.getRawValue());
});

});
Expand Down
14 changes: 7 additions & 7 deletions src/app/dynamic-form/dynamic-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ export class DynamicFormDirective implements OnInit {
@Input() model: any;
@Input() lookups: object;

public form: FormGroup;
get changes() { return this.form.valueChanges; }
get valid() { return this.form.valid; }
get value() { return this.form.value; }
get rawValue() { return this.form.getRawValue(); }
public formGroup: FormGroup;
get changes() { return this.formGroup.valueChanges; }
get valid() { return this.formGroup.valid; }
get value() { return this.formGroup.value; }
get rawValue() { return this.formGroup.getRawValue(); }

constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private container: ViewContainerRef,
@Inject(LAYOUTS_TOKEN) private layouts: LayoutDictionary) {
this.form = new FormGroup({});
this.formGroup = new FormGroup({});
}

public ngOnInit(): void {
Expand All @@ -31,7 +31,7 @@ export class DynamicFormDirective implements OnInit {
const componentReference = this.layouts[this.formConfig.layout];
const componentFactory = this.componentFactoryResolver.resolveComponentFactory<Layout>(componentReference);
const component = this.container.createComponent(componentFactory);
component.instance.form = this.form;
component.instance.formGroup = this.formGroup;
component.instance.formConfig = this.formConfig;
component.instance.model = this.model;
}
Expand Down
10 changes: 10 additions & 0 deletions src/app/layouts/base-layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormConfig, Layout } from '../../types';

export class BaseLayout implements Layout {
@Input() formConfig: FormConfig;
@Input() model: any;
@Input() lookups: object;
@Input() formGroup: FormGroup;
}
6 changes: 6 additions & 0 deletions src/app/layouts/basic/basic-layout.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div class="row">
<div class="col-md-12" [formGroup]="formGroup">
<h2>{{formConfig.title}}</h2>
<div *ngFor="let field of formConfig.fields" dynamicField [field]="field" [group]="formGroup" [model]="model" class="mb-2"></div>
</div>
</div>
77 changes: 77 additions & 0 deletions src/app/layouts/basic/basic-layout.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Component, NgModule } from "@angular/core";
import { Field, FieldConfig, FieldDictionary, FIELD_DICT_TOKEN, FormConfig } from "../../../types";
import { FormGroup, ReactiveFormsModule, FormsModule } from "@angular/forms";
import { ComponentFixture, TestBed, async } from "@angular/core/testing";
import { CommonModule } from "@angular/common";
import { DynamicFieldDirective } from "../../dynamic-field/dynamic-field.directive";
import { BasicLayoutComponent } from './basic-layout.component';
import { DynamicFormDirective} from '../../dynamic-form/dynamic-form.component';

@Component({
selector: 'form-input',
template: '<div [formGroup]="group"><input [formControlName]="field.name"></div>'
})
export class FormInputComponent implements Field {
field: FieldConfig;
group: FormGroup;
}

const defaultInputs: FieldDictionary = {
text: FormInputComponent
}

@Component({
template: `<dynamic-form [formConfig]="formConfig" #form="dynamicForm" [model]="data" [lookups]="lookups"></dynamic-form>`
})
class TestComponent {
formConfig
data: {};
dynamicForm: {};
lookups: {};
}

@NgModule({
declarations: [FormInputComponent],
imports: [FormsModule, ReactiveFormsModule, CommonModule],
entryComponents: [FormInputComponent, BasicLayoutComponent]
})
class TestModule { }

describe('BasicLayoutComponent Core', () => {
let component: BasicLayoutComponent;
let fixture: ComponentFixture<BasicLayoutComponent>;
let model = { test: 'test', title: 'title' };

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DynamicFieldDirective, TestComponent, BasicLayoutComponent, DynamicFormDirective],
imports: [FormsModule, ReactiveFormsModule, TestModule],
providers: [{ provide: FIELD_DICT_TOKEN, useValue: defaultInputs }]
}).compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(BasicLayoutComponent);
component = fixture.componentInstance;
component.formGroup = new FormGroup({})
component.formConfig = {
form: [
{ label: 'fields and panels', panels: [{ label: 'fields', fields: [{ type: 'text', name: 'title', required: true }] }] },
{ label: 'fields, no panels', fields: [{ type: 'text', name: 'test', required: true }] },
{ label: 'no fields with panels', panels: [{ label: 'no fields' }] },
{ label: 'no fields, no panels' }
]
} as FormConfig;
component.model = model;
fixture.detectChanges();
});

describe('ngOnInit()', () => {

it('should create group', () => {
expect(component.formGroup).toBeDefined();
});

});

});
8 changes: 8 additions & 0 deletions src/app/layouts/basic/basic-layout.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Component } from '@angular/core';
import { BaseLayout } from '../base-layout';

@Component({
selector: 'layout-basic',
template: require('./basic-layout.component.html')
})
export class BasicLayoutComponent extends BaseLayout { }
8 changes: 4 additions & 4 deletions src/app/layouts/groups/group/group.component.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<div class="row">
<div class="col-md-2">
<form-nav [form]="form"></form-nav>
<form-nav [form]="formGroup"></form-nav>
</div>
<div class="col-md-10" [formGroup]="form">
<div class="col-md-10" [formGroup]="formGroup">
<div *ngFor="let panel of formConfig.form" [navTab]="panel">

<ng-container *ngIf="panel.fields">
<layout-group-panel [panelConfig]="panel" [group]="form" [model]="model" [hidden]="panel.hidden"></layout-group-panel>
<layout-group-panel [panelConfig]="panel" [group]="formGroup" [model]="model" [hidden]="panel.hidden"></layout-group-panel>
</ng-container>

<ng-container *ngIf="panel.panels">
<layout-group-panel *ngFor="let panelConfig of panel.panels" [panelConfig]="panelConfig" [group]="form"
<layout-group-panel *ngFor="let panelConfig of panel.panels" [panelConfig]="panelConfig" [group]="formGroup"
[model]="model" [hidden]="panel.hidden"></layout-group-panel>
</ng-container>
</div>
Expand Down
22 changes: 11 additions & 11 deletions src/app/layouts/groups/group/group.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, NgModule } from "@angular/core";
import { Field, FieldConfig, FieldDictionary, FIELD_DICT_TOKEN, ConditionType, LAYOUTS_TOKEN } from "../../../../types";
import { Field, FieldConfig, FieldDictionary, FIELD_DICT_TOKEN, ConditionType, LAYOUTS_TOKEN, FormConfig } from "../../../../types";
import { FormGroup, ReactiveFormsModule, FormsModule } from "@angular/forms";
import { ComponentFixture, TestBed, async } from "@angular/core/testing";
import { CommonModule } from "@angular/common";
Expand Down Expand Up @@ -111,58 +111,58 @@ describe('GroupComponent Core', () => {
beforeEach(() => {
fixture = TestBed.createComponent(GroupComponent);
component = fixture.componentInstance;
component.form = new FormGroup({})
component.formGroup = new FormGroup({})
component.formConfig = {
form: [
{ label: 'fields and panels', panels: [{ label: 'fields', fields: [{ type: 'text', name: 'title', required: true }] }] },
{ label: 'fields, no panels', fields: [{ type: 'text', name: 'test', required: true }] },
{ label: 'no fields with panels', panels: [{ label: 'no fields' }] },
{ label: 'no fields, no panels' }
]
};
} as FormConfig;
component.model = model;
fixture.detectChanges();
});

describe('ngOnInit()', () => {

it('should create group', () => {
expect(component.form).toBeDefined();
expect(component.formGroup).toBeDefined();
});

describe('Lookup Expansion', () => {

it('should not find lookup when no lookups were passed', () => {
component.lookups = null;
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title', lookup: 'test' }] }] };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title', lookup: 'test' }] }] } as FormConfig;
component.ngOnInit();
expect(component.formConfig.form[0].fields[0].options).toBeUndefined();
});

it('should not find lookup when no lookups found', () => {
component.lookups = { test: ['a', 'b', 'c'] };;
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title' }] }] };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title' }] }] } as FormConfig;
component.ngOnInit();
expect(component.formConfig.form[0].fields[0].options).toBeUndefined();
});

it('should not copy lookup with wrong name', () => {
component.lookups = { test: ['a', 'b', 'c'] };;
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title', lookup: 'test1' }] }] };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title', lookup: 'test1' }] }] } as FormConfig;
component.ngOnInit();
expect(component.formConfig.form[0].fields[0].options).toBeUndefined();
});

it('should copy lookup', () => {
component.lookups = { test: ['a', 'b', 'c'] };;
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title', lookup: 'test' }] }] };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title', lookup: 'test' }] }] } as FormConfig;
component.ngOnInit();
expect(component.formConfig.form[0].fields[0].options).toEqual(['a', 'b', 'c']);
});

it('should extract lookup', () => {
component.lookups = { test: [{ t: 'a' }, { t: 'b' }, { t: 'c' }] };;
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title', lookup: { name: 'test', extract: 't' } }] }] };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title', lookup: { name: 'test', extract: 't' } }] }] } as FormConfig;
component.ngOnInit();
expect(component.formConfig.form[0].fields[0].options).toEqual(['a', 'b', 'c']);
});
Expand All @@ -173,14 +173,14 @@ describe('GroupComponent Core', () => {

it('should enable the fields', () => {
component.model = { title: 'test' };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title' }], enableWhen: { rules: [{ field: "title", equals: ["test"] }] } }] };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title' }], enableWhen: { rules: [{ field: "title", equals: ["test"] }] } }] } as FormConfig;
component.ngOnInit();
expect(component.formConfig.form[0].fields[0].disabled).toBeFalsy();
});

it('should disable the fields', () => {
component.model = { title: 'test' };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title' }], enableWhen: { rules: [{ field: "title", equals: ["test1"] }] } }] };
component.formConfig = { form: [{ fields: [{ type: 'text', name: 'title' }], enableWhen: { rules: [{ field: "title", equals: ["test1"] }] } }] } as FormConfig;
component.ngOnInit();
expect(component.formConfig.form[0].fields[0].disabled).toBeTruthy();
});
Expand Down
12 changes: 4 additions & 8 deletions src/app/layouts/groups/group/group.component.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FieldConfig, ILookup, FormConfig, PanelGroup, ConditionType } from '../../../../types'; // todo: move specific types here
import { Component, OnInit } from '@angular/core';
import { FieldConfig, ILookup, PanelGroup, ConditionType } from '../../../../types'; // todo: move specific types here
import { BaseLayout } from '../../base-layout';

@Component({
selector: 'layout-group-group',
template: require('./group.component.html'),
styles: [require('./group.component.scss').toString()]
})
export class GroupComponent implements OnInit {
@Input() formConfig: FormConfig;
@Input() model: any;
@Input() lookups: object;
@Input() form: FormGroup;
export class GroupComponent extends BaseLayout implements OnInit {

public ngOnInit(): void {
let fields: FieldConfig[] = [];
Expand Down
16 changes: 8 additions & 8 deletions src/app/layouts/layouts.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LayoutDictionary } from '../../types';
import { GroupComponent } from './groups/group/group.component';
import { FormNavModule} from './groups/nav/nav-app';
import { FormNavModule } from './groups/nav/nav-app';
import { PanelComponent } from './groups/panel/panel.component';
import { DynamicFieldModule } from '../dynamic-field/dynamic-field.module';
import { BasicLayoutComponent } from './basic/basic-layout.component';

export const defaultLayouts: LayoutDictionary = {
groups: GroupComponent
groups: GroupComponent,
basic: BasicLayoutComponent
};

@NgModule({
Expand All @@ -18,15 +20,13 @@ export const defaultLayouts: LayoutDictionary = {
],
declarations: [
GroupComponent,
PanelComponent
],
exports: [
GroupComponent,
PanelComponent
PanelComponent,
BasicLayoutComponent
],
entryComponents: [
GroupComponent,
PanelComponent
PanelComponent,
BasicLayoutComponent
],
schemas: [
NO_ERRORS_SCHEMA
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const FIELD_DICT_TOKEN = new InjectionToken<FieldDictionary>('fields');
export const LAYOUTS_TOKEN = new InjectionToken<Layout>('layouts');

export interface Layout {
form: FormGroup;
formGroup: FormGroup;
formConfig: any;
model: any;
}
Expand Down