Angora Form
Angora Forms is a custom form component abstraction library designed for Angular that streamlines and simplifies the process of creating custom form components in Angular.
Custom form components in Angular comes with a bit of boilerplate code and Angora Forms components abstracts away 90.9% of that boilerplate code.
See [our website] or below for example code comparison.
Documentation
The official documentation website is [website address].
Angora Forms [version number] was released on [date]. You can find more details on [version changes address]
Key Features
- Ease of Use: Getting started with Angora Forms is simple. Visit our documentations for a quick start up guide.
- Static Typing: Custom components created with our abstraction library accomodate for TypeScript to adhere to the philosophy of the Angular framework and improve overall deveoper experience.
- Customizable Components: Angora Forms does not come with component styling. Developers are free to style any components to their own tastes.
- Maintainability: Custom components are aggregated in a single location with minimal boilerplate code normally required by the Angular framework, aiding maintainability and improving reviewability.
Getting Started
-
Install Node.js.
-
Install Angora Forms npm library link.
npm install angora-forms
- Configure webpack.config.ts:
const path = require("path");
const customComponents = require('./src/app/customComponents.ts')
module.exports = {
mode: "development",
entry: ["./src/app/app.module.ts"],
output: {},
devtool: false,
module: {
rules: [
{
test: /\.ts$/,
use: [
{
loader: "@angoraforms/angora-loader",
options: {
customComponents: customComponents
}
},
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
};
- Create Custom Component File:
class customComponent1 {
template = '/* html template */'
onChange = (value: any) => {};
onTouched = () => {};
value: any = 0;
disabled = false
}
Each custom component class will require a template, onChange, onTouched, value and disabled property.
- Insert html into value of template within backticks.
Example:
template = `
<h1>{{value}}</h1>
<button (click)='increment()'>Increment</button>
<button (click)='decrement()'>Decrement</button>
`;
-
Customise value and/or disabled if/as required.
-
Add custom methods to component if/as required. Example:
increment() {
this.value++;
this.onChange(this.value);
this.onTouched();
}
decrement() {
this.value--;
this.onChange(this.value);
this.onTouched();
}
- Additional custom components are added following the first custom component class.
Example:
class customComponent1 {
template = `
<h1>{{value}}</h1>
<button (click)='increment()'>Increment</button>
<button (click)='decrement()'>Decrement</button>
`;
onChange = (value: any) => {};
onTouched = () => {};
value = 0;
disabled = false
increment() {
this.value++;
this.onChange(this.value);
this.onTouched();
}
decrement() {
this.value--;
this.onChange(this.value);
this.onTouched();
}
}
class customComponent2 {
template = `
<input type="file" class="file-input" (change)="onFileSelected($event)" #fileUpload>
<div>
<input class="form-control" [disabled]="true" [value]="value">
<button class="btn btn-primary" (click)="onClick(fileUpload)" [disabled]="disabled">Attach File</button>
</div>
`;
onChange = (value: any) => {};
onTouched = () => {};
value = '';
disabled = false;
onFileSelected(event: any) {
const file = event.target.files[0];
if (file) {
this.value = file.name;
console.log(this.value);
this.onChange(this.value);
}
}
onClick(fileUpload: any) {
this.onTouched();
fileUpload.click();
}
}
- Export custom component classes within an array.
Example:
module.exports = [customComponent1, customComponent2]
- Run
npx webpack
in terminal before runningng serve
.
Custom component files will be generated and required modifications to the app.modules file will be made.
Example Comparison
Without Angora Forms:
customComponent1.ts
import { Component } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'custom-comp1',
template: `
<h1>{{value}}</h1>
<button (click)='increment()'>Increment</button>
<button (click)='decrement()'>Decrement</button>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: customComp1
}
]
})
export class customComp1 implements ControlValueAccessor {
onChange = (value: any) => { }
onTouched = () => { }
value = 0
disabled = false
increment() {
this.value++;
this.onChange(this.value);
this.onTouched();
}
decrement() {
this.value--;
this.onChange(this.value);
this.onTouched();
}
writeValue(value: any) {
this.value = value
}
registerOnChange(onChange: any) {
this.onChange = onChange
}
registerOnTouched(onTouched: any){
this.onTouched = onTouched
}
setDisabledState(disabled: boolean): void {
this.disabled = disabled
}
}
customComponent2.ts
import { Component } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'custom-comp2',
template: `
<input type="file" class="file-input" (change)="onFileSelected($event)" #fileUpload>
<div>
<input class="form-control" [disabled]="true" [value]="value">
<button class="btn btn-primary" (click)="onClick(fileUpload)" [disabled]="disabled">Attach File</button>
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: customComp2
}
]
})
export class customComp2 implements ControlValueAccessor {
onChange = (value: any) => { }
onTouched = () => { }
value = ''
disabled = false
onFileSelected(event: any) {
const file = event.target.files[0];
if (file) {
this.value = file.name;
console.log(this.value);
this.onChange(this.value);
}
}
onClick(fileUpload: any) {
this.onTouched();
fileUpload.click();
}
writeValue(value: any) {
this.value = value
}
registerOnChange(onChange: any) {
this.onChange = onChange
}
registerOnTouched(onTouched: any){
this.onTouched = onTouched
}
setDisabledState(disabled: boolean): void {
this.disabled = disabled
}
}
With Angora Forms:
class customComp1 {
template = `
<h1>{{value}}</h1>
<button (click)='increment()'>Increment</button>
<button (click)='decrement()'>Decrement</button>
`;
onChange = (value: any) => {};
onTouched = () => {};
value = 0;
disabled = false
increment() {
this.value++;
this.onChange(this.value);
this.onTouched();
}
decrement() {
this.value--;
this.onChange(this.value);
this.onTouched();
}
}
class customComp2 {
template = `
<input type="file" class="file-input" (change)="onFileSelected($event)" #fileUpload>
<div>
<input class="form-control" [disabled]="true" [value]="value">
<button class="btn btn-primary" (click)="onClick(fileUpload)" [disabled]="disabled">Attach File</button>
</div>
`;
onChange = (value: any) => {};
onTouched = () => {};
value = '';
disabled = false;
onFileSelected(event: any) {
const file = event.target.files[0];
if (file) {
this.value = file.name;
console.log(this.value);
this.onChange(this.value);
}
}
onClick(fileUpload: any) {
this.onTouched();
fileUpload.click();
}
}
module.exports = [customComp1, customComp2]
Other Information
AngoraForms is in beta and will be updated in the future. You should also take a look at our [website](link to website) and its github repo web application!
Contributors
- Aaron Chen - Github
- Ryan Hastings - Github
- Wayne Leung - Github
- Curtis Lovrak - Github
- Hadar Weinstein - Github
License
This project is licensed under the MIT License.