# Convert Create/Edit Modals to Page In this document we will explain how to convert BookStore's Books create & edit modals to regular blazor pages. ## Before ![bookstore-crud-before](images/old.gif) ## After ![bookstore-crud-after](images/new.gif) # Books.razor Page Books.razor page is the main page of the books management. Create & Update operations are done in this page. So we'll remove create & update operations from this page and move a separate blazor component for each operation. Each component will be a page. - Remove both Create & Update modals. ![remove-all-modals](images/books-remove-modals.png) - Replace **NewBook** button with a link to **CreateBook** page. ```html ``` - Inject `NavigationManager` to `Books.razor` page. ```csharp @inject NavigationManager NavigationManager ``` - Replace **Edit** button with a link to **UpdateBook** page. ```html ``` ```csharp private void NavigateToEdit(Guid id) { NavigationManager.NavigateTo($"books/{id}/edit"); } ``` - Remove all methods in the `Books.razor` page except constructor. And add `GoToEditPage` as below: ```csharp protected void GoToEditPage(BookDto book) { NavigationManager.NavigateTo($"books/{book.Id}"); } ``` ![bookstore-remove-methods](images/books-remove-methods.png) - Change Edit button to a link in the table. ```html ``` # CreateBooks Page Create new `CreateBook.razor` and `CreateBook.razor.cs` files in your project. - `CreateBook.razor` ```html @page "/books/new" @attribute [Authorize(BookStorePermissions.Books.Create)] @inherits BookStoreComponentBase @using Acme.BookStore.Books; @using Acme.BookStore.Localization; @using Acme.BookStore.Permissions; @using Microsoft.Extensions.Localization; @using Volo.Abp.AspNetCore.Components.Web; @inject IStringLocalizer L @inject AbpBlazorMessageLocalizerHelper LH @inject IBookAppService AppService @inject NavigationManager NavigationManager @L["NewBook"] @L["Author"] @L["Name"] @L["Type"] @L["PublishDate"] @L["Price"] ``` - `CreateBook.razor.cs` ```csharp using Acme.BookStore.Books; using Blazorise; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Volo.Abp; namespace Acme.BookStore.Blazor.Pages; public partial class CreateBook { protected Validations CreateValidationsRef; protected CreateUpdateBookDto NewEntity = new(); IReadOnlyList authorList = Array.Empty(); protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); authorList = (await AppService.GetAuthorLookupAsync()).Items; if (!authorList.Any()) { throw new UserFriendlyException(message: L["AnAuthorIsRequiredForCreatingBook"]); } NewEntity.AuthorId = authorList.First().Id; if (CreateValidationsRef != null) { await CreateValidationsRef.ClearAll(); } } protected virtual async Task CreateEntityAsync() { try { var validate = true; if (CreateValidationsRef != null) { validate = await CreateValidationsRef.ValidateAll(); } if (validate) { await AppService.CreateAsync(NewEntity); NavigationManager.NavigateTo("books"); } } catch (Exception ex) { await HandleErrorAsync(ex); } } } ``` # EditBooks Page Create new `EditBook.razor` and `EditBook.razor.cs` files in your project. - `EditBook.razor` ```html @page "/books/{Id}" @attribute [Authorize(BookStorePermissions.Books.Edit)] @inherits BookStoreComponentBase @using Acme.BookStore.Books; @using Acme.BookStore.Localization; @using Acme.BookStore.Permissions; @using Microsoft.Extensions.Localization; @using Volo.Abp.AspNetCore.Components.Web; @inject IStringLocalizer L @inject AbpBlazorMessageLocalizerHelper LH @inject IBookAppService AppService @inject NavigationManager NavigationManager @EditingEntity.Name @L["Author"] @L["Name"] @L["Type"] @L["PublishDate"] @L["Price"] ``` - `EditBook.razor.cs` ```csharp using Acme.BookStore.Books; using Blazorise; using Microsoft.AspNetCore.Components; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Volo.Abp; namespace Acme.BookStore.Blazor.Pages; public partial class EditBook { protected CreateUpdateBookDto EditingEntity = new(); protected Validations EditValidationsRef; IReadOnlyList authorList = Array.Empty(); [Parameter] public string Id { get; set; } public Guid EditingEntityId { get; set; } protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); // Blazor can't parse Guid as route constraint currently. // See https://github.com/dotnet/aspnetcore/issues/19008 EditingEntityId = Guid.Parse(Id); authorList = (await AppService.GetAuthorLookupAsync()).Items; if (!authorList.Any()) { throw new UserFriendlyException(message: L["AnAuthorIsRequiredForCreatingBook"]); } var entityDto = await AppService.GetAsync(EditingEntityId); EditingEntity = ObjectMapper.Map(entityDto); if (EditValidationsRef != null) { await EditValidationsRef.ClearAll(); } } protected virtual async Task UpdateEntityAsync() { try { var validate = true; if (EditValidationsRef != null) { validate = await EditValidationsRef.ValidateAll(); } if (validate) { await AppService.UpdateAsync(EditingEntityId, EditingEntity); NavigationManager.NavigateTo("books"); } } catch (Exception ex) { await HandleErrorAsync(ex); } } } ``` You can check the following commit for details: https://github.com/abpframework/abp-samples/commit/aae61ad6d66ebf6191dd4dcfb4e23d30bd680a4e