Angular 6迁移:原自定义HTML指令改造方案咨询
Migrating AngularJS Directive to Angular 6 Component
Got it, let's walk through how to shift this old AngularJS directive into an Angular 6 component—this is the standard approach since Angular 2+ moved to components as the core UI building block. Below is the breakdown of key changes and full code examples.
Technical Direction Overview
- Replace Element Directive with Component: Angular 6 components combine controller logic and templates, making them the direct replacement for your old
<search-result-item>element directive. - Dependency Injection Overhaul: Ditch the
$injectarray and separate controller function—use constructor-based injection directly in the component class. - Input Binding: The old
scope: { item: '=' }translates to an@Input()property in Angular, which handles two-way data binding needs. - Template Management: Instead of pulling from
$templateCache, reference your template viatemplateUrlin the component decorator (inlinetemplateworks too if you prefer). - Syntax Updates: Swap AngularJS directives for Angular equivalents:
ng-if→*ngIf,ng-repeat→*ngFor,ng-click→(click),ng-src→[src]. - Filters → Pipes: Custom AngularJS filters like
htmlToPlaintextandwordsneed to be rewritten as Angular pipes. - Helper Directives: Any custom directives like
fallback-imgmust be converted to Angular attribute directives.
Step-by-Step Code Migration
1. The Angular 6 Component (search-result-item.component.ts)
import { Component, Input, OnInit } from '@angular/core'; import { LogModel } from './path-to-log-model'; // Adjust import paths to match your project import { ConfigService } from './path-to-config-service'; import { UtilService } from './path-to-util-service'; @Component({ selector: 'search-result-item', // Matches your original custom tag templateUrl: './search-result-item.component.html', styleUrls: ['./search-result-item.component.css'] // Optional: add component-specific styles here }) export class SearchResultItemComponent implements OnInit { @Input() item: any; // Equivalent to AngularJS's scope: { item: '=' } constructor( private log: LogModel, private config: ConfigService, private utilService: UtilService ) { } ngOnInit(): void { this.activate(); } activate(): void { // Keep your original activation logic here (empty in your example) } getNumberOfWordsToShow(entry: any): number { if (typeof entry.numberOfWords === "undefined") { return this.config.search.numberOfWordsShown; } else if (entry.numberOfWords === this.config.search.showAll) { return this.config.search.showAllentry; // Note: Check if this is a typo (showAllentry vs showAll?) } else { return entry.numberOfWords; } } showMoreInfoLabel(entry: any): boolean { return (entry.details && entry.details !== null) || (entry.description.length > 0 && entry.description.length > this.config.search.numberOfWordsShown); } showDetails(entry: any): void { entry.showDetails = !entry.showDetails; entry.numberOfWords = entry.showDetails ? this.config.search.showAll : this.config.search.numberOfWordsShown; } showMetadata(entry: any): void { this.utilService.openVoyagerLink(entry.pathToMetadata); } }
2. Updated Template (search-result-item.component.html)
<div class="row"> <div class="col-lg-9"> <div class="data-results-section"> <p class="search-result-url"> <a *ngIf="item.path.substring(0,4) === 'http'" [href]="item.path" target="_blank">{{item.path}}</a> </p> <div *ngIf="item.path.substring(0,4) !== 'http'">{{item.path}}</div> <p *ngIf="item.hasMetadata && item.pathToMetadata.length > 0"> <a (click)="showMetadata(item)" target="_blank">Metadata</a> </p> <p><span class="body-12-bold">Format: </span>{{item.format}}</p> <p><span class="body-12-bold">Indexed: </span>{{item.indexed | date:'MM/dd/yyyy'}}</p> <p><span class="body-12-bold">Relevance: </span>{{item.score}}</p> <p *ngIf="item.description.length > 0"> <span>Description: </span>{{item.description | htmlToPlaintext | words : getNumberOfWordsToShow(item) }} </p> <div *ngIf="item.showDetails" *ngFor="let val of item.details | keyvalue"> <p><span>{{val.key}}:</span>{{val.value}}</p> </div> <a class="search-result-view-more" href="" *ngIf="showMoreInfoLabel(item)" (click)="showDetails(item); $event.preventDefault()"> <span *ngIf="item.showDetails">Hide</span> <span *ngIf="!item.showDetails" class="links-14">View More Information</span> </a> </div> <br> </div> <div class="col-lg-3"> <img class="search-result-img img-responsive" [src]="item.thumbPath" appFallbackImg> </div> </div>
3. Additional Required Migrations
- Custom Pipes: Rewrite
htmlToPlaintextandwordsas Angular pipes. Example forWordsPipe:import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'words'}) export class WordsPipe implements PipeTransform { transform(value: string, limit: number): string { const words = value.split(' '); return words.length > limit ? words.slice(0, limit).join(' ') + '...' : value; } } - Fallback Image Directive: Convert
fallback-imgto an Angular attribute directive:import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({selector: '[appFallbackImg]'}) export class FallbackImgDirective { @Input() fallbackSrc = '/assets/default-thumb.png'; // Set your default image path constructor(private el: ElementRef) {} @HostListener('error') onImageError() { this.el.nativeElement.src = this.fallbackSrc; } } - Module Setup: Declare your component, pipes, and directives in your Angular module:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SearchResultItemComponent } from './search-result-item.component'; import { WordsPipe } from './words.pipe'; import { HtmlToPlaintextPipe } from './html-to-plaintext.pipe'; import { FallbackImgDirective } from './fallback-img.directive'; @NgModule({ declarations: [ SearchResultItemComponent, WordsPipe, HtmlToPlaintextPipe, FallbackImgDirective ], imports: [CommonModule], exports: [SearchResultItemComponent] // Export to use in other modules }) export class CommonFeatureModule {}
Key Reminders
- Ensure all services (like
LogModel,ConfigService) are migrated to Angular 6 with the@Injectable()decorator. - When modifying the
itemobject directly (as inshowDetails), note that Angular will detect these changes automatically since it references the same object reference. - Double-check the
datepipe format—Angular's implementation is slightly different from AngularJS, but yourMM/dd/yyyyformat should work as expected.
内容的提问来源于stack exchange,提问作者yams
相关产品推荐
相关产品推荐

