Opgave: Edit and Delete Items


Dette er den 4. opgave i opgave-serien ItemRazor.
I forrige opgave blev det muligt at validere data på siden CreateItem samt at søge i Items name og filtrere Items price. I denne opgave vil vi gøre det muligt at opdatere (Edit) og slette (Delete) Items fra tabellen.

Udgangspunktet er løsningen fra opgave 3 (ItemRazorV3.zip):





Step 1 (IItemService, ItemService)
Første step er at tilføje metode-signaturerne UpdateItem(Item item) og GetItem(int id) til Interfacet IItemService og implementere metoderne i Class ItemService.

Metoden UpdateItem(Item item) skal tage et Item som argument, gennemløbe listen og finde det Item der har samme Id. Name og Price skal opdateres for det fundne Item (vi tager pt ikke højde for om Item med givne Id findes eller ej, overvej evt hvad man kunne gøre?):

public void UpdateItem(Item item)
{
if (item != null)
{
foreach (Item i in _items)
{
if (i.Id == item.Id)
{
i.Name = item.Name;
i.Price = item.Price;
}
}
}
}

Metoden GetItem(int id) skal tage et Item Id og returnere det Item der har det givne Id (metoden skal returnere null, hvis der ikke findes et Item med det givne Id).

Step 2 (EditItem)
Næste step er at oprette en ny Razer Page: EditItem i mappen Pages/Item.

 

Step 3 (EditItem.cshtml.cs)
a) Add følgende instancefield til klassen EditItemModel:

private ItemService _itemService;

Så klassen kan benytte vores service og kan anvende listen af Item objekter.


b) Add en property Item til klassen.

[BindProperty]
public Models.Item Item { get; set; }


c) Add en constructor: EditItemModel(ItemService itemService) der injicere ItemService og initialisere _itemService:

public CreateItemModel(ItemService itemService)
{
_itemService = itemService;
}


d) Add metoden OnGet(int id). Metoden skal initialisere property'en Item med det Item der skal opdateres. Det sker ved at kalde GetItem(id) på servicen, hvor id er parameter-overført fra siden (kommer senere). OnGet(int id) skal returnere siden selv, nu initialiseret med det Item der skal opdateres:

public IActionResult OnGet(int id)
{
Item = _itemService.GetItem(id);
if (Item == null)
return RedirectToPage("/NotFound"); //NotFound er ikke defineret endnu

return Page();
}


e) Add metoden OnPost( ). Metoden skal kalde UpdateItem(Item), hvor Item indeholder de opdaterede properties. Efter opdatering omdirigeres (RedirectToPage) til siden "GetAllItems"

public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
_itemService.UpdateItem(Item);
return RedirectToPage("GetAllItems");
}

 

Step 4 (EditItem.cshtml)
Add et <form>-tag til EditItem.cshtml, så de nye værdier for Name og Price kan indtastes. Der skal være et <input>-tag af typen="submit" så der kan sendes et HTTP-request (method="post") til serveren og OnPost( ) metoden kaldt

<form method="post">
<div class="form-group">
<label asp-for="Item.Id" class="control-lable"></label>
<input asp-for="Item.Id" class="form-control" readonly="@(true)"/>
</div>
<div class="form-group">
<label asp-for="Item.Name" class="control-lable"></label>
<input asp-for="Item.Name" class="form-control" />
<span asp-validation-for="Item.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Item.Price" class="control-lable"></label>
<input asp-for="Item.Price" class="form-control" />
<span asp-validation-for="Item.Price" class="text-danger"></span>
</div>

<div class="form-group">
<input type="submit" value="Update" class="btn btn-primary" />
</div>
</form>

Overvej:



Bemærk: når der skal Routes fra siden "GetAllItems" til "EditItem" skal der sendes en route-parameter med, nemlig Id på det Item der skal opdateres. Det specificeres øverst på siden i page direktivet: @Page ved at tilføje "{id:int}". int angiver en constraint - at id skal være af typen int. Havde vi skrevet "{id:int?}" var parameteren "optional".

Opdater siden med: @Page "{id:int}"

Add et <a>-tag, med asp-page="/Item/GetAllItems" i bunden af siden, så der kan navigeres (routes) tilbage til siden "GetAllItems":

<div>
<a asp-page="/Item/GetAllItems">Back to List</a>
</div>

 


Step 5 (GetAllItems.cshtml)
Nu mangler vi blot at tilføje et <td>-tag med et <a>-tag for hvert Item i tabellen (under de andre <td>-tag med Item properties). <a> tagget skal være af typen "button" og skal indeholde et asp-page helper tag der router til siden "EditItem". Bemærk da id skal sendes med som router-parameter skal der også være et asp-route helper tag: asp-route-id="@item.Id" (url'en bliver således: "/EditItem/id")

<td>
<a class="btn btn-primary btn-sm" type="button" title="Edit" asp-page="EditItem" asp-route-id="@item.Id">Edit</a>
</td>




Step 6 (Afprøv)

Afprøv at programmet virker og at det er muligt at opdatere Items objekter ala:

 

Det er nu muligt at lave CRU operationerne (Create, Read og Update) på Items. Nu skal vi have implementeret Delete.

Step 7 (IItemService, ItemService)
Først opdateres IItemService og ItemService med metoden: DeleteItem(int id) ala:


public Item DeleteItem(int? itemId)
{
foreach (Item item in _items)
{
if (item.Id == itemId)
{
_items.Remove(item);
return item;
}
}
return null;
}


Step 8 (DeleteItem)
Næste step er at oprette en ny Razer Page: DeleteItem i mappen Pages/Item.

Step 9 (DeleteItem.cshtml.cs)
a) Add instancefield, property og constructor til klassen DeleteItemModel (ala EditItem):

private ItemService _itemService;

[BindProperty]
public Models.Item Item { get; set; }

public DeleteItemModel(ItemService itemService)
{
_itemService = itemService;
}


b) Add metoden OnGet(int id). Metoden skal initialisere property'en Item med det Item der skal slettes. Det sker ved at kalde GetItem(id) på servicen. OnGet(int id) skal returnere siden selv, nu initialiseret med det Item der skal slettes:

public IActionResult OnGet(int id)
{
Item = _itemService.GetItem(id);
if (Item == null)
return RedirectToPage("/NotFound"); //NotFound er ikke defineret endnu

return Page();
}


c) Add metoden OnPost( ). OnPost( ) skal kalde service-metoden DeleteItem(Item.id). Efter sletning omdirigeres (RedirectToPage) til siden "GetAllItems" ala:

public IActionResult OnPost()
{
Models.Item deletedItem = _itemService.DeleteItem(Item.Id);
if (deletedItem == null)
return RedirectToPage("/NotFound"); //NotFound er ikke defineret endnu
return RedirectToPage("GetAllItems");
}

 

Step 10 (DeleteItem.cshtml)
Det skal være muligt at fortryde, at man er ved at slette et Item. Derfor skal siden indeholde en bekræftelse og en mulighed for at fortryde.

Tilføje et <button>-tag af typen "submit" - et klik på denne submit-button vil kalde ovenstående OnPost( ) - metode og Item slettes. Tilføj også et <a>-tag med et asp-page helper tag der router tilbage til GetAllItems, hvis der fortrydes.

<h1>Delete Confirmation></h1>
<div class="alert alert-danger">
<h5>Are you sure you want to delete Item - @Model.Item.Name</h5>
<form method="post">
<button type="submit" class="btn btn-danger">Yes</button>
<a class="btn btn-primary" asp-page="/Item/GetAllItems">No</a>
</form>
</div>

 

Step 11 (GetAllItems.cshtml)
Nu mangler vi blot at tilføje et <a>-tag for hvert Item i tabellen . <a> tagget skal være af typen "button" og skal indeholde et asp-page helper tag der router til siden "DeleteItem". Bemærk id skal sendes med som router-parameter, hvorfor der også her skal være et asp-route helper tag: asp-route-id="@item.Id" . Placer <a>-tagget i samme <td>-tag som Edit-knappen:

<td>
<a class="btn btn-primary btn-sm" type="button" title="Edit" asp-page="EditItem" asp-route-id="@item.Id">Edit</a>
<a class="btn btn-danger btn-sm " type="button" title="Delete" asp-page="DeleteItem" asp-route-id="@item.Id">Delete</a>
</td>




Step 12 (Afprøv)

Afprøv at programmet virker og at det er muligt at slette Items objekter ala:

 

 

 

 


God fornøjelse!
Henrik Høltzer