如何将Angular指令转换为TypeScript组件?附待转换代码
Got it, let's break down how to turn your AngularJS directive into a modern Angular (TypeScript) component—each part of the original directive maps directly to Angular component features, so I'll make that connection clear as we go.
Step 1: Component Structure & Decorator
First, we'll replace the directive class with an Angular component using the @Component decorator. Since your original directive was an attribute directive (restrict: 'A'), we'll keep the same attribute-based selector.
import { Component, Input, OnInit } from '@angular/core'; // Assuming balanceSheetFSPolicy is available in your codebase (we'll talk about improving this later!) declare const balanceSheetFSPolicy: any; @Component({ selector: '[tableRowBsGroup]', // Matches the original directive's attribute usage templateUrl: balanceSheetFSPolicy.dirvmConstant.TableRowGroupTmpl, // Reuse your existing template }) export class TableRowBsGroupComponent implements OnInit { // Step 2: Map scope bindings to Angular inputs @Input() dirvm: any; // Equivalent to scope: { dirvm: '=' } @Input() grouplvl: any; // Equivalent to scope: { grouplvl: '=' } @Input() classlvl: string; // Equivalent to scope: { classlvl: '@' } // Expose balanceSheetFSPolicy to the template (matches $scope.balanceSheetFSPolicy) balanceSheetFSPolicy = balanceSheetFSPolicy; ngOnInit(): void { // Step 3: Replace directive controller logic with a lifecycle hook // This runs after inputs are initialized, just like the directive controller would balanceSheetFSPolicy.balanceSheetFSViewModel = this.dirvm; } }
Key Mapping Breakdown
- Selector:
[tableRowBsGroup]means you'll use the component exactly like the original directive—e.g.,<tr tableRowBsGroup [dirvm]="myViewModel" ...> - Inputs:
@Input() dirvm: anyreplaces the two-way binding (=) from the directive scope. If you need explicit two-way binding later, you can add an@Output() dirvmChange = new EventEmitter<any>()and emit updates, but the original code only assigns to a global variable, so a basic input works here.@Input() grouplvl: anymaps directly to the originalgrouplvl: '='binding.@Input() classlvl: stringmaps toclasslvl: '@'(since@is for string/attribute values in AngularJS).
- Template: We reuse the exact same
templateUrlfrom your original directive—no changes needed here unless you want to update the template to use Angular syntax. - Controller Logic: The original directive's controller code (setting the global
balanceSheetFSPolicyvalues) moves to thengOnInitlifecycle hook. This runs right after the component's inputs are initialized, which matches when the directive controller would execute. - Template Data Access: Instead of assigning to
$scope, we makebalanceSheetFSPolicya public component property—this makes it automatically available in the template, just like$scope.balanceSheetFSPolicywas.
Step 4: Register the Component in Your Module
Replace the old directive registration with component registration in your Angular module. For the original app.recon.statements module, update its declarations:
import { NgModule } from '@angular/core'; import { TableRowBsGroupComponent } from './table-row-bs-group.component'; // Import other components/directives/pipes here @NgModule({ declarations: [ TableRowBsGroupComponent, // Add other declarations your module needs ], // Include imports, exports, providers as needed }) export class ReconStatementsModule { }
Quick Improvement: Ditch Global Variables
Your original directive uses a global balanceSheetFSPolicy variable. In Angular, the better practice is to wrap this logic in a service (using @Injectable) instead of relying on globals—it makes your code more testable and maintainable. Here's a quick example:
// balance-sheet-fs.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class BalanceSheetFSService { balanceSheetFSViewModel: any; dirvmConstant = { /* Your constant values here */ }; }
Then inject it into your component:
import { BalanceSheetFSService } from './balance-sheet-fs.service'; // ... constructor(private balanceSheetFSService: BalanceSheetFSService) { this.balanceSheetFSPolicy = balanceSheetFSService; // Keep exposing to template if needed } ngOnInit(): void { this.balanceSheetFSService.balanceSheetFSViewModel = this.dirvm; }
This replaces the global variable with a proper Angular service, which is the standard approach for shared state/logic.
内容的提问来源于stack exchange,提问作者Markus ofcrypto

