适用Zero版本:ASP.NET Core & Angular 2+ (aspnet-zero-core-3.1.0)。

该版本官方有两个solution文件夹:Angular(前端) 和 aspnet-core(后台服务)。

在开始以下步骤之前需要能够成功发布程序,对于后台服务只要能运行即可,如有报错可根据提示安装需要的插件。Angular 则比较麻烦,装的东西较多,官方建议用yarn,这个要下载,顺藤摸瓜都安装完即可。

我没有改解决方案名称,仍用的默认solution的名称MyCompanyName.AbpZeroTemplate,所以下面有的文件名跟官网的phonebook示例文档有区别。

修改1版将aspnet-core后台服务project和Angular前端project的步骤分类,这样不需要跳跃性的操作,阅读操作效率更高。本文仅谈实操,不详细解释理论性的东西,因为本文观点认为,实操没问题了,初学者的信心就有了,理解仅仅是时间问题。

一、aspnet-core后台Project步骤如下:

1、 src/***.core/***CoreModule.cs文件中临时禁用多租户。

  1. [DependsOn(typeof(AbpZeroCoreModule))]
  2. public class PhoneBookCoreModule : AbpModule
  3. {
  4. public override void PreInitialize()
  5. {
  6. //some other code...
  7.  
  8. //Enable this line to create a multi-tenant application.
  9. Configuration.MultiTenancy.IsEnabled = false;
  10.  
  11. //some other code...
  12. }
  13. }

2、src/***.core/Localization/AbpZeroTemplate/AbpZeroTemplate.xml (默认的英文字体)中加入代码。如有对应中文,可在对应的中文文件中加入中文名称。其他语言中没加的都默认用英文的。

  1. <text name="PhoneBook">Phone Book</text>
  1.  

3、创建实体类person。在.Core内新建文件夹People,然后在People文件夹内新建如下Person.cs类。

  1. using System.ComponentModel.DataAnnotations;
  2. using System.ComponentModel.DataAnnotations.Schema;
  3. using Abp.Domain.Entities.Auditing;
  4.  
  5. namespace Acme.PhoneBook.People
  6. {
  7. [Table("PbPersons")]
  8. public class Person : FullAuditedEntity
  9. {
  10. public const int MaxNameLength = 32;
  11. public const int MaxSurnameLength = 32;
  12. public const int MaxEmailAddressLength = 255;
  13.  
  14. [Required]
  15. [MaxLength(MaxNameLength)]
  16. public virtual string Name { get; set; }
  17.  
  18. [Required]
  19. [MaxLength(MaxSurnameLength)]
  20. public virtual string Surname { get; set; }
  21.  
  22. [MaxLength(MaxEmailAddressLength)]
  23. public virtual string EmailAddress { get; set; }
  24. }
  25. }

4、在.EntityFramework内的****DbContext.cs文件增加如下黄色标记代码。

  1. public class ******DbContext : AbpZeroDbContext<Tenant, Role, User>
  2. {
  3. public virtual IDbSet<Person> Persons { get; set; }
  4.  
  5. //...other code
  6. }

5、用EntityFramework的code first迁移功能更新数据库创建PdPersons表。

在windows command prompt 命令行工具定位到.EntityFramework文件夹。输入:“dotnet ef migrations add "Added_Persons_Table”并回车。

这会在Migrations文件夹中增加一个***Added_Persons_Table.cs类。然后在命令行中输入:“dotnet ef database update”命令,即可在数据库中生成新表。

我在执行这步的时候报错了。提示C:\Program Files\dotnet\shared\Microsoft.NETCore.App 目录里没有1.1.0版本的。原来是我没安装command line版的

.net core 1.1 sdk.官网直接下载即可下载地址:https://www.microsoft.com/net/core#windowscmd 。安装好即可成功更新数据库。

6、为新创建的PdPersons表造点初始数据。

在.EntityFramework空间内的Migrations/seed/host 内新建InitialPeopleCreator.cs类

类代码:

  1. using System.Linq;
  2. using Acme.PhoneBook.EntityFramework;
  3. using Acme.PhoneBook.People;
  4.  
  5. namespace Acme.PhoneBook.Migrations.Seed.Host
  6. {
  7. public class InitialPeopleCreator
  8. {
  9. private readonly PhoneBookDbContext _context;
  10.  
  11. public InitialPeopleCreator(PhoneBookDbContext context)
  12. {
  13. _context = context;
  14. }
  15.  
  16. public void Create()
  17. {
  18. var douglas = _context.Persons.FirstOrDefault(p => p.EmailAddress == "douglas.adams@fortytwo.com");
  19. if (douglas == null)
  20. {
  21. _context.Persons.Add(
  22. new Person
  23. {
  24. Name = "Douglas",
  25. Surname = "Adams",
  26. EmailAddress = "douglas.adams@fortytwo.com"
  27. });
  28. }
  29.  
  30. var asimov = _context.Persons.FirstOrDefault(p => p.EmailAddress == "isaac.asimov@foundation.org");
  31. if (asimov == null)
  32. {
  33. _context.Persons.Add(
  34. new Person
  35. {
  36. Name = "Isaac",
  37. Surname = "Asimov",
  38. EmailAddress = "isaac.asimov@foundation.org"
  39. });
  40. }
  41. }
  42. }
  43. }  

7、在.EntityFramework空间内的Migrations/seed/host 内的InitialHostDbBuilder.cs类里新增如下黄色标记代码。

  1. public class InitialHostDbBuilder
  2. {
  3. //existing codes...
  4.  
  5. public void Create()
  6. {
  7. //existing code...
  8. new InitialPeopleCreator(_context).Create();
  9.  
  10. _context.SaveChanges();
  11. }
  12. }

然后在命令行中执行代码:“dotnet ef database update ” 即可。查看PdPersons表里已有数据。

8、创建person应用程序服务-----------新建一个接口类。

应用程序服务对应.Application空间,在MyCompanyName.AbpZeroTemplate.Application下面建立文件夹People。

然后在People文件夹中新建IPersonAppService.cs接口类.代码如下:

  1. using Abp.Application.Services;
  2. using Abp.Application.Services.Dto;
  3.  
  4. namespace Acme.PhoneBook.People
  5. {
  6. public interface IPersonAppService : IApplicationService
  7. {
  8. ListResultDto<PersonListDto> GetPeople(GetPeopleInput input);
  9. }
  10. }
  1.  

9、在People文件夹下面再建立一个文件夹Dto,然后在此新建PersonListDto.cs文件。代码如下:

  1. using Abp.Application.Services.Dto;
  2. using Abp.AutoMapper;
  3.  
  4. namespace MyCompanyName.AbpZeroTemplate.People.Dto
  5. {
  6. [AutoMapFrom(typeof(Person))]
  7. public class PersonListDto : FullAuditedEntityDto
  8. {
  9. public string Name { get; set; }
  10.  
  11. public string Surname { get; set; }
  12.  
  13. public string EmailAddress { get; set; }
  14.  
  15. }
  16.  
  17. public class GetPeopleInput
  18. {
  19. public string Filter { get; set; }
  20. }
  21.  
  22. }

10、在Pepole文件夹下再建立一个PersonAppService.cs文件。代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Abp.Application.Services.Dto;
  6. using Abp.AutoMapper;
  7. using Abp.Domain.Repositories;
  8. using Abp.Extensions;
  9. using Abp.Linq.Extensions;
  10. using MyCompanyName.AbpZeroTemplate.People.Dto;
  11.  
  12. namespace MyCompanyName.AbpZeroTemplate.People
  13. {
  14. public class PersonAppService:AbpZeroTemplateAppServiceBase,IPersonAppService
  15. {
  16. private readonly IRepository<Person> _personRepository;
  17.  
  18. public PersonAppService(IRepository<Person> personRepository)
  19. {
  20. _personRepository = personRepository;
  21. }
  22.  
  23. public async Task CreatePerson(CreatePersonInput input)
  24. {
  25. var person = input.MapTo<Person>();
  26. await _personRepository.InsertAsync(person);
  27. }
  28.  
  29. public ListResultDto<PersonListDto> GetPeople(GetPeopleInput input)
  30. {
  31. var persons = _personRepository
  32. .GetAll()
  33. .WhereIf(
  34. !input.Filter.IsNullOrEmpty(),
  35. p => p.Name.Contains(input.Filter) ||
  36. p.Surname.Contains(input.Filter) ||
  37. p.EmailAddress.Contains(input.Filter)
  38. )
  39. .OrderBy(p => p.Name)
  40. .ThenBy(p => p.Surname)
  41. .ToList();
  42.  
  43. return new ListResultDto<PersonListDto>(persons.MapTo<List<PersonListDto>>());
  44. }
  45. }
  46.  
  47. }

11、增加Person。

首先再IpersonAppService.cs文件里新增如下代码:

  1. Task CreatePerson(CreatePersonInput input);

然后在Dto文件内新增类CreatePersonInput.cs类,代码如下:

  1. using Abp.AutoMapper;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel.DataAnnotations;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7.  
  8. namespace MyCompanyName.AbpZeroTemplate.People.Dto
  9. {
  10. [AutoMapTo(typeof(Person))]
  11. public class CreatePersonInput
  12. {
  13. [Required]
  14. [MaxLength(Person.MaxNameLength)]
  15. public string Name { get; set; }
  16.  
  17. [Required]
  18. [MaxLength(Person.MaxSurnameLength)]
  19. public string Surname { get; set; }
  20.  
  21. [EmailAddress]
  22. [MaxLength(Person.MaxEmailAddressLength)]
  23. public string EmailAddress { get; set; }
  24. }
  25.  
  26. }

12、允许创建person对象的授权。

首先加入允许进入phonebook页的授权。在src/***.core/Authorization/AppPermissions.cs文件中加入常量定义:

  1. public const string Pages_Tenant_PhoneBook = "Pages.Tenant.PhoneBook";

在src/MyCompanyName.AbpZeroTemplate.Application/People里的PersonAppService.cs里加入如下黄色标记代码:

  1. [AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook)]
  2. public class PersonAppService : PhoneBookAppServiceBase, IPersonAppService
  3. {
  4. //...
  5. }

在src/***.core/Authorization/AppAuthorizationProvider.cs类中定义许可,代码如下:

  1. var phoneBook = pages.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook, L("PhoneBook"), multiTenancySides: MultiTenancySides.Tenant);
  2. phoneBook.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson, L("CreateNewPerson"), multiTenancySides: MultiTenancySides.Tenant);

在同目录下的AppPermissions.cs文件中加入常量定义:

  1. public const string Pages_Tenant_PhoneBook_CreatePerson = "Pages.Tenant.PhoneBook.CreatePerson";

13、增加ABP授权属性。

在src/MyCompanyName.AbpZeroTemplate.Application/People里的PersonAppService.cs文件中增加属性标记代码如下

  1. [AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson)]
  2. public async Task CreatePerson(CreatePersonInput input)
  3. {
  4. //...
  5. }

14、删除person实体对象。

在IPersonAppService.cs文件中增加代码:

  1. Task DeletePerson(EntityDto input);

在PersonAppService.cs文件中增加代码:

  1. [AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_DeletePerson)]
  2. public async Task DeletePerson(EntityDto input)
  3. {
  4. await _personRepository.DeleteAsync(input.Id);
  5. }

另外提醒一下, 要跟创建person的权限设置一样在AppPermissions.cs文件中定义常量Pages_Tenant_PhoneBook_DeletePerson,

且在src/***.core/Authorization/AppAuthorizationProvider.cs类中定义许可,代码如下:

  1. phoneBook.DeleteChildPermission(AppPermissions.Pages_Tenant_PhoneBook_DeletePerson, L("DeletePerson"), multiTenancySides: MultiTenancySides.Tenant);

以后这类增删查改不再赘述权限功能的实现。

15、创建Phone 实体。

在src/*******.core下创建Phone.cs类代码如下

  1. [Table("PbPhones")]
  2. public class Phone : CreationAuditedEntity<long>
  3. {
  4. public const int MaxNumberLength = ;
  5.  
  6. [ForeignKey("PersonId")]
  7. public virtual Person Person { get; set; }
  8. public virtual int PersonId { get; set; }
  9.  
  10. [Required]
  11. public virtual PhoneType Type { get; set; }
  12.  
  13. [Required]
  14. [MaxLength(MaxNumberLength)]
  15. public virtual string Number { get; set; }
  16. }

16、在Person.cs中增加phones字段。

  1. [Table("PbPersons")]
  2. public class Person : FullAuditedEntity
  3. {
  4. //...other properties
  5.  
  6. public virtual ICollection<Phone> Phones { get; set; }
  7. }

17、在.core下增加PhoneType.cs类

  1. public enum PhoneType : byte
  2. {
  3. Mobile,
  4. Home,
  5. Business
  6. }

18、在Entity Framework下的AbpZeroTemplateDbContext.cs增加代码

  1. public virtual IDbSet<Phone> Phones { get; set; }

且用命令行命令:dotnet ef migrations add "Added_Phone"  增加数据库phone表的迁移类。

然后更新数据库,该部分类似操作在上文已有介绍,不赘述。

  1. 该部分未完成待续。。。

19、

20、

二、Angular前端Project步骤如下:

  1. 1、增加一个新的菜单项。app\shared\layout\side-bar.component.ts (展开side-bar.component.html文件)在dashboard下面加入如下代码
  1.   new SideBarMenuItem("PhoneBook", null, "icon-notebook", "/app/main/phonebook")

2、app\main\main-routing.module.ts  文件中加路由

{ path: 'dashboard', component: DashboardComponent, data: { permission: 'Pages.Tenant.Dashboard' } },

{ path: 'phonebook', component: PhoneBookComponent }

此时phoneBookComponent报错,先忽略不管。

3、在app/main中新建一个phonebook文件夹并创建phonebook.component.ts文件,代码如下:

  1. import { Component, Injector } from '@angular/core';
  2. import { AppComponentBase } from '@shared/common/app-component-base';
  3. import { appModuleAnimation } from '@shared/animations/routerTransition';
  4.  
  5. @Component({
  6. templateUrl: './phonebook.component.html',
  7. animations: [appModuleAnimation()]
  8. })
  9. export class PhoneBookComponent extends AppComponentBase {
  10.  
  11. constructor(
  12. injector: Injector
  13. ) {
  14. super(injector);
  15. }
  16.  
  17. }

4、解决第2步的报错问题。在main-routing.module.ts加入import代码:

  1. import { PhoneBookComponent } from './phonebook/phonebook.component';

5、在app/main/phonebook中新建 phonebook.component.html文件,代码如下:

  1. <div [@routerTransition]>
  2. <div class="row margin-bottom-5">
  3. <div class="col-xs-12">
  4. <div class="page-head">
  5. <div class="page-title">
  6. <h1>
  7. <span>{{l("PhoneBook")}}</span>
  8. </h1>
  9. </div>
  10. </div>
  11. </div>
  12. </div>
  13.  
  14. <div class="portlet light margin-bottom-0">
  15. <div class="portlet-body">
  16.  
  17. <p>PHONE BOOK CONTENT COMES HERE!</p>
  18.  
  19. </div>
  20. </div>
  21. </div>

6、在app/main/main.module.ts文件中添加下面有黄色标记的代码。

  1. import { NgModule } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { BrowserModule } from '@angular/platform-browser';
  4. import { FormsModule } from '@angular/forms';
  5.  
  6. import { ModalModule, TabsModule, TooltipModule } from 'ng2-bootstrap';
  7.  
  8. import { UtilsModule } from '@shared/utils/utils.module'
  9. import { AppCommonModule } from '@app/shared/common/app-common.module'
  10.  
  11. import { MainRoutingModule } from './main-routing.module'
  12. import { MainComponent } from './main.component'
  13. import { DashboardComponent } from './dashboard/dashboard.component';
  14. import { PhoneBookComponent } from './phonebook/phonebook.component';
  15.  
  16. @NgModule({
  17. imports: [
  18. BrowserModule,
  19. CommonModule,
  20. FormsModule,
  21.  
  22. ModalModule.forRoot(),
  23. TabsModule.forRoot(),
  24. TooltipModule.forRoot(),
  25.  
  26. UtilsModule,
  27. AppCommonModule,
  28.  
  29. MainRoutingModule
  30. ],
  31. declarations: [
  32. MainComponent,
  33. DashboardComponent,
  34. PhoneBookComponent
  35. ]
  36. })
  37. export class MainModule { }

保存后刷新前端页面点击phone book后可出来如下页面。

7、更新服务端后台服务(后台新增功能代码时执行)。 在dos命令行工具里先定位到angular所在目录路径,然后输入命令:nswag/refresh.bat 执行更新命令。

8、获取person列表。

首先在 shared/service-proxies/service-proxy.module.ts文件中的对应地方加入如下代码:

  1. ApiServiceProxies.PersonServiceProxy

修改phonebook.component.ts里的代码如下面的黄色标记处所示:

  1. import { Component, Injector, OnInit } from '@angular/core';
  2. import { AppComponentBase } from '@shared/common/app-component-base';
  3. import { appModuleAnimation } from '@shared/animations/routerTransition';
  4. import { PersonServiceProxy, PersonListDto, ListResultDtoOfPersonListDto } from '@shared/service-proxies/service-proxies';
  5.  
  6. @Component({
  7. templateUrl: './phonebook.component.html',
  8. animations: [appModuleAnimation()]
  9. })
  10. export class PhoneBookComponent extends AppComponentBase implements OnInit {
  11.  
  12. people: PersonListDto[] = [];
  13. filter: string = '';
  14.  
  15. constructor(
  16. injector: Injector,
  17. private _personService: PersonServiceProxy
  18. ) {
  19. super(injector);
  20. }
  21.  
  22. ngOnInit(): void {
  23. this.getPeople();
  24. }
  25.  
  26. getPeople(): void {
  27. this._personService.getPeople(this.filter).subscribe((result) => {
  28. this.people = result.items;
  29. });
  30. }
  31. }

再替换phonebook.component.html的 <p>PHONE BOOK CONTENT COMES HERE!</p>代码为下面的黄色标记代码:

  1. <div [@routerTransition]>
  2. <div class="row margin-bottom-5">
  3. <div class="col-xs-12">
  4. <div class="page-head">
  5. <div class="page-title">
  6. <h1>
  7. <span>{{l("PhoneBook")}}</span>
  8. </h1>
  9. </div>
  10. </div>
  11. </div>
  12. </div>
  13.  
  14. <div class="portlet light margin-bottom-0">
  15. <div class="portlet-body">
  16.  
  17. <h3>{{l("AllPeople")}}</h3>
  18.  
  19. <div class="list-group">
  20. <a *ngFor="let person of people" href="javascript:;" class="list-group-item">
  21. <h4 class="list-group-item-heading">
  22. {{person.name + ' ' + person.surname}}
  23. </h4>
  24. <p class="list-group-item-text">
  25. {{person.emailAddress}}
  26. </p>
  27. </a>
  28. </div>
  29.  
  30. </div>
  31. </div>
  32. </div>

刷新页面

9、新建一个person对象。

首先在phonebook文件夹内创建一个组件create-person-modal.component.ts文件。代码如下:

  1. import { Component, ViewChild, Injector, ElementRef, Output, EventEmitter } from '@angular/core';
  2. import { ModalDirective } from 'ng2-bootstrap';
  3. import { PersonServiceProxy, CreatePersonInput } from '@shared/service-proxies/service-proxies';
  4. import { AppComponentBase } from '@shared/common/app-component-base';
  5.  
  6. @Component({
  7. selector: 'createPersonModal',
  8. templateUrl: './create-person-modal.component.html'
  9. })
  10. export class CreatePersonModalComponent extends AppComponentBase {
  11.  
  12. @Output() modalSave: EventEmitter<any> = new EventEmitter<any>();
  13.  
  14. @ViewChild('modal') modal: ModalDirective;
  15. @ViewChild('nameInput') nameInput: ElementRef;
  16.  
  17. person: CreatePersonInput;
  18.  
  19. active: boolean = false;
  20. saving: boolean = false;
  21.  
  22. constructor(
  23. injector: Injector,
  24. private _personService: PersonServiceProxy
  25. ) {
  26. super(injector);
  27. }
  28.  
  29. show(): void {
  30. this.active = true;
  31. this.person = new CreatePersonInput();
  32. this.modal.show();
  33. }
  34.  
  35. onShown(): void {
  36. $(this.nameInput.nativeElement).focus();
  37. }
  38.  
  39. save(): void {
  40. this.saving = true;
  41. this._personService.createPerson(this.person)
  42. .finally(() => this.saving = false)
  43. .subscribe(() => {
  44. this.notify.info(this.l('SavedSuccessfully'));
  45. this.close();
  46. this.modalSave.emit(this.person);
  47. });
  48. }
  49.  
  50. close(): void {
  51. this.modal.hide();
  52. this.active = false;
  53. }
  54. }

然后创建同名的html文件 create-person-modal.component.html,代码如下:

  1. <div bsModal #modal="bs-modal" (onShown)="onShown()" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true" [config]="{backdrop: 'static'}">
  2. <div class="modal-dialog">
  3. <div class="modal-content">
  4. <form *ngIf="active" #personForm="ngForm" novalidate (ngSubmit)="save()">
  5. <div class="modal-header">
  6. <button type="button" class="close" (click)="close()" aria-label="Close">
  7. <span aria-hidden="true">&times;</span>
  8. </button>
  9. <h4 class="modal-title">
  10. <span>{{l("CreateNewPerson")}}</span>
  11. </h4>
  12. </div>
  13. <div class="modal-body">
  14.  
  15. <div class="form-group form-md-line-input form-md-floating-label no-hint">
  16. <input #nameInput class="form-control" type="text" name="name" [(ngModel)]="person.name" required maxlength="32">
  17. <label>{{l("Name")}}</label>
  18. </div>
  19.  
  20. <div class="form-group form-md-line-input form-md-floating-label no-hint">
  21. <input class="form-control" type="email" name="surname" [(ngModel)]="person.surname" required maxlength="32">
  22. <label>{{l("Surname")}}</label>
  23. </div>
  24.  
  25. <div class="form-group form-md-line-input form-md-floating-label no-hint">
  26. <input class="form-control" type="email" name="emailAddress" [(ngModel)]="person.emailAddress" required maxlength="255" pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,})+$"> <label>{{l("EmailAddress")}}</label>
  27. </div>
  28.  
  29. </div>
  30. <div class="modal-footer">
  31. <button [disabled]="saving" type="button" class="btn btn-default" (click)="close()">{{l("Cancel")}}</button>
  32. <button type="submit" class="btn btn-primary blue" [disabled]="!personForm.form.valid" [buttonBusy]="saving" [busyText]="l('SavingWithThreeDot')"><i class="fa fa-save"></i> <span>{{l("Save")}}</span></button>
  33. </div>
  34. </form>
  35. </div>
  36. </div>
  37. </div>

接着在main.module.ts类里加入如下黄色标记代码:

  1. ...previous imports
  2. import { CreatePersonModalComponent } from './phonebook/create-person-modal.component';
  3.  
  4. @NgModule({
  5. imports: [
  6. ...existing module imports...
  7. ],
  8. declarations: [
  9. MainComponent,
  10. DashboardComponent,
  11. PhoneBookComponent,
  12. CreatePersonModalComponent
  13. ]
  14. })
  15. export class MainModule { }

最后,在phonebook.component.html文件里加入如下黄色标记代码:

  1. <div [@routerTransition]>
  2. <div class="row margin-bottom-5">
  3. <div class="col-xs-6">
  4. <div class="page-head">
  5. <div class="page-title">
  6. <h1>
  7. <span>{{l("PhoneBook")}}</span>
  8. </h1>
  9. </div>
  10. </div>
  11. </div>
  12. <div class="col-xs-6 text-right">
  13. <button class="btn btn-primary blue" (click)="createPersonModal.show()"><i class="fa fa-plus"></i> {{l("CreateNewPerson")}}</button>
  14. </div>
  15. </div>
  16.  
  17. <div class="portlet light margin-bottom-0">
  18. <div class="portlet-body">
  19.  
  20. <h3>{{l("AllPeople")}}</h3>
  21.  
  22. <div class="list-group">
  23. <a *ngFor="let person of people" href="javascript:;" class="list-group-item">
  24. <h4 class="list-group-item-heading">
  25. {{person.name + ' ' + person.surname}}
  26. </h4>
  27. <p class="list-group-item-text">
  28. {{person.emailAddress}}
  29. </p>
  30. </a>
  31. </div>
  32.  
  33. </div>
  34. </div>
  35. <createPersonModal #createPersonModal (modalSave)="getPeople()"></createPersonModal>
  36. </div>

10、隐藏未授权的button按钮。

打开phonebook.component.html文件。在button处加入下面的黄色标记代码:

  1. <button *ngIf="isGranted('Pages.Tenant.PhoneBook.CreatePerson')" class="btn btn-primary blue" (click)="createPersonModal.show()"><i class="fa fa-plus"></i> {{l("CreateNewPerson")}}</button>

11、删除peson对象。

修改phonebook.component.html文件,增加如下黄色标记处代码:

  1. ...
  2. <h3>{{l("AllPeople")}}</h3>
  3.  
  4. <div class="list-group">
  5. <a *ngFor="let person of people" href="javascript:;" class="list-group-item">
  6. <h4 class="list-group-item-heading">
  7. {{person.name + ' ' + person.surname}}
  8. <button (click)="deletePerson(person)" title="{{l('Delete')}}" class="btn btn-circle btn-icon-only red delete-person" href="javascript:;">
  9. <i class="icon-trash"></i>
  10. </button>
  11. </h4>
  12. <p class="list-group-item-text">
  13. {{person.emailAddress}}
  14. </p>
  15. </a>
  16. </div>
  17. ...

12、使用LESS样式将按钮移至右边。

在phonebook文件夹下创建phonebook.component.less样式文件,代码如下:

  1. .list-group-item-heading {
  2. button.delete-person {
  3. float: right;
  4. }
  5. }

在 phonebook.component.ts 文件中引入样式文件,代码如黄色标记:

  1. @Component({
  2. templateUrl: './phonebook.component.html',
  3. styleUrls: ['./phonebook.component.less'],
  4. animations: [appModuleAnimation()]
  5. })

13、在phonebook.component.ts内添加删除功能代码:

  1. deletePerson(person: PersonListDto): void {
  2. this.message.confirm(
  3. this.l('AreYouSureToDeleteThePerson', person.name),
  4. isConfirmed => {
  5. if (isConfirmed) {
  6. this._personService.deletePerson(person.id).subscribe(() => {
  7. this.notify.info(this.l('SuccessfullyDeleted'));
  8. _.remove(this.people, person);
  9. });
  10. }
  11. }
  12. );
  13. }

并且在@Component标记前增加引入代码:

  1. import * as _ from 'lodash';

14、

15、

16、

未完待续。。。

Asp.net Zero 应用实战-官方示例PhoneBook学习1_修改1版的更多相关文章

  1. Asp.net Zero 应用实战-官方示例PhoneBook学习1

    适用Zero版本:ASP.NET Core & Angular 2+ (aspnet-zero-core-3.1.0). 该版本官方有两个solution文件夹:Angular(前端) 和 a ...

  2. gRPC官方快速上手学习笔记(c#版)

    上手前准备工作 支持操作系统:windows.OS X.Linux.实例采用.net..net core sdk. The .NET Core SDK command line tools. The ...

  3. Asp.Net Core 项目实战之权限管理系统(0) 无中生有

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  4. Asp.Net Core 项目实战之权限管理系统(6) 功能管理

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  5. 【无私分享:ASP.NET CORE 项目实战(第十四章)】图形验证码的实现

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 很长时间没有来更新博客了,一是,最近有些忙,二是,Core也是一直在摸索中,其实已经完成了一个框架了,并且正在准备在生产环境中 ...

  6. 【无私分享:ASP.NET CORE 项目实战(第十三章)】Asp.net Core 使用MyCat分布式数据库,实现读写分离

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 MyCat2.0版本很快就发布了,关于MyCat的动态和一些问题,大家可以加一下MyCat的官方QQ群:106088787.我 ...

  7. 【无私分享:ASP.NET CORE 项目实战(第十二章)】添加对SqlServer、MySql、Oracle的支持

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 增加对多数据库的支持,并不是意味着同时对多种数据库操作,当然,后面,我们会尝试同时对多种数据库操作,这可能需要多个上下文,暂且 ...

  8. 【无私分享:ASP.NET CORE 项目实战(第十一章)】Asp.net Core 缓存 MemoryCache 和 Redis

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitHub上下载了十几个源码参考, Memory 和 Redis 终于写出一个 ...

  9. 【无私分享:ASP.NET CORE 项目实战(第七章)】文件操作 FileHelper

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在程序设计中,我们很多情况下,会用到对文件的操作,在 上一个系列 中,我们有很多文件基本操作的示例,在Core中有一些改变,主 ...

随机推荐

  1. URL 传递问题

    工作日记: ----更正:如下做改成%26是不行的.正在寻求解决方法 在K2邮件发送正文中我拼接了URL如:http://shisupportqa:8090/WorkflowPages/SendFil ...

  2. drf框架之分页器的用法

    1. 分页器分为:简单分页器与偏移分页器和加密分页器 2.实现一个简单的分页器的用法: # 简单分页 # 第一步,导入分页类 # from rest_framework.pagination impo ...

  3. DEDECMS 多站用一个站图片

    function replaceurl($newurl) { $newurl=str_replace('src="/uploads/allimg/','src="xxx.com/u ...

  4. html:input的type=number的时候maxlength失效问题

    <input type="text"  maxlength="5" />   效果ok,当 <input type="number& ...

  5. VirtualBox安装Ubuntu16.04过程

    1. 软件版本 Windows: Win7/Win10 VirtualBox: VirtualBox-6.0.24-108355-Win Ubuntu: ubuntu-16.04-desktop-am ...

  6. xmlns 啥意思

    参考:https://blog.csdn.net/zhch152/article/details/8191377 前提科普:DTD 文档类型定义(Document Type Definition) 问 ...

  7. Java开发中的23种设计模式(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  8. python之全局变量与局部变量

    全局变量: -   在书写中顶格开始: -   一旦定义完毕在整个文件生效: -   在函数内如果定义了同名全局变量名,会“覆盖”掉全局变量: -   在函数中同名的变量,当在函数退出后消失,全局的同 ...

  9. contains用法

    判断List<UserInfoDto>里是否有重复的UserInfoDto,不能使用contains 例: List<UserInfoDto> list = new Array ...

  10. Java成员变量与局部变量的区别

    从语法形式上看,成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数:成员变量可以被public,private,static等修饰符所修饰,而局部变量不能被访问控制修饰符及static所 ...