Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add forms overview guide #25663

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions aio/content/examples/forms-overview/e2e/src/app.e2e-spec.ts
@@ -0,0 +1,10 @@
import { browser, element, by } from 'protractor';

describe('Forms Overview Tests', function () {

beforeEach(function () {
browser.get('');
});

});

Empty file.
Empty file.
10 changes: 10 additions & 0 deletions aio/content/examples/forms-overview/src/app/app.component.html
@@ -0,0 +1,10 @@
<!--The content below is only a placeholder and can be replaced.-->
<h1>Forms Overview</h1>

<h2>Reactive</h2>

<app-reactive-favorite-color></app-reactive-favorite-color>

<h2>Template-Driven</h2>

<app-template-favorite-color></app-template-favorite-color>
31 changes: 31 additions & 0 deletions aio/content/examples/forms-overview/src/app/app.component.spec.ts
@@ -0,0 +1,31 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { TemplateModule } from './template/template.module';
import { ReactiveModule } from './reactive/reactive.module';

describe('AppComponent', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ReactiveModule, TemplateModule],
declarations: [
AppComponent
],
}).compileComponents();
}));

it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;

expect(app).toBeTruthy();
}));

it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();

const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Forms Overview');
}));
});
10 changes: 10 additions & 0 deletions aio/content/examples/forms-overview/src/app/app.component.ts
@@ -0,0 +1,10 @@
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'forms-intro';
}
20 changes: 20 additions & 0 deletions aio/content/examples/forms-overview/src/app/app.module.ts
@@ -0,0 +1,20 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ReactiveModule } from './reactive/reactive.module';
import { TemplateModule } from './template/template.module';

@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
ReactiveModule,
TemplateModule
],
providers: [],
brandonroberts marked this conversation as resolved.
Show resolved Hide resolved
bootstrap: [AppComponent]
})
export class AppModule { }
@@ -0,0 +1,50 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';

import { FavoriteColorComponent } from './favorite-color.component';
import { createNewEvent } from '../../shared/utils';

describe('Favorite Color Component', () => {
let component: FavoriteColorComponent;
let fixture: ComponentFixture<FavoriteColorComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ ReactiveFormsModule ],
declarations: [ FavoriteColorComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(FavoriteColorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

// #docregion view-to-model
it('should update the value of the input field', () => {
const input = fixture.nativeElement.querySelector('input');
const event = createNewEvent('input');

input.value = 'Red';
input.dispatchEvent(event);

expect(fixture.componentInstance.favoriteColorControl.value).toEqual('Red');
});
// #enddocregion view-to-model

// #docregion model-to-view
it('should update the value in the control', () => {
component.favoriteColorControl.setValue('Blue');

const input = fixture.nativeElement.querySelector('input');

expect(input.value).toBe('Blue');
});
// #enddocregion model-to-view
});
@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
selector: 'app-reactive-favorite-color',
template: `
Favorite Color: <input type="text" [formControl]="favoriteColorControl">
`,
styles: []
brandonroberts marked this conversation as resolved.
Show resolved Hide resolved
})
export class FavoriteColorComponent {
favoriteColorControl = new FormControl('');
}
@@ -0,0 +1,13 @@
import { ReactiveModule } from './reactive.module';

describe('ReactiveModule', () => {
let reactiveModule: ReactiveModule;

beforeEach(() => {
reactiveModule = new ReactiveModule();
});

it('should create an instance', () => {
expect(reactiveModule).toBeTruthy();
});
});
@@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { FavoriteColorComponent } from './favorite-color/favorite-color.component';

@NgModule({
imports: [
CommonModule,
ReactiveFormsModule
],
declarations: [FavoriteColorComponent],
exports: [FavoriteColorComponent],
})
export class ReactiveModule { }
5 changes: 5 additions & 0 deletions aio/content/examples/forms-overview/src/app/shared/utils.ts
@@ -0,0 +1,5 @@
export function createNewEvent(eventName: string, bubbles = false, cancelable = false) {
let evt = document.createEvent('CustomEvent');
evt.initCustomEvent(eventName, bubbles, cancelable, null);
return evt;
}
@@ -0,0 +1,56 @@
import { async, ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';

import { FavoriteColorComponent } from './favorite-color.component';
import { createNewEvent } from '../../shared/utils';

describe('FavoriteColorComponent', () => {
let component: FavoriteColorComponent;
let fixture: ComponentFixture<FavoriteColorComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ FormsModule ],
declarations: [ FavoriteColorComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(FavoriteColorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

// #docregion model-to-view
it('should update the favorite color on the input field', fakeAsync(() => {
component.favoriteColor = 'Blue';

fixture.detectChanges();

tick();

const input = fixture.nativeElement.querySelector('input');

expect(input.value).toBe('Blue');
}));
// #enddocregion model-to-view

// #docregion view-to-model
it('should update the favorite color in the component', fakeAsync(() => {
const input = fixture.nativeElement.querySelector('input');
const event = createNewEvent('input');

input.value = 'Red';
input.dispatchEvent(event);

fixture.detectChanges();

expect(component.favoriteColor).toEqual('Red');
}));
// #enddocregion view-to-model
});
@@ -0,0 +1,12 @@
import { Component } from '@angular/core';

@Component({
selector: 'app-template-favorite-color',
template: `
Favorite Color: <input type="text" [(ngModel)]="favoriteColor">
`,
styles: []
brandonroberts marked this conversation as resolved.
Show resolved Hide resolved
})
export class FavoriteColorComponent {
favoriteColor = '';
}
@@ -0,0 +1,13 @@
import { TemplateModule } from './template.module';

describe('TemplateModule', () => {
let templateModule: TemplateModule;

beforeEach(() => {
templateModule = new TemplateModule();
});

it('should create an instance', () => {
expect(templateModule).toBeTruthy();
});
});
@@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { FavoriteColorComponent } from './favorite-color/favorite-color.component';

@NgModule({
imports: [
CommonModule,
FormsModule
],
declarations: [FavoriteColorComponent],
exports: [FavoriteColorComponent]
})
export class TemplateModule { }
14 changes: 14 additions & 0 deletions aio/content/examples/forms-overview/src/index.html
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Forms Overview</title>
<base href="/">

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
12 changes: 12 additions & 0 deletions aio/content/examples/forms-overview/src/main.ts
@@ -0,0 +1,12 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
7 changes: 7 additions & 0 deletions aio/content/examples/forms-overview/stackblitz.json
@@ -0,0 +1,7 @@
{
"description": "Forms Overview",
"files":[
"!**/*.d.ts",
"!**/*.js"
]
}