diff --git a/docs/forms.md b/docs/forms.md index e69de29..aa1cc09 100644 --- a/docs/forms.md +++ b/docs/forms.md @@ -0,0 +1,252 @@ +# Forms + +Angular offers two different approach to retrieving data from a from. +- Template-driven (predefined) +- Reactive (Manual setup but flexible) + +## Template driven +### Creating the Form and registering the controls + +Import the Form module in the `app.module.ts`. + +```ts +import { FormsModule } from '@angular/forms'; + +@NgModules({ + imports: [ FormsModule ] +}) +``` + +Register the imput with the `ngModel` directive. + +overview + +### Submitting and using the Form + +app.component.html +```html +
+``` + +app.component.ts +```ts +onSubmit(form: ngForm) { + console.log(form); +} +``` +overview + +#### @ViewChild + +Here we can retrive the data also without submitting the form + +```ts +import { ViewChild } from '@angular/core'; + +export class AppComponent { + @ViewChild('f') signupForm: ngForm; + + onSubmit() { + console.log(this.signupForm); +} + +``` + +### FormValidation + +By adding an attribute like `required`, `email` to the html form. Angular detects as a directive and validates it automatically. + +[Angular Validators](https://angular.io/api/forms/Validators) + +#### Using the Form state + +```html + +``` + +The `f` referes to the local reference declaredy§ in the form. + +Visually can be showen that a input is invalid by adding this CSS definition. + +```css +input.ng-invalid.ng-touched { + border: 1px solid red; +} +``` + +It shows only a red boder when the input field has been modified. + +Showing some hint text +```html + + + Please enter a valid email! +``` + +`setValue` and `patchValue` helps to preset the form with predefined values. With `setValue` overrides the whole form, and `patchValue` updates only a specific inputfield. `patchValue` is aviable only from the `form` (`signupForm.form.patchValue({userData: { username: 'bliblubla'}});`). + +## Reactive driven + +Import the Form module in the `app.module.ts`. + +```ts +import { ReactiveFormsModule } from '@angular/forms'; + +@NgModules({ + imports: [ ReactiveFormsModule ] +}) +``` + +app.component.html +```html +
+
+
+ +
+
+ + + + This name is invalid! + This field is required! + + +
+
+ + + Please enter a valid email! +
+
+
+ +
+
+

Your Hobbies

+ +
+ +
+
+ Please enter valid data! + + +
+
+
+``` + +app.component.ts +```ts +import { Component, OnInit } from '@angular/core'; +import { FormArray, FormControl, FormGroup, Validators } from '@angular/forms'; +import { Observable } from 'rxjs/Observable'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent implements OnInit { + genders = ['male', 'female']; + signupForm: FormGroup; + forbiddenUsernames = ['Chris', 'Anna']; + + constructor() {} + + ngOnInit() { + this.signupForm = new FormGroup({ + 'userData': new FormGroup({ + 'username': new FormControl(null, [Validators.required, this.forbiddenNames.bind(this)]), + 'email': new FormControl(null, [Validators.required, Validators.email], this.forbiddenEmails) + }), + 'gender': new FormControl('male'), + 'hobbies': new FormArray([]) + }); + // this.signupForm.valueChanges.subscribe( + // (value) => console.log(value) + // ); + this.signupForm.statusChanges.subscribe( + (status) => console.log(status) + ); + this.signupForm.setValue({ + 'userData': { + 'username': 'Max', + 'email': 'max@test.com' + }, + 'gender': 'male', + 'hobbies': [] + }); + this.signupForm.patchValue({ + 'userData': { + 'username': 'Anna', + } + }); + } + + onSubmit() { + console.log(this.signupForm); + this.signupForm.reset(); + } + + onAddHobby() { + const control = new FormControl(null, Validators.required); + (this.signupForm.get('hobbies')).push(control); + } + + forbiddenNames(control: FormControl): {[s: string]: boolean} { + if (this.forbiddenUsernames.indexOf(control.value) !== -1) { + return {'nameIsForbidden': true}; + } + return null; + } + + forbiddenEmails(control: FormControl): Promise | Observable { + const promise = new Promise((resolve, reject) => { + setTimeout(() => { + if (control.value === 'test@test.com') { + resolve({'emailIsForbidden': true}); + } else { + resolve(null); + } + }, 1500); + }); + return promise; + } +} +``` \ No newline at end of file diff --git a/img/form_ngModel.png b/img/form_ngModel.png new file mode 100644 index 0000000..268850f Binary files /dev/null and b/img/form_ngModel.png differ diff --git a/img/ngForm_json.png b/img/ngForm_json.png new file mode 100644 index 0000000..5a2c1a6 Binary files /dev/null and b/img/ngForm_json.png differ