我的同事(賈斯汀)幫助我如何從動態HTML訪問表單值。 @Hagner(http://plnkr.co/edit/DeYGuZSOYvxT76YI8SRU?p=preview)答案是你可以做的一種方法。這涉及到服務。下面的方法不涉及服務,是更直接的方式來訪問值。我想我會爲這些場景發佈帖子。
-- app/app.component.ts
import {
AfterContentInit, AfterViewInit, AfterViewChecked, OnInit, Compiler, Component, NgModule, ViewChild,
ViewContainerRef, forwardRef, Injectable, ChangeDetectorRef
} from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ReactiveFormsModule, FormGroup, FormControl, FormsModule, FormArray, FormBuilder, Validators } from '@angular/forms';
import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
@Injectable()
export class DynamicControlClass {
constructor(public Key: string,
public Validator: boolean,
public minLength: number,
public maxLength: number,
public defaultValue: string,
public requiredErrorString: string,
public minLengthString: string,
public maxLengthString: string,
public ControlType: string
) { }
}
@Component({
selector: 'my-app',
template: `
<h1>Dynamic template:</h1>
<div class="container">
<form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate>
<div class="form-row">
<label for="">First Name</label>
<input type="text" class="form-control" formControlName="firstname" required>
<div *ngIf="formErrors.firstname" class="alert alert-danger">
{{ formErrors.firstname }}
</div>
</div>
<div class="form-row">
<label for="">Last Name</label>
<input type="text" class="form-control" formControlName="lastname" required>
<div *ngIf="formErrors.lastname" class="alert alert-danger">
{{ formErrors.lastname }}
</div>
</div>
<div #container></div>
<!--
<div class="form-row">
<input type="radio" formControlName="Medical_Flu_Concent_Decline_medical_flu_concent_decline_rule1" value="1"> <b>Concent Template </b>
<br>
<input type="radio" formControlName="Medical_Flu_Concent_Decline_medical_flu_concent_decline_rule1" value="2"> <b>Decline Template</b>
</div>
-->
<br>
<!--
<button type="submit" class="btn btn-default"
[disabled]="!myForm.valid">Submit</button>
-->
<button type="submit" class="btn btn-default" >Submit</button>
<div *ngIf="payLoad" class="form-row">
<strong>Saved the following values</strong><br>{{payLoad}}
</div>
<div> Is Form Valid : {{myForm.valid}}</div>
</form>
</div>
`
,
styles: ['h1 {color: #369;font-family: Arial, Helvetica, sans-serif;font-size: 250%;} input[required]:valid {border-left: 5px solid #42A948; /* green */ } input[required]:invalid {border-left: 5px solid #a94442; /* red */ } .radioValidation input:invalid{outline: 2px solid #a94442;} .radioValidation input:valid{outline: 2px solid #42A948;}'],
})
export class AppComponent implements AfterContentInit {
@ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
public myForm: FormGroup; // our model driven form
public payLoad: string;
public controlData: [string, boolean, number];
public ctlClass: DynamicControlClass[];
public formErrors: any = {};
public group: any = {};
public submitted: boolean = false;
public setValidatorValue: boolean = false;
public onSubmit() {
this.submitted = true;
this.setValidatorValue = false;
this.onValueChanged();
if (this.myForm.valid) {
const form = this.myForm
const control = form.get('Medical_Flu_Concent_Decline_medical_flu_concent_decline');
if (control) {
if (control.value === '1') {
const controlreset = form.get('Medical_Flu_Decline_Details_medical_flu_decline_details');
if ((controlreset) && (controlreset.value)) {
this.myForm.patchValue({ Medical_Flu_Decline_Details_medical_flu_decline_details: null });
}
}
}
this.payLoad = JSON.stringify(this.myForm.value);
}
}
constructor(private compiler: Compiler, private formBuilder: FormBuilder, private sanitizer: DomSanitizer) {
this.ctlClass = [
new DynamicControlClass('firstname', true, 5, 0, '', 'Please enter First Name', 'First Name must be Minimum of 5 Characters', '', 'textbox'),
new DynamicControlClass('lastname', true, 5, 0, '', 'Please enter LastName', 'Last Name must be Minimum of 5 Characters', '', 'textbox'),
new DynamicControlClass('address', true, 5, 0, 'Default Address', 'Please enter Address', 'Address must be Minimum of 5 Characters', '', 'textbox'),
new DynamicControlClass('Medical_Flu_Concent_Decline_medical_flu_concent_decline', true, 0, 0, null, 'Please Select one of the Radio option', '', '', 'radio'),
new DynamicControlClass('Medical_Flu_Decline_Details_medical_flu_decline_details', false, 0, 0, null, 'Please Select one of the Decline option', '', '', 'radio'),
new DynamicControlClass('city', true, 5, 0, 'Enter City', 'Please enter City', 'City must be Minimum of 5 Characters', '', 'textbox')]
};
ngAfterContentInit() {
this.ctlClass.forEach(dyclass => {
let minValue: number = dyclass.minLength;
let maxValue: number = dyclass.maxLength;
if (dyclass.Validator) {
this.formErrors[dyclass.Key] = '';
if ((dyclass.ControlType === 'radio') || (dyclass.ControlType === 'checkbox')) {
this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || null, [Validators.required]);
}
else {
if ((minValue > 0) && (maxValue > 0)) {
this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '', [Validators.required, <any>Validators.minLength(minValue), <any>Validators.maxLength(maxValue)]);
}
else if ((minValue > 0) && (maxValue === 0)) {
this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '', [Validators.required, <any>Validators.minLength(minValue)]);
}
else if ((minValue === 0) && (maxValue > 0)) {
this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '', [Validators.required, <any>Validators.maxLength(maxValue)]);
}
else if ((minValue === 0) && (maxValue === 0)) {
this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '', [Validators.required]);
}
}
}
else {
if (dyclass.Key === 'Medical_Flu_Decline_Details_medical_flu_decline_details') {
this.formErrors[dyclass.Key] = 'null';
this.group[dyclass.Key] = new FormControl(dyclass.defaultValue);
}
else {
this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '');
}
}
});
this.myForm = new FormGroup(this.group);
this.myForm.valueChanges.subscribe(data => this.onValueChanged(data));
this.onValueChanged(); // (re)set validation messages now
this.addComponent('<div [formGroup]="_parent.myForm" class="form-row"> <label for="">Address</label> <input type="text" class="form-control" formControlName="address" required> <div *ngIf="_parent.formErrors.address" class="alert alert-danger">{{ _parent.formErrors.address }}</div><\div><div [formGroup]="_parent.myForm" class="form-row"> <label for="">City</label> <input type="text" class="form-control" formControlName="city" required> <div *ngIf="_parent.formErrors.city" class="alert alert-danger">{{ _parent.formErrors.city }}</div><\div><div [formGroup]="_parent.myForm" class="form-row radioValidation" > <input type="radio" formControlName="Medical_Flu_Concent_Decline_medical_flu_concent_decline" id="Medical_Flu_Concent_Decline_medical_flu_concent_decline_1" name="Medical_Flu_Concent_Decline_medical_flu_concent_decline" value="1" required> <b>CONSENT.</b><br><br> Here is my Consent. <br><br><input type="radio" formControlName="Medical_Flu_Concent_Decline_medical_flu_concent_decline" name="Medical_Flu_Concent_Decline_medical_flu_concent_decline" id="Medical_Flu_Concent_Decline_medical_flu_concent_decline_2" value="2" required> <b>DECLINE. </b><br/> I am choosing to decline for the following reason: <br><br> <div *ngIf="_parent.formErrors.Medical_Flu_Concent_Decline_medical_flu_concent_decline" class="alert alert-danger">{{ _parent.formErrors.Medical_Flu_Concent_Decline_medical_flu_concent_decline }}</div></div><div [formGroup]="_parent.myForm" class="form-row"> <input type="radio" formControlName="Medical_Flu_Decline_Details_medical_flu_decline_details" id="Medical_Flu_Decline_Details_medical_flu_decline_details_1" name="Medical_Flu_Decline_Details_medical_flu_decline_details" value="1" > I am not interested<br><br><input type="radio" formControlName="Medical_Flu_Decline_Details_medical_flu_decline_details" id="Medical_Flu_Decline_Details_medical_flu_decline_details_2" name="Medical_Flu_Decline_Details_medical_flu_decline_details" value="2" > I have already received <br><br><input type="radio" formControlName="Medical_Flu_Decline_Details_medical_flu_decline_details" id="Medical_Flu_Decline_Details_medical_flu_decline_details_3" name="Medical_Flu_Decline_Details_medical_flu_decline_details" value="3" > I am declining for other reasons<br><br><div *ngIf="_parent.formErrors.Medical_Flu_Decline_Details_medical_flu_decline_details" class="alert alert-danger">{{ _parent.formErrors.Medical_Flu_Decline_Details_medical_flu_decline_details }}</div></div>');
}
public onValueChanged(data?: any) {
if (!this.myForm) { return; }
const form = this.myForm;
for (const field in this.formErrors) {
// clear previous error message (if any)
this.formErrors[field] = '';
const control = form.get(field);
if (field === 'Medical_Flu_Decline_Details_medical_flu_decline_details') {
if ((this.myForm.value['Medical_Flu_Concent_Decline_medical_flu_concent_decline']) && (this.myForm.value['Medical_Flu_Concent_Decline_medical_flu_concent_decline'] === "2")) {
control.setValidators(Validators.required);
control.updateValueAndValidity({ onlySelf: false, emitEvent: false })
}
else if ((this.myForm.value['Medical_Flu_Concent_Decline_medical_flu_concent_decline']) && (this.myForm.value['Medical_Flu_Concent_Decline_medical_flu_concent_decline'] === "1")) {
control.setValidators(null);
control.updateValueAndValidity({ onlySelf: false, emitEvent: false })
const controlreset = form.get('Medical_Flu_Decline_Details_medical_flu_decline_details');
if ((controlreset) && (controlreset.value)) {
this.myForm.patchValue({ Medical_Flu_Decline_Details_medical_flu_decline_details: null });
}
}
}
if ((control && control.dirty && !control.valid) || (this.submitted)) {
let objClass: any;
this.ctlClass.forEach(dyclass => {
if (dyclass.Key === field) {
objClass = dyclass;
}
});
for (const key in control.errors) {
if (key === 'required') {
this.formErrors[field] += objClass.requiredErrorString + ' ';
}
else if (key === 'minlength') {
this.formErrors[field] += objClass.minLengthString + ' ';
}
else if (key === 'maxLengthString') {
this.formErrors[field] += objClass.minLengthString + ' ';
}
}
}
}
}
private addComponent(template: string) {
@Component({
template: template,
styles: ['h1 {color: #369;font-family: Arial, Helvetica, sans-serif;font-size: 250%;} input[required]:valid {border-left: 5px solid #42A948; /* green */ } input[required]:invalid {border-left: 5px solid #a94442; /* red */ } .radioValidation input:invalid{outline: 2px solid #a94442;} .radioValidation input:valid{outline: 2px solid #42A948;}'],
// alternatively: [{provide: TemplateContainer, useExisting: forwardRef(() => AppComponent)}]
})
class TemplateComponent {
constructor(public _parent: AppComponent) {
console.log("parent component", this._parent);
}
}
@NgModule({ imports: [ReactiveFormsModule, FormsModule, BrowserModule], declarations: [TemplateComponent] })
class TemplateModule { }
const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
const factory = mod.componentFactories.find((comp) =>
comp.componentType === TemplateComponent
);
const component = this.container.createComponent(factory);
}
}
-- app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { COMPILER_PROVIDERS } from '@angular/compiler';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, ReactiveFormsModule],
declarations: [AppComponent],
bootstrap: [ AppComponent ]
})
export class AppModule { }
-- app/main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
-- config.js
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
paths: {
'npm:': 'https://unpkg.com/'
},
//map tells the System loader where to look for things
map: {
'app': 'app',
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
// angular testing umd bundles
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
'@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'lodash': 'npm:lodash/lodash.min.js',
'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
'ts': 'npm:plugin-typescript/lib/plugin.js',
'typescript': 'npm:typescript/lib/typescript.js',
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
}
}
});
-- index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css">
<script src="https://unpkg.com/[email protected]/dist/zone.js"></script>
<script src="https://unpkg.com/[email protected]/Reflect.js"></script>
<script src="https://unpkg.com/[email protected]/dist/system.js"></script>
<script src="https://unpkg.com/[email protected]/lib/typescript.js"></script>
<script src="config.js"></script>
<script src="config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>
http://plnkr.co/edit/rELaWPJ2cDJyCB55deTF?p=preview
完全學分制賈斯汀幫了我。
如果你想使用AOT,你需要做什麼 從'@ angular/compiler'導入{JitCompilerFactory};編譯器=新的JitCompilerFactory([{useDebug:false, useJit:true}])。createCompiler(); 在需要的地方創建編譯器@。從構造函數中移除編譯器。 這將與AOT一起使用。 更新了plnkr以使用AOT編譯 http://plnkr.co/edit/2qAWGh?p=preview –