docs: lint code examples (#59979)

PR Close #59979
This commit is contained in:
Gerome Grignon 2025-03-10 00:19:16 +01:00 committed by Jessica Janiuk
parent 2468bd7282
commit c65259c8a5
20 changed files with 144 additions and 125 deletions

View file

@ -17,13 +17,13 @@
</p>
<!-- #enddocregion defaultColor, -->
<hr />
<hr>
<h2>Mouse over the following lines to see fixed highlights</h2>
<p [appHighlight]="'yellow'">Highlighted in yellow</p>
<p appHighlight="orange">Highlighted in orange</p>
<hr />
<hr>
<h2>ngNonBindable</h2>
<!-- #docregion ngNonBindable -->

View file

@ -13,7 +13,7 @@ import {Observable} from 'rxjs';
template: `
<div>
<h2>Job Application for Heroes</h2>
<app-dynamic-form [questions]="questions$ | async"></app-dynamic-form>
<app-dynamic-form [questions]="questions$ | async" />
</div>
`,
providers: [QuestionService],

View file

@ -3,7 +3,7 @@
<form (ngSubmit)="onSubmit()" [formGroup]="form">
@for (question of questions(); track question) {
<div class="form-row">
<app-question [question]="question" [form]="form"></app-question>
<app-question [question]="question" [form]="form" />
</div>
}

View file

@ -1,6 +1,5 @@
// #docregion
import {Component, input, Input, OnInit} from '@angular/core';
import {CommonModule} from '@angular/common';
import {Component, inject, input} from '@angular/core';
import {FormGroup, ReactiveFormsModule} from '@angular/forms';
import {DynamicFormQuestionComponent} from './dynamic-form-question.component';
@ -14,17 +13,13 @@ import {QuestionControlService} from './question-control.service';
providers: [QuestionControlService],
imports: [DynamicFormQuestionComponent, ReactiveFormsModule],
})
export class DynamicFormComponent implements OnInit {
export class DynamicFormComponent {
qcs = inject(QuestionControlService);
questions = input<QuestionBase<string>[] | null>([]);
form!: FormGroup;
form: FormGroup = this.qcs.toFormGroup(this.questions() as QuestionBase<string>[]);
payLoad = '';
constructor(private qcs: QuestionControlService) {}
ngOnInit() {
this.form = this.qcs.toFormGroup(this.questions() as QuestionBase<string>[]);
}
onSubmit() {
this.payLoad = JSON.stringify(this.form.getRawValue());
}

View file

@ -1,9 +1,9 @@
// #docregion
import {Component} from '@angular/core';
import {ActorFormReactiveComponent} from './reactive/actor-form-reactive.component';
import {ActorFormComponent} from '../../../forms/src/app/actor-form/actor-form.component';
import {ReactiveFormsModule} from '@angular/forms';
import {FormsModule} from '@angular/forms';
import {ActorFormTemplateComponent} from './template/actor-form-template.component';
@Component({
selector: 'app-root',
@ -11,6 +11,11 @@ import {FormsModule} from '@angular/forms';
<app-actor-form-template/>
<hr>
<app-actor-form-reactive/>`,
imports: [ActorFormComponent, ActorFormReactiveComponent, FormsModule, ReactiveFormsModule],
imports: [
ActorFormReactiveComponent,
FormsModule,
ReactiveFormsModule,
ActorFormTemplateComponent,
],
})
export class AppComponent {}

View file

@ -1,4 +1,4 @@
<!-- #docregion -->
<!-- #docregion -->
<div class="container">
<h2>Reactive Form</h2>
@ -7,58 +7,59 @@
<div [hidden]="formDir.submitted">
<div class="cross-validation" [class.cross-validation-error]="actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)">
<div class="cross-validation"
[class.cross-validation-error]="actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)">
<div class="form-group">
<label for="name">Name</label>
<!-- #docregion name-with-error-msg -->
<input type="text" id="name" class="form-control"
formControlName="name" required>
formControlName="name" required>
@if(name.invalid && (name.dirty || name.touched)) {
@if (name.invalid && (name.dirty || name.touched)) {
<div class="alert alert-danger">
@if(name.hasError('required')) {
@if (name.hasError('required')) {
<div>
Name is required.
</div>
}
@if(name.hasError('minlength')) {
@if (name.hasError('minlength')) {
<div>
Name must be at least 4 characters long.
</div>
}
@if(name.hasError('forbiddenName')) {
@if (name.hasError('forbiddenName')) {
<div>
Name cannot be Bob.
</div>
}
</div>
}
</div>
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="role">Role</label>
<input type="text" id="role" class="form-control"
formControlName="role">
formControlName="role">
@if(role.pending) {
<div>
Validating...
@if (role.pending) {
<div>Validating...</div>
}
@if (role.invalid) {
<div class="alert alert-danger role-errors">
@if (role.hasError('uniqueRole')) {
<div>
Role is already taken.
</div>
}
</div>
}
@if(role.invalid) {
<div class="alert role-errors">
@if(role.hasError('uniqueRole')) {
Role is already taken.
</div>
</div>
</div>
<!-- #docregion cross-validation-error-message -->
@if(actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)) {
@if (actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)) {
<div class="cross-validation-error-message alert alert-danger">
Name cannot match role or audiences will be confused.
</div>
@ -69,16 +70,16 @@
<div class="form-group">
<label for="skill">Skill</label>
<select id="skill" class="form-control"
formControlName="skill" required>
@for(skill of skills; track $index) {
formControlName="skill" required>
@for (skill of skills; track $index) {
<option [value]="skill">{{ skill }}</option>
}
</select>
@if(skill.invalid && skill.touched) {
@if (skill.invalid && skill.touched) {
<div class="alert alert-danger">
@if(skill.hasError('required')) {
Skill is required.
@if (skill.hasError('required')) {
<div>Skill is required.</div>
}
</div>
}
@ -87,13 +88,15 @@
<p>Complete the form to enable the Submit button.</p>
<button type="submit"
class="btn btn-default"
[disabled]="actorForm.invalid">Submit</button>
[disabled]="actorForm.invalid">Submit
</button>
<button type="button" class="btn btn-default"
(click)="formDir.resetForm({})">Reset</button>
(click)="formDir.resetForm({})">Reset
</button>
</div>
</form>
@if(formDir.submitted) {
@if (formDir.submitted) {
<div class="submitted-message">
<p>You've submitted your actor, {{ actorForm.value.name }}!</p>
<button type="button" (click)="formDir.resetForm({})">Add new actor</button>

View file

@ -1,48 +1,50 @@
<!-- #docregion -->
<!-- #docregion -->
<div>
<h2>Template-Driven Form</h2>
<!-- #docregion cross-validation-register-validator -->
<form #actorForm="ngForm" appUnambiguousRole>
<!-- #enddocregion cross-validation-register-validator -->
<!-- #enddocregion cross-validation-register-validator -->
<div [hidden]="actorForm.submitted">
<div class="cross-validation" [class.cross-validation-error]="actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)">
<div class="cross-validation"
[class.cross-validation-error]="actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)">
<div class="form-group">
<label for="name">Name</label>
<!-- #docregion name-with-error-msg -->
<!-- #docregion name-input -->
<input type="text" id="name" name="name" class="form-control"
required minlength="4" appForbiddenName="bob"
[(ngModel)]="actor.name" #name="ngModel">
required minlength="4" appForbiddenName="bob"
[(ngModel)]="actor.name" #name="ngModel">
<!-- #enddocregion name-input -->
@if(name.invalid && (name.dirty || name.touched)) {
@if (name.invalid && (name.dirty || name.touched)) {
<div class="alert">
@if(name.hasError('required')) {
<div>
Name is required.
</div>
}
@if(name.hasError('minlength')) {
<div>
Name must be at least 4 characters long.
</div>
}
@if(name.hasError('forbiddenName')) {
<div>
Name cannot be Bob.
</div>
}
</div>
@if (name.hasError('required')) {
<div>
Name is required.
</div>
}
@if (name.hasError('minlength')) {
<div>
Name must be at least 4 characters long.
</div>
}
@if (name.hasError('forbiddenName')) {
<div>
Name cannot be Bob.
</div>
}
</div>
}
<!-- #enddocregion name-with-error-msg -->
</div>
}
<div class="form-group">
<label for="role">Role</label>
<!-- #docregion role-input -->
<input type="text"
<!-- #docregion role-input -->
<input type="text"
id="role"
name="role"
#role="ngModel"
@ -50,22 +52,22 @@
[ngModelOptions]="{ updateOn: 'blur' }"
appUniqueRole>
<!-- #enddocregion role-input -->
@if(role.pending) {
<div>
Validating...
@if (role.pending) {
<div>Validating...</div>
}
@if (role.invalid) {
<div class="alert role-errors">
@if (role.hasError('uniqueRole')) {
<div>
Role is already taken.
</div>
}
</div>
}
@if(role.invalid) {
<div class="alert role-errors">
@if(role.hasError('uniqueRole')) {
Role is already taken.
</div>
}
</div>
</div>
<!-- #docregion cross-validation-error-message -->
@if(actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)) {
@if (actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)) {
<div class="cross-validation-error-message alert">
Name cannot match role.
</div>
@ -79,15 +81,15 @@
name="skill"
required [(ngModel)]="actor.skill"
#skill="ngModel">
@for(skill of skills; track $index) {
@for (skill of skills; track $index) {
<option [value]="skill">{{ skill }}</option>
}
</select>
@if(skill.errors && skill.touched) {
@if (skill.errors && skill.touched) {
<div class="alert">
@if(skill.errors['required']) {
Power is required.
@if (skill.errors['required']) {
<div>Skill is required.</div>
}
</div>
}
@ -95,12 +97,14 @@
<p>Complete the form to enable the Submit button.</p>
<button type="submit"
[disabled]="actorForm.invalid">Submit</button>
[disabled]="actorForm.invalid">Submit
</button>
<button type="button"
(click)="actorForm.resetForm({})">Reset</button>
(click)="actorForm.resetForm({})">Reset
</button>
</div>
@if(actorForm.submitted) {
@if (actorForm.submitted) {
<div class="submitted-message">
<p>You've submitted your actor, {{ actorForm.value.name }}!</p>
<button type="button" (click)="actorForm.resetForm({})">Add new actor</button>

View file

@ -2,12 +2,18 @@ import {Component} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {UnambiguousRoleValidatorDirective} from '../shared/unambiguous-role.directive';
import {ForbiddenValidatorDirective} from '../shared/forbidden-name.directive';
import {UniqueRoleValidatorDirective} from '../shared/role.directive';
@Component({
selector: 'app-actor-form-template',
templateUrl: './actor-form-template.component.html',
styleUrls: ['./actor-form-template.component.css'],
imports: [UnambiguousRoleValidatorDirective, FormsModule, ForbiddenValidatorDirective],
imports: [
UnambiguousRoleValidatorDirective,
FormsModule,
ForbiddenValidatorDirective,
UniqueRoleValidatorDirective,
],
})
export class ActorFormTemplateComponent {
skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting'];

View file

@ -3,8 +3,8 @@
<h2>Reactive</h2>
<app-reactive-favorite-color></app-reactive-favorite-color>
<app-reactive-favorite-color />
<h2>Template-Driven</h2>
<app-template-favorite-color></app-template-favorite-color>
<app-template-favorite-color />

View file

@ -33,7 +33,9 @@
<select class="form-control" id="skill"
required [(ngModel)]="model.skill" name="skill"
#skill="ngModel">
<option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option>
@for (skill of skills; track $index) {
<option [value]="skill">{{ skill }}</option>
}
</select>
<div [hidden]="skill.valid || skill.pristine" class="alert alert-danger">
skill is required
@ -132,7 +134,9 @@
<div class="form-group">
<label for="skill">Skill</label>
<select class="form-control" id="skill" required>
<option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option>
@for(skill of skills; track $index) {
<option [value]="skill">{{ skill }}</option>
}
</select>
</div>
<!-- #enddocregion skills -->
@ -168,7 +172,9 @@
<select class="form-control" id="skill"
required
[(ngModel)]="model.skill" name="skill">
<option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option>
@for (skill of skills; track $index) {
<option [value]="skill">{{ skill }}</option>
}
</select>
</div>

View file

@ -4,12 +4,13 @@ import {Component} from '@angular/core';
import {Actor} from '../actor';
import {FormsModule} from '@angular/forms';
import {JsonPipe} from '@angular/common';
// #docregion imports
@Component({
selector: 'app-actor-form',
templateUrl: './actor-form.component.html',
imports: [FormsModule],
imports: [FormsModule, JsonPipe],
})
export class ActorFormComponent {
// #enddocregion imports

View file

@ -1 +1 @@
<app-actor-form></app-actor-form>
<app-actor-form />

View file

@ -2,9 +2,9 @@
<h1>Reactive Forms</h1>
<!-- #docregion app-name-editor-->
<app-name-editor></app-name-editor>
<app-name-editor />
<!-- #enddocregion app-name-editor-->
<!-- #docregion app-profile-editor -->
<app-profile-editor></app-profile-editor>
<!-- #enddocregion app-profile-editor -->
<app-profile-editor />
<!-- #enddocregion app-profile-editor -->

View file

@ -5,10 +5,10 @@
<button type="button" (click)="toggleEditor('profile')">Profile Editor</button>
</nav>
@if (showNameEditor) {
<app-name-editor></app-name-editor>
@if (showNameEditor()) {
<app-name-editor />
}
@if (showProfileEditor) {
<app-profile-editor></app-profile-editor>
@if (showProfileEditor()) {
<app-profile-editor />
}

View file

@ -1,4 +1,6 @@
import {Component} from '@angular/core';
import {Component, computed, signal, WritableSignal} from '@angular/core';
import {NameEditorComponent} from './name-editor/name-editor.component';
import {ProfileEditorComponent} from './profile-editor/profile-editor.component';
export type EditorType = 'name' | 'profile';
@ -6,19 +8,15 @@ export type EditorType = 'name' | 'profile';
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
imports: [NameEditorComponent, ProfileEditorComponent],
})
export class AppComponent {
editor: EditorType = 'name';
editor: WritableSignal<EditorType> = signal('name');
get showNameEditor() {
return this.editor === 'name';
}
get showProfileEditor() {
return this.editor === 'profile';
}
showNameEditor = computed(() => this.editor() === 'name');
showProfileEditor = computed(() => this.editor() === 'profile');
toggleEditor(type: EditorType) {
this.editor = type;
this.editor.set(type);
}
}

View file

@ -30,7 +30,7 @@
<h2>Aliases</h2>
<button type="button" (click)="addAlias()">+ Add another alias</button>
@for(alias of aliases.controls; track alias.value; let i = $index) {
@for(alias of aliases.controls; track $index; let i = $index) {
<div>
<!-- The repeated alias template -->
<label for="alias-{{ i }}">Alias: </label>

View file

@ -29,7 +29,7 @@
<h2>Aliases</h2>
<button type="button" (click)="addAlias()">+ Add another alias</button>
@for (alias of aliases.controls; track alias.value; let i = $index) {
@for (alias of aliases.controls; track $index; let i = $index) {
<div>
<!-- The repeated alias template -->
<label for="alias-{{ i }}">Alias:</label>
@ -45,7 +45,7 @@
<!-- #enddocregion submit-button -->
</form>
<hr />
<hr>
<p>Form Value: {{ profileForm.value | json }}</p>

View file

@ -5,12 +5,13 @@ import {FormBuilder, ReactiveFormsModule} from '@angular/forms';
import {Validators} from '@angular/forms';
// #enddocregion validator-imports
import {FormArray} from '@angular/forms';
import {JsonPipe} from '@angular/common';
@Component({
selector: 'app-profile-editor',
templateUrl: './profile-editor.component.html',
styleUrls: ['./profile-editor.component.css'],
imports: [ReactiveFormsModule],
imports: [ReactiveFormsModule, JsonPipe],
})
export class ProfileEditorComponent {
private formBuilder = inject(FormBuilder);

View file

@ -210,12 +210,12 @@
</p>
</ng-template>
<hr />
<hr>
<h2 id="appIfLoaded">IfLoadedDirective</h2>
<app-hero></app-hero>
<hr />
<hr>
<h2 id="appTrigonometry">TrigonometryDirective</h2>

View file

@ -420,25 +420,25 @@ export class ShellComponent {}
template: `
<h1>Specs Demo</h1>
<my-if-parent-comp></my-if-parent-comp>
<hr />
<hr>
<h3>Input/Output Component</h3>
<io-parent-comp></io-parent-comp>
<hr />
<hr>
<h3>External Template Component</h3>
<external-template-comp></external-template-comp>
<hr />
<hr>
<h3>Component With External Template Component</h3>
<comp-w-ext-comp></comp-w-ext-comp>
<hr />
<hr>
<h3>Reverse Pipe</h3>
<reverse-pipe-comp></reverse-pipe-comp>
<hr />
<hr>
<h3>InputValueBinder Directive</h3>
<input-value-comp></input-value-comp>
<hr />
<hr>
<h3>Button Component</h3>
<lightswitch-comp></lightswitch-comp>
<hr />
<hr>
<h3>Needs Content</h3>
<needs-content #nc>
<child-1 #content text="My"></child-1>