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

Commit

Permalink
feat(ui): #PPC-50 #PPC-51 add radio and checkbox buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
kyxyes committed Jun 15, 2018
1 parent 22c6841 commit c5f3355
Show file tree
Hide file tree
Showing 26 changed files with 220 additions and 67 deletions.
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Greenkeeper badge](https://badges.greenkeeper.io/LabShare/ngx-forms.svg?token=4a12f6b1da0f082ac1bbf2c72bbcaf01b001705746c61c36eee1db6bda3d7c11&ts=1525971500061)](https://greenkeeper.io/)
Dynamic form generator. This module provides components that wrap angular 2+ FormBuilder styled with Bootstrap CSS 4
[![Coverage Status](https://coveralls.io/repos/github/LabShare/ngx-forms/badge.svg?t=K1oUbj)](https://coveralls.io/github/LabShare/ngx-forms)
![Alt text](/readmess.png?raw=true "Optional Title")
![Alt text](/imgs/readmess.png?raw=true "Optional Title")

## Requirements
- angular 2+
Expand Down Expand Up @@ -36,7 +36,7 @@ Name | Type | Description | Example
`disabled?` | `boolean` | disable field if `true` | `disabled: true`
`label?` | `string` | field label | `label: "Project Title"`
`name` | `string` | field name | `name: "projectTitle"`
`options?` | `string[]` | options for `<select>` dropdown | `options: [ "Option 1", "Option 2" ]`
`options?` | `string[]` | options for `<select>` dropdown or radio buttons | `options: [ "Option 1", "Option 2" ]`
`placeholder?` | `string` | text placeholder | `placeholder: "Enter Project Title"`
`type` | `string` | field type (see field type description) | `type: "select"`
`value?` | `any` | field value | `value: 123`
Expand All @@ -48,10 +48,26 @@ Name | Type | Description | Example
`max?` | `number` | Validation: maximum value for number fields | `max: 1000`
`pattern?` | `RegExp` | Validation: regular expression | `pattern: "^[a-zA-Z0-9_]*$"`
`nullValidator?` | `any` | Validation: null validation | `nullValidator: true`
`hidden` | `boolean` | hide the field by default when the form loading| `hidden: true`

## Field types
- `text` - text input `<input type="text">`
- `select` - text unput `<select>`
- `textarea` - text input `<textarea>`
- `editor` - Rich text editor based on `ngx-quill`
- `hidden` - hidden value field `<input type="hidden">`.
- `radio` - radio buttons
- `checkbox` - checkbox buttons

## Interaction between two fields
#### Show a new field by selecting a radio button
![Alt text](/imgs/ngx-forms-radio-buttons.gif)
When users select a value of radio button, a new field which name is same with `ref` in `options` will show up.
If `ref` in that option is missing, it will not show anything and reverse the status back.

Field example
```json
{ "type": "radio", "label": "Were NCATS core facilities used?", "name": "questions", "options": [{"value": "Yes", "ref": "checkId"}, {"value": "No"}]},
{ "type": "checkbox", "label":"Identify all that apply", "name": "checkId", "hidden": true, "options": [{"value": "NIH Grant"}, {"value": "NIH Intramural"}]}
```
So when users select radio button `Yes`, it will look for the field with name `checkID` and show the checkbox. When `No` is selected, the checkbox will hide because there is no value in `ref`.
2 changes: 1 addition & 1 deletion dist/ngx-forms.js

Large diffs are not rendered by default.

Binary file added imgs/ngx-forms-radio-buttons.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
16 changes: 11 additions & 5 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import { FormTextareaComponent } from './app/components/form-textarea/form-texta
import { FormTextEditorComponent } from './app/components/form-text-editor/form-text-editor.component';
import { FormInputHidden } from './app/components/form-hidden/form-hidden.component';
import { FormUserComponent } from './app/components/form-user/form-user.component';
import { FormRadioComponent } from "./app/components/form-radio/form-radio.component";
import { FormCheckboxComponent } from "./app/components/form-checkbox/form-checkbox.component";
import { TagInputModule } from "ngx-chips";
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DataService } from './app/services/data.service';

@NgModule({
Expand All @@ -30,9 +32,11 @@ import { DataService } from './app/services/data.service';
DynamicFieldDirective,
DynamicFormComponent,
FormInputComponent,
FormSelectComponent,
FormSelectComponent,
FormTextareaComponent,
FormUserComponent
FormUserComponent,
FormRadioComponent,
FormCheckboxComponent
],
exports: [
DynamicFormComponent
Expand All @@ -43,7 +47,9 @@ import { DataService } from './app/services/data.service';
FormSelectComponent,
FormTextEditorComponent,
FormTextareaComponent,
FormUserComponent
FormUserComponent,
FormRadioComponent,
FormCheckboxComponent
],
providers: [
DataService
Expand All @@ -52,4 +58,4 @@ import { DataService } from './app/services/data.service';
NO_ERRORS_SCHEMA
]
})
export class NgxFormModule { }
export class NgxFormModule { }
25 changes: 18 additions & 7 deletions src/app/components/dynamic-field/dynamic-field.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { FormGroup } from '@angular/forms';
import { FormInputComponent } from '../form-input/form-input.component';
import { FormSelectComponent } from '../form-select/form-select.component';
import { FormTextEditorComponent } from '../form-text-editor/form-text-editor.component';
import { FormCheckboxComponent } from "../form-checkbox/form-checkbox.component";
import { FormRadioComponent} from "../form-radio/form-radio.component";
import { Field } from '../../models/field.interface';
import { FieldConfig } from '../../models/field-config.interface';
import { FormTextareaComponent } from '../form-textarea/form-textarea.component';
Expand All @@ -15,19 +17,25 @@ const components: { [type: string]: Type<Field> } = {
editor: FormTextEditorComponent,
textarea: FormTextareaComponent,
hidden: FormInputHidden,
user: FormUserComponent
user: FormUserComponent,
radio: FormRadioComponent,
checkbox: FormCheckboxComponent
};

@Directive({
selector: '[dynamicField]'
})
export class DynamicFieldDirective implements Field, OnChanges, OnInit {
@Input()
config: FieldConfig;
field: FieldConfig;

@Input()
group: FormGroup;


@Input()
fields: [FieldConfig];

component: ComponentRef<Field>;

constructor(
Expand All @@ -37,22 +45,25 @@ export class DynamicFieldDirective implements Field, OnChanges, OnInit {

ngOnChanges() {
if (this.component) {
this.component.instance.config = this.config;
this.component.instance.field = this.field;
this.component.instance.group = this.group;
this.component.instance.fields = this.fields;
}
}

ngOnInit() {
if (!components[this.config.type]) {
if (!components[this.field.type]) {
const supportedTypes = Object.keys(components).join(', ');
throw new Error(
`Trying to use an unsupported type (${this.config.type}).
`Trying to use an unsupported type (${this.field.type}).
Supported types: ${supportedTypes}`
);
}
const component = this.resolver.resolveComponentFactory<Field>(components[this.config.type]);
const component = this.resolver.resolveComponentFactory<Field>(components[this.field.type]);
this.component = this.container.createComponent(component);
this.component.instance.config = this.config;
this.component.instance.field = this.field;
this.component.instance.group = this.group;
this.component.instance.fields = this.fields;

}
}
8 changes: 8 additions & 0 deletions src/app/components/form-checkbox/form-checkbox.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="form-group row" [formGroup]="group" *ngIf="isShow()">
<label class="col-md-2 font-weight-bold col-form-label">{{field.label}}</label>
<div class="col-md-10 container">
<label class="row" *ngFor="let item of field.options">
<input type="checkbox" [formControlName]="field.name">{{item.value}}
</label>
</div>
</div>
20 changes: 20 additions & 0 deletions src/app/components/form-checkbox/form-checkbox.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Component } from "@angular/core"
import { Field } from "../../models/field.interface";
import { FormGroup } from '@angular/forms';
import { FieldConfig } from '../../models/field-config.interface';

@Component({
selector: 'form-checkbox',
templateUrl: './form-checkbox.component.html'
})

export class FormCheckboxComponent implements Field{
field : FieldConfig;
group: FormGroup;
fields: FieldConfig[];


isShow () {
return !this.field.hidden;
}
}
4 changes: 2 additions & 2 deletions src/app/components/form-hidden/form-hidden.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<ng-container [formGroup]="group">
<input type="hidden" class="form-control" [formControlName]="config.name">
</ng-container>
<input type="hidden" class="form-control" [formControlName]="field.name">
</ng-container>
3 changes: 2 additions & 1 deletion src/app/components/form-hidden/form-hidden.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { FieldConfig } from '../../models/field-config.interface';
templateUrl: './form-hidden.component.html'
})
export class FormInputHidden implements Field {
config: FieldConfig;
field: FieldConfig;
group: FormGroup;
fields: FieldConfig[];
}
10 changes: 5 additions & 5 deletions src/app/components/form-input/form-input.component.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div class="form-group row" [formGroup]="group">
<label class="col-md-2 font-weight-bold col-form-label">{{config.label}}
<span [hidden]="!config.required">*</span>
<div class="form-group row" [formGroup]="group" *ngIf="isShow()">
<label class="col-md-2 font-weight-bold col-form-label">{{field.label}}
<span [hidden]="!field.required">*</span>
</label>
<div class="col-md-10">
<input type="text" class="form-control" [attr.placeholder]="config.placeholder" [formControlName]="config.name">
<input type="text" class="form-control" [attr.placeholder]="field.placeholder" [formControlName]="field.name">
</div>
</div>
</div>
7 changes: 6 additions & 1 deletion src/app/components/form-input/form-input.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import { FieldConfig } from '../../models/field-config.interface';
templateUrl: './form-input.component.html'
})
export class FormInputComponent implements Field {
config: FieldConfig;
field: FieldConfig;
group: FormGroup;
fields: FieldConfig[];

isShow () {
return !this.field.hidden;
}
}
8 changes: 8 additions & 0 deletions src/app/components/form-radio/form-radio.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="form-group row" [formGroup]="group" *ngIf="isShow()">
<label class="col-md-2 font-weight-bold col-form-label">{{field.label}}</label>
<div class="col-md-10">
<label *ngFor="let item of field.options">
<input type="radio" [value]="item.value" [formControlName]="field.name" (change)=onSelectionChange(item.ref)>{{item.value}}
</label>
</div>
</div>
53 changes: 53 additions & 0 deletions src/app/components/form-radio/form-radio.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Component } from "@angular/core"
import {Field} from "../../models/field.interface";
import { FormGroup } from '@angular/forms';
import { FieldConfig } from '../../models/field-config.interface';
import * as _ from 'lodash';



@Component({
selector: 'form-radio',
templateUrl: './form-radio.component.html'
})

export class FormRadioComponent implements Field{
field: FieldConfig;
group: FormGroup;
fields: FieldConfig[];

/**
* {
* radioName1: refName1,
* radioName2: refName2
* }
* @type {{}}
*/
private radioMap = {};


isShow () {
return !this.field.hidden;
}

/**
* @description change the ref component disabled status when radio button changes
* @param refName
*/
onSelectionChange(refName) {
let radioName = this.field.name;
let isDisabled = false;
if (!refName) {
refName = this.radioMap[radioName];
isDisabled = true;
}

this.fields.forEach(field => {
if (field.name === refName) {
field.hidden = isDisabled;
this.radioMap[radioName] = refName;
}
});

}
}
12 changes: 6 additions & 6 deletions src/app/components/form-select/form-select.component.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<div class="form-group row" [formGroup]="group">
<label class="col-md-2 font-weight-bold col-form-label" for="group">{{config.label}}
<span [hidden]="!config.required">*</span>
<div class="form-group row" [formGroup]="group" *ngIf="isShow()">
<label class="col-md-2 font-weight-bold col-form-label" for="group">{{field.label}}
<span [hidden]="!field.required">*</span>
</label>
<div class="col-md-10">
<select [formControlName]="config.name" class="form-control">
<option *ngFor="let option of config.options" [ngValue]="option">{{option}}</option>
<select [formControlName]="field.name" class="form-control">
<option *ngFor="let option of field.options" [ngValue]="option">{{option}}</option>
</select>
</div>
</div>
</div>
9 changes: 8 additions & 1 deletion src/app/components/form-select/form-select.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import { FieldConfig } from '../../models/field-config.interface';
templateUrl: './form-select.component.html'
})
export class FormSelectComponent implements Field {
config: FieldConfig;
field: FieldConfig;
group: FormGroup;
fields: FieldConfig[];


isShow () {
return !this.field.hidden;
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div class="form-group row" [formGroup]="group">
<label class="col-md-2 font-weight-bold col-form-label" for="group" required>{{config.label}}
<span [hidden]="!config.required">*</span>
<div class="form-group row" [formGroup]="group" *ngIf="isShow()">
<label class="col-md-2 font-weight-bold col-form-label" for="group" required>{{field.label}}
<span [hidden]="!field.required">*</span>
</label>
<div class="col-md-10 editor-container">
<quill-editor [modules]="quillToolbar" [formControlName]="config.name"></quill-editor>
<quill-editor [modules]="quillToolbar" [formControlName]="field.name"></quill-editor>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ import { FieldConfig } from '../../models/field-config.interface';
styles: [require('./form-text-editor.component.scss').toString()]
})
export class FormTextEditorComponent implements Field {
config: FieldConfig;
field: FieldConfig;
group: FormGroup;
private quillToolbar: object = {
fields: FieldConfig[];
private quillToolbar: object = {
toolbar: ['bold', 'italic', 'underline', 'strike', { 'header': 1 }, { 'header': 2 }, { 'list': 'ordered' }, { 'list': 'bullet' }, 'blockquote', 'code-block', 'link']
};
}

isShow () {
return !this.field.hidden;
}
}
10 changes: 5 additions & 5 deletions src/app/components/form-textarea/form-textarea.component.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div class="form-group row" [formGroup]="group">
<label class="col-md-2 font-weight-bold col-form-label">{{config.label}}
<span [hidden]="!config.required">*</span>
<div class="form-group row" [formGroup]="group" *ngIf="isShow()">
<label class="col-md-2 font-weight-bold col-form-label">{{field.label}}
<span [hidden]="!field.required">*</span>
</label>
<div class="col-md-10">
<textarea class="form-control" rows="3" [attr.placeholder]="config.placeholder" [formControlName]="config.name"></textarea>
<textarea class="form-control" rows="3" [attr.placeholder]="config.placeholder" [formControlName]="field.name"></textarea>
</div>
</div>
</div>
7 changes: 6 additions & 1 deletion src/app/components/form-textarea/form-textarea.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import { FieldConfig } from '../../models/field-config.interface';
templateUrl: './form-textarea.component.html'
})
export class FormTextareaComponent implements Field {
config: FieldConfig;
field: FieldConfig;
group: FormGroup;
fields: FieldConfig[];

isShow () {
return !this.field.hidden;
}
}
Loading

0 comments on commit c5f3355

Please sign in to comment.