— No reviews yet
0 installs
12 views
0.0% view→install
Install
$ agentstack add skill-cuongtl1992-vibe-skills-angular-forms ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Are you the author of Angular Forms? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claimAbout
Angular Reactive Forms
Typed reactive forms with signal-based status tracking, commonly used inside dialog components.
Core Form Setup
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { toSignal } from '@angular/core/rxjs-interop';
import { startWith } from 'rxjs';
readonly form = new FormGroup({
name: new FormControl('', {
nonNullable: true,
validators: [Validators.required, Validators.maxLength(255)],
}),
description: new FormControl('', { nonNullable: true }),
isActive: new FormControl(true, { nonNullable: true }),
});
Signal-Based Form Status
// MUST use startWith to capture initial status
private readonly formStatus = toSignal(
this.form.statusChanges.pipe(startWith(this.form.status)),
{ initialValue: this.form.status }
);
readonly saveDisabled = computed(() =>
this.formStatus() !== 'VALID' || this._submitting()
);
Computed Error Messages
readonly nameErrorMessage = computed(() => {
const control = this.form.controls.name;
if (!control.touched) return undefined;
if (control.hasError('required')) return 'Name is required';
if (control.hasError('maxlength')) return 'Name must be 255 characters or less';
return undefined;
});
Submission with exhaustMap
Prevent double-submit using Subject + exhaustMap:
private readonly submitTrigger$ = new Subject();
private readonly destroyRef = inject(DestroyRef);
ngOnInit(): void {
this.submitTrigger$
.pipe(
exhaustMap(() => this.handleSubmission()),
takeUntilDestroyed(this.destroyRef) // MUST pass destroyRef
)
.subscribe();
}
onSubmit(): void {
if (this.form.invalid) { this.markFormAsTouched(); return; }
if (this._submitting()) return;
this.submitTrigger$.next();
}
private markFormAsTouched(): void {
Object.values(this.form.controls).forEach(c => c.markAsTouched());
}
Dual Mode (Create/Edit)
mode = input.required();
entity = input();
readonly isCreateMode = computed(() => this.mode() === 'create');
ngOnInit(): void {
// ... wire submitTrigger$ ...
if (this.mode() === 'edit') {
const existing = this.entity();
if (existing) {
this.form.patchValue({ name: existing.name, description: existing.description });
}
}
}
Key Rules
toSignal(form.statusChanges.pipe(startWith(form.status)))— always use startWith- Pass
this.destroyReftotakeUntilDestroyed()inngOnInit() - Use
exhaustMapfor submission (prevents concurrent submits) - Check
touchedbefore showing errors
For full dialog form patterns, see [references/form-patterns.md](references/form-patterns.md).
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: cuongtl1992
- Source: cuongtl1992/vibe-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.