You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 $inject array 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 via templateUrl in the component decorator (inline template works 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 htmlToPlaintext and words need to be rewritten as Angular pipes.
  • Helper Directives: Any custom directives like fallback-img must 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 htmlToPlaintext and words as Angular pipes. Example for WordsPipe:
    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-img to 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 item object directly (as in showDetails), note that Angular will detect these changes automatically since it references the same object reference.
  • Double-check the date pipe format—Angular's implementation is slightly different from AngularJS, but your MM/dd/yyyy format should work as expected.

内容的提问来源于stack exchange,提问作者yams

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:07:44