// TEXT INPUT
// We use two-way data binding with 'ngModel' to bind to the 'textValue' property
// on the component class. Two-way binding allows us to use the property to set
// the initial value of an '<input>', and then have the user's changes flow back to the property.
// text.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-text-box',
template: `
<h1>Text ({{textValue}})</h1>
<input #textbox type="text" [(ngModel)]="textValue" required> <!-- A template reference variable on the input... -->
<button (click)="logText(textbox.value)">Update Log</button> <!-- ...gives us access to the properties and methods of the input control. -->
<button (click)="textValue=''">Clear</button>
<h2>Template Reference Variable</h2>
Type: '{{textbox.type}}', required: '{{textbox.hasAttribute('required')}}',
upper: '{{textbox.value.toUpperCase()}}'
<h2>Log <button (click)="log=''">Clear</button></h2>
<pre>{{log}}</pre>`
})
export class TextComponent {
textValue = 'initial value';
log = '';
logText(value: string): void {
this.log += `Text changed to '${value}'\n`;
}
}
// CHECKBOX
// checkbox.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-checkbox',
template: `
<h1>Checkbox</h1>
<p>
<label [class.selected]="cb1.checked"> <!-- we can determine whether or not the checkbox has been selected using the 'checked' property and highlight the selected checkbox labels using class bindings. -->
<input #cb1 type="checkbox" value="one" (change)="logCheckbox(cb1)"> One <!-- 'change' event is triggered when the user clicks on a checkbox. We use this event to pass a template reference variable to the function -->
</label>
<label [class.selected]="cb2.checked">
<input #cb2 type="checkbox" value="two" (change)="logCheckbox(cb2)"> Two
</label>
<label [class.selected]="cb3.checked">
<input #cb3 type="checkbox" value="three" (change)="logCheckbox(cb3)"> Three
</label>
</p>
<h2>Log <button (click)="log=''">Clear</button></h2>
<pre>{{log}}</pre>`,
styles: ['.selected {color: OrangeRed;}']
})
export class CheckboxComponent {
log = '';
logCheckbox(element: HTMLInputElement): void {
this.log += `Checkbox ${element.value} was ${element.checked ? '' : 'un'}checked\n`;
}
}
// RADIO
// radio.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-radio',
template: `
<h1>Radio</h1>
<p>
<label [class.selected]="r1.checked">
<input #r1 type="radio" name="r" value="one" (change)="logRadio(r1)"> One
</label>
<label [class.selected]="r2.checked">
<input #r2 type="radio" name="r" value="two" (change)="logRadio(r2)"> Two
</label>
<label [class.selected]="r3.checked">
<input #r3 type="radio" name="r" value="three" (change)="logRadio(r3)"> Three
</label>
</p>
<h2>Log <button (click)="log=''">Clear</button></h2>
<pre>{{log}}</pre>`,
styles: ['.selected {color: OrangeRed;}']
})
export class RadioComponent {
log = '';
logRadio(element: HTMLInputElement): void {
this.log += `Radio ${element.value} was selected\n`;
}
}
// COMBO / DROPDOWN LIST
// drop-down.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-drop-down',
template: `
<h1>Drop-down List</h1>
<select #select [(ngModel)]="current" (change)="logDropdown(select.value)">
<option *ngFor="let item of list" [value]="item.id">{{item.name}}</option>
</select>
<h2>Log <button (click)="log=''">Clear</button></h2>
<pre>{{log}}</pre>`
})
export class DropDownComponent {
list: any = [
{id: 1, name: 'one'},
{id: 2, name: 'two'},
{id: 3, name: 'three'}
];
current = 2;
log = '';
logDropdown(id: number): void {
const NAME = this.list.find((item: any) => item.id === +id).name;
this.log += `Value ${NAME} was selected\n`;
}
}
user.interface.ts
export interface User {
name: string; // text
age?: number; // number
gender?: string; // radio
role?: string; // select (primitive)
theme?: Theme; // select (object)
topics?: string[]; // multiple select
isActive?: boolean; // checkbox
toggle?: string; // checkbox toggle either 'toggled' or 'untoggled'
}
theme.interface.ts
export interface Theme {
display: string;
backgroundColor: string;
fontColor: string;
}
app.component.ts
import { Component, OnInit } from '@angular/core';
import { User } from './user.interface';
import { Theme } from './theme.interface';
@Component({
moduleId: module.id, //?
selector: 'my-app',
templateUrl: 'app.component.html',
directives: []
})
export class AppComponent implements OnInit {
public user: User; // en lugar de models usa interfaces, por que?
/* standing data (ver en cada caso de cada input) */
ngOnInit() {
// initialize user model
this.user = {
name: '',
gender: this.genders[0].value, // default to Female
role: null,
theme: this.themes[0], // default to dark theme
isActive: false,
toggle: this.toggles[1].value, // default to untoggled
topics: [this.topics[1].value] // [] MAKES THE FIELD AN ARRAY //default to Technology
}
}
public save(isValid: boolean, f: User) {
console.log(f);
}
}
app.component.html
<form #f="ngForm" novalidate>
<!-- We'll add our form controls here -->
<button type="submit" (click)="save(f.value, f.valid)">Submit</button>
</form>
You need the name attribute, and ngModel.
<div>
<label>Name</label>
<input type="text" name="name" [(ngModel)]="user.name">
</div>
<div>
<label>Age</label>
<input type="number" name="age" [(ngModel)]="user.age">
</div>
We have this list of genders:
public genders = [
{ value: 'F', display: 'Female' },
{ value: 'M', display: 'Male' }
];
When select, we want only the value F
or M
:
<div>
<label>Gender</label>
<div *ngFor="let gender of genders">
<label>
<input type="radio" name="gender"
[(ngModel)]="user.gender" //bindeamos con la propiedad del model que queramos
[value]="gender.value"> //componemos las opciones a partir del array de 'genders'
{{gender.display}}
</label>
</div>
</div>
We have a list of roles:
public roles = [
{ value: 'admin', display: 'Administrator' },
{ value: 'guest', display: 'Guest' },
{ value: 'custom', display: 'Custom' }
];
When value selected, we expected it to return string value admin
, guest
or custom
:
<div>
<label>Role</label>
<select name="role" [(ngModel)]="user.role"> //bindeamos con la propiedad del model que queramos
<option *ngFor="let role of roles" [value]="role.value"> //componemos las opciones a partir del array de 'roles'
{{role.display}}
</option>
</select>
</div>
Instead of simple type, we want the whole object when it’s selected.
We have the list of themes:
public themes: Theme[] = [ //array de elementos del tipo Theme (porqué lo usa así en lugar de con models?)
{ backgroundColor: 'black', fontColor: 'white', display: 'Dark' },
{ backgroundColor: 'white', fontColor: 'black', display: 'Light' },
{ backgroundColor: 'grey', fontColor: 'white', display: 'Sleek' }
];
When selected, for example Light theme, we expect { backgroundColor: 'white', fontColor: 'black', display: 'Light' }
to be returned. Instead of binding to the value
property, we bind to ngValue
property.
<div>
<label>Theme</label>
<select name="theme" [(ngModel)]="user.theme">
<option *ngFor="let theme of themes" [ngValue]="theme">
{{theme.display}}
</option>
</select>
</div>
when selecting game and tech, it should return ['game', 'tech']
.
public topics = [
{ value: 'game', display: 'Gaming' },
{ value: 'tech', display: 'Technology' },
{ value: 'life', display: 'Lifestyle' },
];
Similar to select, but this time our model is array of string: topics: []
<div>
<label>Topics</label>
<select multiple name="topics" [(ngModel)]="user.topics">
<option *ngFor="let topic of topics" [value]="topic.value">
{{topic.display}}
</option>
</select>
</div>
By default, checkbox return boolean.
<div>
<label>
<input type="checkbox" name="isActive" [(ngModel)]="user.isActive">
Is Active
</label>
</div>
Instead of boolean, we expecting value. When checked, it should return toggled, else return value untoggled.
public toggles = [
{ value: 'toggled', display: 'Toggled' },
{ value: 'untoggled', display: 'UnToggled' },
];
How we do it:
<div>
<input type="hidden" name="toggle" [(ngModel)]="user.toggle"> // we define a hidden input to bind to the real model
<div>
<label>
<input type="checkbox"
[checked]="user.toggle === toggles[0].value" //handle the 'checked' property
(change)="$event.target.checked ? (user.toggle = toggles[0].value) : (user.toggle = toggles[1].value)"> // 'change' event fire every time value change: we read the $event.target.checked to find out if the checkbox is checked, then update model value accordingly
{{ toggles[0].display }}
</label>
</div>
</div>
During development, visualize the values:
<pre>{{your_form or control_name | json }}</pre>