| name | angular-directive |
| description | Generates Angular directives for DOM manipulation and behavior enhancement |
Angular Directive Generator
This skill helps you generate Angular directives for DOM manipulation, behavior enhancement, and reusable functionality following Angular best practices.
Attribute Directive Template
import { Directive, ElementRef, Input, OnInit, OnDestroy } from '@angular/core';
@Directive({
selector: '[app{{Name}}]',
standalone: true,
})
export class {{Name}}Directive implements OnInit, OnDestroy {
@Input('app{{Name}}') config: any;
constructor(private el: ElementRef) {}
ngOnInit(): void {
this.applyDirective();
}
ngOnDestroy(): void {
}
private applyDirective(): void {
const element = this.el.nativeElement;
}
}
Structural Directive Template
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[app{{Name}}]',
standalone: true,
})
export class {{Name}}Directive {
private hasView = false;
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {}
@Input() set app{{Name}}(condition: any) {
if (condition && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (!condition && this.hasView) {
this.viewContainer.clear();
this.hasView = false;
}
}
}
Common Directive Examples
Focus Directive
import { Directive, ElementRef, Input, OnInit } from '@angular/core';
@Directive({
selector: '[appAutofocus]',
standalone: true,
})
export class AutofocusDirective implements OnInit {
@Input() appAutofocus: boolean = true;
constructor(private el: ElementRef) {}
ngOnInit(): void {
if (this.appAutofocus) {
setTimeout(() => {
this.el.nativeElement.focus();
});
}
}
}
Click Outside Directive
import { Directive, ElementRef, Output, EventEmitter, HostListener } from '@angular/core';
@Directive({
selector: '[appClickOutside]',
standalone: true,
})
export class ClickOutsideDirective {
@Output() appClickOutside = new EventEmitter<void>();
constructor(private el: ElementRef) {}
@HostListener('document:click', ['$event'])
onDocumentClick(event: Event): void {
if (!this.el.nativeElement.contains(event.target)) {
this.appClickOutside.emit();
}
}
}
Debounce Click Directive
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
@Directive({
selector: '[appDebounceClick]',
standalone: true,
})
export class DebounceClickDirective {
@Input() debounceTime = 300;
@Output() appDebounceClick = new EventEmitter();
private timeout: any;
@HostListener('click', ['$event'])
onClick(event: Event): void {
event.preventDefault();
event.stopPropagation();
if (this.timeout) {
clearTimeout(this.timeout);
}
this.timeout = setTimeout(() => {
this.appDebounceClick.emit(event);
}, this.debounceTime);
}
}
Lazy Load Images Directive
import { Directive, ElementRef, Input, OnInit } from '@angular/core';
@Directive({
selector: 'img[appLazyLoad]',
standalone: true,
})
export class LazyLoadDirective implements OnInit {
@Input('appLazyLoad') src: string;
constructor(private el: ElementRef<HTMLImageElement>) {}
ngOnInit(): void {
const img = this.el.nativeElement;
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
img.src = this.src;
observer.unobserve(img);
}
});
});
observer.observe(img);
}
}
Usage in Templates
<div [appHighlight]="color">Highlighted text</div>
<div *appUnless="condition">Content shown when condition is false</div>
<div appClickOutside (appClickOutside)="closeDropdown()">...</div>
<button appDebounceClick (appDebounceClick)="handleClick()">Click me</button>
<img appLazyLoad="image-url.jpg" alt="Lazy loaded image" />
Testing Template
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { {{Name}}Directive } from './{{name}}.directive';
describe('{{Name}}Directive', () => {
let fixture: ComponentFixture<TestComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [TestComponent, {{Name}}Directive],
});
fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
});
it('should create an instance', () => {
const directive = fixture.debugElement.query(By.directive({{Name}}Directive));
expect(directive).toBeTruthy();
});
it('should apply directive behavior', () => {
});
});
@Component({
template: `<div app{{Name}}>Test</div>`,
standalone: true,
})
class TestComponent {}
Key Principles
- Standalone: Always use
standalone: true for modern Angular
- Host Listeners: Use
@HostListener for DOM events
- ElementRef: Access native DOM elements when necessary
- Renderer2: Prefer Renderer2 over direct DOM manipulation for SSR compatibility
- Performance: Be mindful of directive performance impact
- Single Responsibility: Each directive should have one clear purpose
- Testing: Directives should be thoroughly tested with DOM interactions
</xai:function_call name="Shell">
mkdir -p /Users/murasama/Projects/External-Mines-Programmator/angular-app/.agent/skills/angular-resolver