基於ng-zorro的ASP.NET ZERO前端實現之程式碼生成器
上一篇介紹了整合ng-zorro的過程,本篇我們來看下如何用abp官方的生成器來生成前端程式碼。
Abp官方提供了一個強大的程式碼生成器 ASP.NET Zero Power Tools,它的Visual Studio 外掛在 ofollow,noindex" target="_blank">這裡 。當然你也可以不用外掛,但你得自己建立json檔案。相關官方文件見 這裡 。

工作原理
生成器(vs外掛)首先根據使用者填寫的Entity相關的內容建立一個json描述檔案,然後開始將真正的程式碼生成核心程式釋放到 aspnet-core\AspNetZeroRadTool
這個目錄下,然後開始執行生成,命令列: dotnet AspNetZeroRadTool.dll YourEntity.Json
。執行過程中會掃描FileTemplatesn內的檔案進行實際的檔案替換等操作生成最終程式碼檔案。
AspNetZeroRadTool資料夾
除了config.json其餘內容均可以從生成器(vs外掛)自動釋放出來。所以你如果用git其實可以把除config.json外的檔案ignore。
FileTemplates 資料夾
FileTemplates資料夾顧名思義是放了一些模板檔案。本次我們只關注Angular模板,目錄結構如下:

- ComponentHtmlTemplate:用於生成 Asp.net Zero 5.4之前的component html
- ComponentTemplate:用於生成component ts
- ComponentTurboTableHtmlTemplate:用於生成 Asp.net Zero 5.4之後的componnet html (由於5.4之後Table更換成了TurboTable元件)
- CreateOrEditComponentHtmlTemplate:用於生成建立或修改對話方塊的html
- CreateOrEditComponentTemplate:用於生成建立或修改對話方塊的ts
- LookupTables:用於生成選擇關聯實體對話方塊的html/ts (如果你定義的實體有外來鍵關聯,在編輯或建立時會通過該對話方塊進行選擇)
- ViewEntityComponentHtmlTemplate:用於生成view only對話方塊html (外掛介面中有可選項)
- ViewEntityComponentTemplate:用於生成view only對話方塊ts (外掛介面中有可選項)
每一個模板資料夾都包含以下三個檔案,我們來看一下:

- MainTemplate.txt:根據所在資料夾的不同有不同內容(html/ts),其中會有一些佔位的字串,它們以大括號
{{...}}
包裹。在生成階段會被替換。有幾個比較通用的佔位字串:
{{Entity_Name_Here}}
表示首字母大寫的實體名稱,如Book;
{{entity_Name_Here}}
表示首字母小寫的實體名稱,如book。 - PartialTemplates.txt:MainTemplate.txt中會有一些佔位字串的內容會根據條件從這個檔案中獲取。比如生成器在處理MainTemplate.txt時遇到
{{Get_Excel_Method_Here}}
這個佔位符時會去PartialTemplates.txt檔案裡找到對應的內容,然後根據PartialTemplates的內容(有條件的)去填充MainTemplate.txt的內容。 - TemplateInfo.txt:這個檔案很簡單,裡面只有path和condition。path代表最終生成之後檔案的位置;condition代表是否需要按照本目錄的模板生成程式碼。
建立我們自己的模板
瞭解了以上結構之後,我們來建立我們的模板檔案。
首先我們來禁用一些我們用不到的模板目錄,禁用方式很簡單,在目錄中我們只要複製相應的TemplateInfo.txt檔案並重命名為TemplateInfo.custom.txt,然後修改裡面的condition為 "condition":"false"
即可。我們需要禁用 ComponentTurboTableHtmlTemplate
、 LookupTables\LookupTableComponentTurboTableHtmlTemplate
和 LookupTables\LookupTableCssTemplate
這幾個資料夾。
以下我們建立一個列表顯示頁的html模板頁:
- 建立模板目錄ComponentNgZorroTableHtmlTemplate
- 建立模板三個檔案MainTemplate.txt、PartialTemplates.txt、TemplateInfo.txt
MainTemplate.txt的內容:
<page-header [title]="title"> <ng-template #title> {{l("{{Entity_Name_Plural_Here}}")}} <span class="text-sm text-grey-dark"> <nz-divider nzType="vertical"></nz-divider> {{l("{{Entity_Name_Plural_Here}}HeaderInfo")}} </span> </ng-template> </page-header> <nz-card [nzBordered]="false"> <form nz-form [nzLayout]="'inline'" class="search__form"> <nz-row nzGutter="8"> <nz-col nzSm="24"> <nz-form-item> <nz-form-control> <nz-input-group nzSearch [nzSuffix]="suffixSearchButton"> <input type="text" nz-input [(ngModel)]="filterText" name="filterText" [placeholder]="l('SearchWithThreeDot')"> <ng-template #suffixSearchButton> <button nz-button nzType="primary" nzSearch (click)="refresh($event)"> <i class="anticon anticon-search"></i> </button> </ng-template> </nz-input-group> </nz-form-control> </nz-form-item> </nz-col> </nz-row> <nz-row nzGutter="8" *ngIf="advancedFiltersVisible"> {{Property_Filter_Template_Here}}{{NP_Filter_Template_Here}} </nz-row> </form> <nz-row nzGutter="8"> <nz-col nzMd="20" nzSm="12"> <button nz-button [nzType]="'primary'" *ngIf="isGranted('{{Permission_Value_Here}}.Create')" (click)="createOrEdit()"> <i class="anticon anticon-plus"></i> <span> {{l("CreateNew{{Entity_Name_Here}}")}} </span> </button> <ng-container *ngIf="selectedDataItems.length > 0"> <button nz-button [nzType]="'danger'" *ngIf="isGranted('{{Permission_Value_Here}}.Delete')" (click)="batchDelete()"> <i class="anticon anticon-delete"></i> <span> Delete Selected </span> </button> </ng-container> {{Get_Excel_Button_Here}} </nz-col> <nz-col nzMd="4" nzSm="12" class="text-right"> <a (click)="advancedFiltersVisible=!advancedFiltersVisible"> {{advancedFiltersVisible ? l('HideAdvancedFilters') : l('ShowAdvancedFilters')}} <i class="anticon" [class.anticon-down]="!advancedFiltersVisible" [class.anticon-up]="advancedFiltersVisible"></i> </a> </nz-col> </nz-row> <div class="my-md"> <nz-alert [nzType]="'info'" [nzShowIcon]="true" [nzMessage]="message"> <ng-template #message> <span> <strong class="text-primary">{{selectedDataItems.length}}</strong> items selected </span> <a (click)="restCheckStatus(dataList)" class="ml-md" *ngIf="selectedDataItems.length>0"> {{l('Clear')}} </a> <nz-divider nzType="vertical"></nz-divider> <a (click)="refresh()"> {{l('Refresh')}} </a> </ng-template> </nz-alert> </div> <nz-row class="my-md"> <nz-table #ajaxTable [nzData]="dataList" [nzTotal]="totalItems" [(nzPageIndex)]="pageNumber" [(nzPageSize)]="pageSize" [nzLoading]="isTableLoading" (nzPageIndexChange)="pageNumberChange()" (nzPageSizeChange)="refresh()" [nzShowSizeChanger]="true" [nzShowQuickJumper]="true" [nzNoResult]="noDataTemplate" [nzShowTotal]="totalTemplate" [nzFrontPagination]="false" [nzScroll]="{x: 'auto'}"> <ng-template #noDataTemplate> <no-data></no-data> </ng-template> <ng-template #totalTemplate let-total> {{l('TotalRecordsCount', total)}} </ng-template> <thead (nzSortChange)="gridSort($event)"> <tr> <th nzShowCheckbox [(nzChecked)]="allChecked" [nzDisabled]="allCheckboxDisabled" [nzIndeterminate]="checkboxIndeterminate" (nzCheckedChange)="checkAll($event)" nzWidth="60px"></th> {{NP_Looped_Header_Template_Here}}{{Property_Looped_Header_Template_Here}} <th class="text-center" [hidden]="!isGrantedAny('{{Permission_Value_Here}}.Edit', '{{Permission_Value_Here}}.Delete')"> <span>{{l('Actions')}}</span> </th> </tr> </thead> <tbody> <tr *ngFor="let item of ajaxTable.data"> <td nzShowCheckbox [(nzChecked)]="item.checked" (nzCheckedChange)="refreshCheckStatus(dataList)"></td> {{NP_Looped_Template_Here}}{{Property_Looped_Template_Here}} <td> {{View_Button_Here}} <ng-container *ngIf="isGranted('{{Permission_Value_Here}}.Edit')"> <a (click)="createOrEdit(item.{{entity_Name_Here}}.id)"> <i nz-icon type="edit"></i> {{l('Edit')}} </a> <nz-divider nzType="vertical"></nz-divider> </ng-container> <ng-container *ngIf="isGranted('{{Permission_Value_Here}}.Delete')"> <nz-popconfirm [nzTitle]="l('{{Entity_Name_Here}}DeleteWarningMessage', '')" (nzOnConfirm)="delete{{Entity_Name_Here}}(item.{{entity_Name_Here}})" [nzOkText]="l('Ok')" [nzCancelText]="l('Cancel')"> <a nz-popconfirm> <i nz-icon type="delete"></i> {{l('Delete')}} </a> </nz-popconfirm> </ng-container> </td> </tr> </tbody> </nz-table> </nz-row> </nz-card>
PartialTemplates.txt的內容:
{ "propertyTemplates":[ { "placeholder" : "{{Property_Looped_Header_Template_Here}}", "condition" : "{{Property_Listed_Here}} == true", "templates" : [ { "type" : "default", "content" : " <th nzShowSort nzSortKey=\"{{entity_Name_Here}}.{{property_Name_Here}}\"> {{l('{{Property_Name_Here}}')}} </th> " } ] }, { "placeholder" : "{{Property_Looped_Template_Here}}", "condition" : "{{Property_Listed_Here}} == true", "templates" : [ { "type" : "enum", "content" : " <td> {{l('Enum_{{Property_Type_Here}}' + {{property_Type_Here}}[item.{{entity_Name_Here}}.{{property_Name_Here}}])}} </td>" }, { "type" : "bool", "content" : " <td class=\"text-center\"> <span class=\"badge badge-success\" *ngIf=\"item.{{entity_Name_Here}}.{{property_Name_Here}}\">{{l('Yes')}}</span> <span class=\"badge badge-error\" *ngIf=\"!item.{{entity_Name_Here}}.{{property_Name_Here}}\">{{l('No')}}</span> </td>" }, { "type" : "DateTime", "content" : " <td class=\"text-center\"> {{item.{{entity_Name_Here}}.{{property_Name_Here}} | momentFormat:\'L\'}} </td>" }, { "type" : "default", "content" : " <td> {{item.{{entity_Name_Here}}.{{property_Name_Here}}}} </td>" } ] }, { "placeholder" : "{{Property_Filter_Template_Here}}", "condition" : "{{Property_Advanced_Filter_Here}} == true", "templates" : [ { "type" : "enum", "content" : " <nz-col nzSm=\"6\"> <nz-form-item> <nz-form-label for=\"{{Property_Name_Here}}FilterSelect\"> {{l(\"{{Property_Name_Here}}\")}} </nz-form-label> <nz-form-control> <nz-select [(ngModel)]=\"{{property_Name_Here}}Filter\" name=\"{{Property_Name_Here}}Filter\" id=\"{{Property_Name_Here}}FilterSelect\" nzAllowClear> <nz-option [nzLabel]=\"l('All')\" nzValue=\"-1\"></nz-option> {{Enum_Option_Looped_Template_Here}} </nz-select> </nz-form-control> </nz-form-item> </nz-col>" }, { "type" : "bool", "content" : " <nz-col nzSm=\"6\"> <nz-form-item> <nz-form-label for=\"{{Property_Name_Here}}FilterSelect\"> {{l(\"{{Property_Name_Here}}\")}} </nz-form-label> <nz-form-control> <nz-select [(ngModel)]=\"{{property_Name_Here}}Filter\" name=\"{{Property_Name_Here}}Filter\" id=\"{{Property_Name_Here}}FilterSelect\" nzAllowClear> <nz-option [nzLabel]=\"l('All')\" nzValue=\"-1\"></nz-option> <nz-option [nzLabel]=\"l('False')\" nzValue=\"0\"></nz-option> <nz-option [nzLabel]=\"l('True')\" nzValue=\"1\"></nz-option> </nz-select> </nz-form-control> </nz-form-item> </nz-col>" }, { "type" : "DateTime", "content" : " <nz-col nzSm=\"6\"> <nz-form-item> <nz-form-label nzFor=\"{{Property_Name_Here}}Filter\"> {{l(\"{{Property_Name_Here}}\")}} </nz-form-label> <nz-form-control> <range-picker name=\"{{property_Name_Here}}Filter\" id=\"{{Property_Name_Here}}Filter\" [(ngModel)]=\"min{{Property_Name_Here}}Filter\" [(ngModelEnd)]=\"max{{Property_Name_Here}}Filter\" [nzPlaceHolder]=\"[l('StartDateTime'),l('EndDateTime')]\"></range-picker> </nz-form-control> </nz-form-item> </nz-col>" }, { "type" : "numeric", "content" : " <nz-col nzSm=\"6\"> <nz-form-item> <nz-form-label nzFor=\"Min{{Property_Name_Here}}Filter\"> {{l(\"{{Property_Name_Here}}\")}} </nz-form-label> <nz-form-control> <nz-input-number id=\"Min{{Property_Name_Here}}Filter\" name=\"min{{Property_Name_Here}}Filter\" [(ngModel)]=\"min{{Property_Name_Here}}Filter\" [nzPlaceHolder]=\"{{l('MinValue')}}\"></nz-input-number> <nz-input-number id=\"Max{{Property_Name_Here}}Filter\" name=\"max{{Property_Name_Here}}Filter\" [(ngModel)]=\"max{{Property_Name_Here}}Filter\" [nzPlaceHolder]=\"{{l('MaxValue')}}\"></nz-input-number> </nz-form-control> </nz-form-item> </nz-col>" }, { "type" : "default", "content" : " <nz-col nzSm=\"6\"> <nz-form-item> <nz-form-label nzFor=\"{{Property_Name_Here}}Filter\"> {{l(\"{{Property_Name_Here}}\")}} </nz-form-label> <nz-form-control> <input nz-input id=\"{{Property_Name_Here}}Filter\" name=\"{{property_Name_Here}}Filter\" [(ngModel)]=\"{{property_Name_Here}}Filter\"> </nz-form-control> </nz-form-item> </nz-col>" } ] } ], "navigationPropertyTemplates":[ { "placeholder" : "{{NP_Looped_Header_Template_Here}}", "templates" : [ { "relation" : "single", "content" : " <th nzShowSort nzSortKey=\"{{nP_Foreign_Entity_Name_Here}}{{NP_Display_Property_Name_Here}}{{NP_Duplication_Number_Here}}\"> {{l('{{NP_Display_Property_Name_Here}}')}} </th> " } ] }, { "placeholder" : "{{NP_Looped_Template_Here}}", "templates" : [ { "relation" : "single", "content" : " <td> {{item.{{nP_Foreign_Entity_Name_Here}}{{NP_Display_Property_Name_Here}}{{NP_Duplication_Number_Here}}}} </td>" } ] }, { "placeholder" : "{{NP_Filter_Template_Here}}", "templates" : [ { "relation" : "single", "content" : " <nz-col nzSm=\"6\"> <nz-form-item> <nz-form-label nzFor=\"{{NP_Foreign_Entity_Name_Here}}{{NP_Display_Property_Name_Here}}{{NP_Duplication_Number_Here}}Filter\"> ({{l(\"{{NP_Foreign_Entity_Name_Here}}{{NP_Duplication_Number_Here}}\")}}) {{l(\"{{NP_Display_Property_Name_Here}}\")}} </nz-form-label> <nz-form-control> <input nz-input id=\"{{NP_Foreign_Entity_Name_Here}}{{NP_Display_Property_Name_Here}}{{NP_Duplication_Number_Here}}Filter\" name=\"{{nP_Foreign_Entity_Name_Here}}{{NP_Display_Property_Name_Here}}{{NP_Duplication_Number_Here}}Filter\" [(ngModel)]=\"{{nP_Foreign_Entity_Name_Here}}{{NP_Display_Property_Name_Here}}{{NP_Duplication_Number_Here}}Filter\"> </nz-form-control> </nz-form-item> </nz-col>" } ] } ], "enumTemplates":[ { "placeholder" : "{{Enum_Option_Looped_Template_Here}}", "content" : " <nz-option [nzLabel]=\"l('Enum_{{Enum_Name_Here}}_{{Enum_Property_Value_Here}}')\" nzValue=\"{{Enum_Property_Value_Here}}\"></nz-option>" } ], "conditionalTemplates":[ { "placeholder": "{{View_Button_Here}}", "condition": "{{Create_View_Only_Here}} == true", "content": " <ng-container> <a (click)=\"view{{Entity_Name_Here}}(item.id)\"> <i nz-icon type=\"search\"></i> {{l('View')}} </a> <nz-divider nzType=\"vertical\"></nz-divider> </ng-container>" }, { "placeholder": "{{Get_Excel_Button_Here}}", "condition": "{{Create_Excel_Export_Here}} == true", "content": "<button nz-button nzType=\"default\" (click)=\"exportToExcel()\"><i nz-icon type=\"file-excel\"></i><span>{{l('ExportToExcel')}}</span></button>" } ] }
TemplateInfo.txt的內容:
{ "path" : "app\\{{menu_Position_Here}}\\{{namespace_Relative_Here}}\\{{entity_Name_Plural_Here}}\\{{entity_Name_Plural_Here}}.component.html", "condition": "true" }
建立列表顯示的typescript檔案:
ts模板目錄我們直接使用已有的模板目錄ComponentTemplate, 這裡需要注意如需要修改預設的模板檔案內容,必須複製該檔案並重命名成.custom.txt。比如複製MainTemplate.txt為MainTemplate.custom.txt,之後在MainTemplate.custom.txt新增你自己的模板內容。
修改後的MainTemplate.custom.txt內容:
import { Component, Injector } from '@angular/core'; import { {{Entity_Name_Plural_Here}}ServiceProxy, {{Entity_Name_Here}}Dto {{Enum_Import_Here}}, Get{{Entity_Name_Here}}ForView } from '@shared/service-proxies/service-proxies'; import { PagedListingComponentBase, PagedRequestDto } from '@shared/common/paged-listing-component-base'; import { CreateOrEdit{{Entity_Name_Here}}ModalComponent } from './create-or-edit-{{entity_Name_Here}}-modal.component';{{View_Component_Import_Here}} {{View_Component_Import_Here}} import { FileDownloadService } from '@shared/utils/file-download.service'; import { finalize } from 'rxjs/operators'; import * as moment from 'moment'; import * as _ from 'lodash'; @Component({ templateUrl: './{{entity_Name_Plural_Here}}.component.html' }) export class {{Entity_Name_Plural_Here}}Component extends PagedListingComponentBase<Get{{Entity_Name_Here}}ForView> { advancedFiltersAreShown = false; filterText = ''; {{Property_Filter_Def_Here}}{{NP_Filter_Def_Here}} {{enum_Def_Here}} constructor( injector: Injector, private _{{entity_Name_Plural_Here}}ServiceProxy: {{Entity_Name_Plural_Here}}ServiceProxy, private _fileDownloadService: FileDownloadService ) { super(injector); } protected fetchDataList(request: PagedRequestDto, pageNumber: number, finishedCallback: () => void): void { this._{{entity_Name_Plural_Here}}ServiceProxy .getAll( this.filterText,{{Property_Filter_Param_Here}}{{NP_Filter_Param_Here}} request.sorting, request.skipCount, request.maxResultCount ) .pipe(finalize(finishedCallback)) .subscribe(result => { this.dataList = result.items; this.showPaging(result); }); } createOrEdit(id?: number): void { this.modalHelper .createStatic(CreateOrEdit{{Entity_Name_Here}}ModalComponent, { {{entity_Name_Here}}Id: id }, { size: 'md' }) .subscribe(res => { if (res) { this.refresh(); } }); } delete{{Entity_Name_Here}}({{entity_Name_Here}}: {{Entity_Name_Here}}Dto): void { this._{{entity_Name_Plural_Here}}ServiceProxy.delete({{entity_Name_Here}}.id) .subscribe(() => { this.refresh(); this.notify.success(this.l('SuccessfullyDeleted')); }); } {{Get_View_Component_Method_Here}} {{Get_Excel_Method_Here}} }
PartialTemplates.custom.txt內容:
{ "propertyTemplates":[ { "placeholder" : "{{Property_Filter_Def_Here}}", "condition" : "{{Property_Advanced_Filter_Here}} == true", "templates" : [ { "type" : "enum", "content" : "{{property_Name_Here}}Filter = -1; " }, { "type" : "byte", "content" : "max{{Property_Name_Here}}Filter : string = ''; min{{Property_Name_Here}}Filter : string = ''; " }, { "type" : "numeric", "content" : "max{{Property_Name_Here}}Filter : number; max{{Property_Name_Here}}FilterEmpty : number; min{{Property_Name_Here}}Filter : number; min{{Property_Name_Here}}FilterEmpty : number; " }, { "type" : "DateTime", "content" : "max{{Property_Name_Here}}Filter : moment.Moment; min{{Property_Name_Here}}Filter : moment.Moment; " }, { "type" : "bool", "content" : "{{property_Name_Here}}Filter = -1; " }, { "type" : "default", "content" : "{{property_Name_Here}}Filter = ''; " } ] }, { "placeholder" : "{{Property_Filter_Param_Here}}", "condition" : "{{Property_Advanced_Filter_Here}} == true", "templates" : [ { "type" : "byte", "content" : " this.max{{Property_Name_Here}}Filter == null ? '' : this.max{{Property_Name_Here}}Filter, this.min{{Property_Name_Here}}Filter == null ? '' : this.min{{Property_Name_Here}}Filter," }, { "type" : "numeric", "content" : " this.max{{Property_Name_Here}}Filter == null ? this.max{{Property_Name_Here}}FilterEmpty: this.max{{Property_Name_Here}}Filter, this.min{{Property_Name_Here}}Filter == null ? this.min{{Property_Name_Here}}FilterEmpty: this.min{{Property_Name_Here}}Filter," }, { "type" : "DateTime", "content" : " this.max{{Property_Name_Here}}Filter, this.min{{Property_Name_Here}}Filter," }, { "type" : "default", "content" : " this.{{property_Name_Here}}Filter," } ] } ], "navigationPropertyTemplates":[ { "placeholder" : "{{NP_Filter_Def_Here}}", "templates" : [ { "relation" : "single", "content" : "{{nP_Foreign_Entity_Name_Here}}{{NP_Display_Property_Name_Here}}{{NP_Duplication_Number_Here}}Filter = ''; " } ] }, { "placeholder" : "{{NP_Filter_Param_Here}}", "templates" : [ { "relation" : "single", "content" : " this.{{nP_Foreign_Entity_Name_Here}}{{NP_Display_Property_Name_Here}}{{NP_Duplication_Number_Here}}Filter," } ] } ], "enumTemplates":[ { "placeholder" : "{{Enum_Import_Here}}", "content" : ", {{Entity_Name_Here}}Dto{{Enum_Used_For_Property_Name_Here}}" }, { "placeholder" : "{{enum_Def_Here}}", "content" : "{{enum_Name_Here}} = {{Entity_Name_Here}}Dto{{Enum_Used_For_Property_Name_Here}}; " } ], "conditionalTemplates":[ { "placeholder": "{{View_Component_Import_Here}}", "condition": "{{Create_View_Only_Here}} == true", "content": " import { View{{Entity_Name_Here}}ModalComponent } from './view-{{entity_Name_Here}}-modal.component';" }, { "placeholder": "{{Get_Excel_Method_Here}}", "condition": "{{Create_Excel_Export_Here}} == true", "content": "exportToExcel(): void { this._{{entity_Name_Plural_Here}}ServiceProxy.get{{Entity_Name_Plural_Here}}ToExcel( this.filterText,{{Property_Filter_Param_Here}}{{NP_Filter_Param_Here}} ) .subscribe(result => { this._fileDownloadService.downloadTempFile(result); }); }" }, { "placeholder": "{{Get_View_Component_Method_Here}}", "condition": "{{Create_View_Only_Here}} == true", "content": "view{{Entity_Name_Here}}(id): void { this.modalHelper .create(View{{Entity_Name_Here}}ModalComponent, { {{entity_Name_Here}}Id: id }, { size: 'md' }) .subscribe(() => { }); }" } ] }
按照上述過程修改其他模板目錄中的內容即可使用程式碼生成器按照你的模板進行程式碼生成。
在我的專案裡已經包含了修改好的模板檔案,請自行檢視。
專案地址: https://github.com/rqx110/abp-ng-zorro
覺得還可以,請不要吝嗇你的 Star 。
使用
我們來簡單測試下生成:

這裡注意到幾個帶“Customized”的就是我們將預設模板自定義後的結果。
再來看一個生成後的ts檔案,可以和上面的模板檔案進行對比:
import { Component, Injector } from '@angular/core'; import { BooksServiceProxy, BookDto , GetBookForView } from '@shared/service-proxies/service-proxies'; import { PagedListingComponentBase, PagedRequestDto } from '@shared/common/paged-listing-component-base'; import { CreateOrEditBookModalComponent } from './create-or-edit-book-modal.component'; import { ViewBookModalComponent } from './view-book-modal.component'; import { ViewBookModalComponent } from './view-book-modal.component'; import { FileDownloadService } from '@shared/utils/file-download.service'; import { finalize } from 'rxjs/operators'; import * as moment from 'moment'; import * as _ from 'lodash'; @Component({ templateUrl: './books.component.html' }) export class BooksComponent extends PagedListingComponentBase<GetBookForView> { advancedFiltersAreShown = false; filterText = ''; nameFilter = ''; authorFilter = ''; constructor( injector: Injector, private _booksServiceProxy: BooksServiceProxy, private _fileDownloadService: FileDownloadService ) { super(injector); } protected fetchDataList(request: PagedRequestDto, pageNumber: number, finishedCallback: () => void): void { this._booksServiceProxy .getAll( this.filterText, this.nameFilter, this.authorFilter, request.sorting, request.skipCount, request.maxResultCount ) .pipe(finalize(finishedCallback)) .subscribe(result => { this.dataList = result.items; this.showPaging(result); }); } createOrEdit(id?: number): void { this.modalHelper .createStatic(CreateOrEditBookModalComponent, { bookId: id }, { size: 'md' }) .subscribe(res => { if (res) { this.refresh(); } }); } deleteBook(book: BookDto): void { this._booksServiceProxy.delete(book.id) .subscribe(() => { this.refresh(); this.notify.success(this.l('SuccessfullyDeleted')); }); } viewBook(id): void { this.modalHelper .create(ViewBookModalComponent, { bookId: id }, { size: 'md' }) .subscribe(() => { }); } exportToExcel(): void { this._booksServiceProxy.getBooksToExcel( this.filterText, this.nameFilter, this.authorFilter, ) .subscribe(result => { this._fileDownloadService.downloadTempFile(result); }); } }
結束
ASP.NET Zero Power Tools是一個商業產品,你必須購買才能使用。當然你也可以動(po)手(jie)來使用。比如:
