Selaa lähdekoodia

Adding optional links to text and select fields

Richard Knight 6 vuotta sitten
vanhempi
commit
22cc91c482

+ 27 - 0
src/app/_mock/testfields.v10.ts

@@ -0,0 +1,27 @@
+// TESTS: Labelling Containers, hidden fields, and fields with links
+
+const model = {
+	aSubGroup: {
+		modelOnlyField: 55
+	}
+};
+
+const meta = {
+	aSubGroup: {
+		label: 'This is a relabelled subgroup',
+		meta: {
+			aField: { type: 'radio', options: ['Yes', 'No', 'Maybe'], horizontal: 1 },
+			anotherSubGroup: {
+				label: 'Another label override',
+				meta: {
+					isWorking: { type: 'radio', 'label': 'Does it work yet?' },
+					hiddenField: { type: 'hidden', value: 'BOO!' },
+					fieldWithLink: { link: { route: 'simple' } },
+					selectWithLink: { type: 'select', options: ['1', '2', '3', '4', '5'], link: { route: 'simple' } },
+				}
+			}
+		}
+	}
+};
+
+export { model, meta };

+ 1 - 1
src/app/app.component.html

@@ -4,7 +4,7 @@
 			<h1>NgDynaform</h1>
 			<p>
 			Dynamic Form Layout Module<br>
-			Load different tests by appending a query param to the URL <b>?test=N</b> (where N is a number between 1 and 9).<br>
+			Load different tests by appending a query param to the URL <b>?test=N</b> (where N is a number between 1 and 10).<br>
 			NOTE: Model set to update on change, but this can be set to blur or submit for less re-rendering.
 			</p>
 		</div>

+ 3 - 2
src/app/app.component.ts

@@ -11,10 +11,11 @@ import * as test6 from './_mock/testfields.v6';
 import * as test7 from './_mock/testfields.v7';
 import * as test8 from './_mock/testfields.v8';
 import * as test9 from './_mock/testfields.v9';
+import * as test10 from './_mock/testfields.v10';
 
-const testdata = [ test1, test2, test3, test4, test5, test6, test7, test8, test9 ];
+const testdata = [ test1, test2, test3, test4, test5, test6, test7, test8, test9, test10 ];
 
-const defatltTest = 8;
+const defatltTest = 10;
 
 @Component({
 	selector: 'app-root',

+ 3 - 0
src/app/app.module.ts

@@ -2,6 +2,8 @@ import { NgModule } from '@angular/core';
 import { BrowserModule } from '@angular/platform-browser';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterModule } from '@angular/router';
+
 import { DynaformModule } from './dynaform/dynaform.module';
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
 import { AppComponent } from './app.component';
@@ -13,6 +15,7 @@ import { JsonFormatterDirective } from './directives/json-formatter.directive';
 		BrowserAnimationsModule,
 		FormsModule,
 		ReactiveFormsModule,
+		RouterModule.forRoot([]),
 		DynaformModule,
 		NgbModule.forRoot()
 	],

+ 13 - 1
src/app/dynaform/components/native/select/select.component.html

@@ -1,3 +1,15 @@
-<select [formControl]="control" class="custom-select custom-select-sm">
+<select *ngIf="!link; else fieldWithLink" [formControl]="control" class="custom-select custom-select-sm">
 	<option *ngFor="let opt of options" [value]="opt.value">{{ opt.label }}</option>
 </select>
+
+<ng-template #fieldWithLink>
+	<div class="input-group input-group-sm">
+		<select [formControl]="control" #field class="custom-select custom-select-sm">
+			<option *ngFor="let opt of options" [value]="opt.value">{{ opt.label }}</option>
+		</select>
+		<div class="input-group-append">
+			<button class="btn btn-outline-primary" type="button"
+				[routerLink]="[ link.route, field.value ]">{{ link.label || 'Details' }}</button>
+		</div>
+	</div>
+</ng-template>

+ 1 - 1
src/app/dynaform/components/native/select/select.component.ts

@@ -8,6 +8,6 @@ import { NativeInputComponent } from '../../_abstract/native-input.component';
 })
 export class SelectComponent extends NativeInputComponent {
 
-	exposeMetaInTemplate: string[] = ['options'];
+	exposeMetaInTemplate: string[] = ['options', 'link'];
 
 }

+ 17 - 1
src/app/dynaform/components/native/text/text.component.html

@@ -1,5 +1,21 @@
-<input type="text"
+<input *ngIf="!link; else fieldWithLink"
+	type="text"
 	[formControl]="control"
 	[placeholder]="placeholder"
 	class="form-control form-control-sm"
 >
+
+<ng-template #fieldWithLink>
+	<div class="input-group input-group-sm">
+		<input type="text"
+			#field
+			[formControl]="control"
+			[placeholder]="placeholder"
+			class="form-control form-control-sm"
+		>
+		<div class="input-group-append">
+			<button class="btn btn-outline-primary" type="button"
+				[routerLink]="[ link.route, field.value ]">{{ link.label || 'Details' }}</button>
+		</div>
+	</div>
+</ng-template>

+ 1 - 1
src/app/dynaform/components/native/text/text.component.ts

@@ -8,6 +8,6 @@ import { NativeInputComponent } from '../../_abstract/native-input.component';
 })
 export class TextComponent extends NativeInputComponent {
 
-	exposeMetaInTemplate: string[] = ['placeholder'];
+	exposeMetaInTemplate: string[] = ['placeholder', 'link'];
 
 }

+ 21 - 20
src/app/dynaform/dynaform.component.html

@@ -6,26 +6,28 @@
 <!-- Default template for form field
      used when a TemplateRef is NOT supplied to component -->
 <ng-template #default let-control="control" let-meta="meta">
-	
-	<div class="form-group row" *ngIf="meta.type !== 'Container'; else recursiveDynaform" [ngClass]="getRowClass(control, meta.type)">
-		<label class="col-sm-4" [for]="meta.name" title="">
-			{{ meta.label }}
-			<span *ngIf="control && control.touched && control.invalid" class="fas fa-exclamation-triangle"
-				[ngbTooltip]="getValidationFailureMessage(control, meta)"
-			></span>
-		</label>
-		<div class="col-sm-8">
-			<ng-container dynafield [control]="control" [meta]="meta" (call)="handleCallback($event)"></ng-container>
-		</div>
-	</div>
-	
-	<ng-template #recursiveDynaform>
-		<div class="row pt-3">
-			<h3 class="col-sm-12" [ngClass]="'h-dyna-' + (path.length + 2)">{{ meta.label }}</h3>
-		</div>
-		<app-dynaform [formGroup]="control" [meta]="meta.meta" [template]="template" (call)="handleCallback($event)"></app-dynaform>
-	</ng-template>
+	<ng-container *ngIf="meta.type !== 'Hidden'">
 
+		<div class="form-group row" *ngIf="meta.type !== 'Container'; else recursiveDynaform" [ngClass]="getRowClass(control, meta.type)">
+				<label class="col-sm-4" [for]="meta.name" title="">
+					{{ meta.label }}
+					<span *ngIf="control && control.touched && control.invalid" class="fas fa-exclamation-triangle"
+						[ngbTooltip]="getValidationFailureMessage(control, meta)"
+					></span>
+				</label>
+				<div class="col-sm-8">
+					<ng-container dynafield [control]="control" [meta]="meta" (call)="handleCallback($event)"></ng-container>
+				</div>
+			</div>
+			
+			<ng-template #recursiveDynaform>
+				<div class="row pt-3">
+					<h3 class="col-sm-12" [ngClass]="'h-dyna-' + (path.length + 2)">{{ meta.label }}</h3>
+				</div>
+				<app-dynaform [formGroup]="control" [meta]="meta.meta" [template]="template" (call)="handleCallback($event)"></app-dynaform>
+			</ng-template>
+		
+	</ng-container>
 </ng-template>
 
 
@@ -39,4 +41,3 @@
 		class="alert mt-4"
 		role="alert">{{ formGroup.pristine ? 'Untouched' : getValidationErrors() | json }}</pre>
 </div>
-

+ 2 - 0
src/app/dynaform/dynaform.module.ts

@@ -1,6 +1,7 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterModule } from '@angular/router';
 
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
 
@@ -19,6 +20,7 @@ import { DateInputsModule } from '@progress/kendo-angular-dateinputs';
 		CommonModule,
 		FormsModule,
 		ReactiveFormsModule,
+		RouterModule.forChild([]),
 		NgbModule,
 		DateInputsModule
 	],

+ 16 - 2
src/app/dynaform/models/field.model.ts

@@ -32,8 +32,15 @@ interface Option {
 
 interface OptionsFieldMetaData extends SimpleFieldMetaData {
 	options;									// Array of Options - for select, radio-button-group and other 'multiple-choice' types
-	horizontal?;								// Whether to arrang radio buttons or checkboxes horizontally (default false)
+	horizontal?: boolean;						// Whether to arrang radio buttons or checkboxes horizontally (default false)
 }
+
+// For components that include links to other pages
+interface Link {
+	label: string;
+	route: any[] | string;
+}
+
 interface DropdownModifiedInputFieldMetaData extends SimpleFieldMetaData {
 	modifiers: string[];
 	transform: ValueTransformer;
@@ -124,6 +131,8 @@ abstract class OptionsField extends SimpleField {
 
 class TextField extends SimpleField {
 	type = 'Text';
+	link?: Link;
+	
 }
 
 class TextareaField extends SimpleField {
@@ -136,12 +145,17 @@ class PasswordField extends SimpleField {
 
 class SelectField extends OptionsField {
 	type = 'Select';
+	link?: Link;
 }
 
 class RadioField extends OptionsField {
 	type = 'Radio';
 }
 
+class HiddenField extends SimpleField {
+	type = 'Hidden';
+}
+
 // ---------------------------------------------------------------------------------------------------------------------
 // Concrete Implementations - Custom Form Components
 
@@ -261,7 +275,7 @@ class ButtonGroup {
 
 export {
 	SimpleField,
-	TextField, TextareaField, PasswordField, SelectField, RadioField,
+	TextField, TextareaField, PasswordField, SelectField, RadioField, HiddenField,
 	CheckbuttonField, DropdownModifiedInputField,
 	CheckbuttonGroup,
 	TimepickerField, DatepickerField,