上一篇介绍了集成ng-zorro的过程,本篇我们来看下如何用abp官方的生成器来生成前端代码。

Abp官方提供了一个强大的代码生成器 ASP.NET Zero Power Tools,它的Visual Studio 插件在这里。当然你也可以不用插件,但你得自己创建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"即可。我们需要禁用ComponentTurboTableHtmlTemplateLookupTables\LookupTableComponentTurboTableHtmlTemplateLookupTables\LookupTableCssTemplate这几个文件夹。

以下我们创建一个列表显示页的html模板页:

  1. 创建模板目录ComponentNgZorroTableHtmlTemplate
  2. 创建模板三个文件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);
});
}
}

Update (20190426)

生成完成后,在你的adminModule或mainModule里可能会默认生成了一些primeNG的东西,请手动删除。并且请把createOrEdit***ModalComponent加入到module的entryComponents中。

结束

ASP.NET Zero Power Tools是一个商业产品,你必须购买才能使用。

基于ng-zorro的ASP.NET ZERO前端实现之代码生成器的更多相关文章

  1. 基于ng-zorro的ASP.NET ZERO前端实现

    Abp官方提供的企业版(ASP.NET ZERO)[以下简称Zero]模板中前端使用的是Metronic,本篇博客介绍使用ng-zorro和ng-alain替换官方前端,以及使用官方生成器自动生成代码 ...

  2. 基于Microsoft Azure、ASP.NET Core和Docker的博客系统

    欢迎阅读daxnet的新博客:一个基于Microsoft Azure.ASP.NET Core和Docker的博客系统   2008年11月,我在博客园开通了个人帐号,并在博客园发表了自己的第一篇博客 ...

  3. 基于DDD的现代ASP.NET开发框架--ABP系列之3、ABP分层架构

    基于DDD的现代ASP.NET开发框架--ABP系列之3.ABP分层架构 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:ht ...

  4. 一种基于自定义代码的asp.net网站首页根据IP自动跳转指定页面的方法!

    一种基于自定义代码的asp.net网站首页根据IP自动跳转指定页面的方法! 对于大中型网站,为了增强用户体验,往往需要根据不同城市站点的用户推送或展现相应个性化的内容,如对于一些大型门户网站的新闻会有 ...

  5. 基于HBuilderX+UniApp+ThorUI的手机端前端开发处理

    现在的很多程序应用,基本上都是需要多端覆盖,因此基于一个Web API的后端接口,来构建多端应用,如微信.H5.APP.WInForm.BS的Web管理端等都是常见的应用.本篇随笔概括性的介绍基于HB ...

  6. FineUI 基于 ExtJS 的专业 ASP.NET 控件库

    FineUI 基于 ExtJS 的专业 ASP.NET 控件库 http://www.fineui.com/

  7. 基于微软平台IIS/ASP.NET开发的大型网站有哪些呢?

    首先说明一下,本文绝不是要说Microsoft平台多么好,多么牛.只是要提醒一些LAMP/JAVA平台下的同志们,微软平台不至于像你们说的,和想象的那么不堪!只是你们自己不知道而已.同时,也希望广大M ...

  8. 基于微软平台IIS/ASP.NET开发的大型网站有哪些?

    首先说明一下,本文绝不是要说Microsoft平台多么好,多么牛.只是要提醒一些LAMP/Java平台下的同志们,微软平台不至于像你们说的,和想象的那么不堪!只是你们自己不知道而已.同时,也希望广大M ...

  9. 基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程

    基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boi ...

随机推荐

  1. Qt中由表中单元格的QModelIndex获取Global Pos的正确方法

    一直在尝试从单元格的行列索引(QModelIndex)获取其单元格的全局坐标(Global Pos)的方法,以期待在指定单元格附近弹出帮助信息.由View中的columnViewportPositio ...

  2. 【图文】[新手]C++ 动态库导出函数名“乱码”及解决

    刚接触C++,在尝试从 dll 中导出函数时,发现导出的函数名都"乱码"了. 导出过程如下: 新建一个Win32项目: 新建的解决方案里有几个导出的示例: // 下列 ifdef ...

  3. EF 6.0 Code First 迁移MySql数据库

    一.准备工作     使用NUGET安装Entity Framework 6,下载MySql Connector/Net 6.9.5   二.创建实体     我们在下面创建了两个类(博客和文章),并 ...

  4. DNS之主服务器正向区域部署流程

    正向区域:将域名解析为IP 搭建步骤 1)定义区域 2)编写区域解析库文件 3)添加记录 环境介绍 [root@dns ~]# cat /etc/centos-releaseCentOS releas ...

  5. Django之forms组件进阶

    Django Form表单组件   Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要 ...

  6. HBase —— 单机环境搭建

    一.安装前置条件说明 1.1 JDK版本说明 HBase 需要依赖JDK环境,同时HBase 2.0+ 以上版本不再支持JDK 1.7 ,需要安装JDK 1.8+ .JDK 安装方式见本仓库: Lin ...

  7. Scala 学习之路(一)—— Scala简介及开发环境配置

    一.Scala简介 1.1 概念 Scala全称为Scalable Language,即“可伸缩的语言”,之所以这样命名,是因为它的设计目标是希望伴随着用户的需求一起成长.Scala是一门综合了面向对 ...

  8. Spark学习之路(十五)—— Spark Streaming 整合 Flume

    一.简介 Apache Flume是一个分布式,高可用的数据收集系统,可以从不同的数据源收集数据,经过聚合后发送到分布式计算框架或者存储系统中.Spark Straming提供了以下两种方式用于Flu ...

  9. Java NIO 学习笔记(一)----概述,Channel/Buffer

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  10. 【win10家庭版】删除文件提示没有权限最简单的方式(已验证)

    趁着618入了新本本,预装了家庭普通版Win10,但是实际使用中遇到了一些问题.问题不大,但是着实反人类,在此吐槽! 问题: 首先,进入系统会提示你建一个账号,建立完成登录系统.本账户拥有Admini ...