Část 5: Editační formuláře a šablonování textu
MVC Music Store je kurzová aplikace, která představuje a vysvětluje, jak používat ASP.NET MVC a Visual Studio pro vývoj pro web.
MVC Music Store je jednoduchá ukázková implementace obchodu, která prodává hudební alba online a implementuje základní správu webu, přihlašování uživatelů a funkce nákupního košíku.
Tato série kurzů podrobně popisuje všechny kroky potřebné k vytvoření ukázkové aplikace ASP.NET MVC Music Store. Část 5 se věnuje úpravám formulářů a šablon.
V předchozí kapitole jsme načítali data z naší databáze a zobrazovali je. V této kapitole také povolíme úpravy dat.
Vytvoření StoreManagerControlleru
Začneme vytvořením nového kontroleru s názvem StoreManagerController. U tohoto kontroleru budeme využívat funkce generování uživatelského rozhraní, které jsou k dispozici v aktualizaci nástrojů ASP.NET MVC 3. Nastavte možnosti dialogového okna Přidat kontroler, jak je znázorněno níže.
Když kliknete na tlačítko Přidat, uvidíte, že mechanismus generování ASP.NET MVC 3 udělá spoustu práce za vás:
- Vytvoří nový StoreManagerController s místní proměnnou Entity Framework.
- Přidá složku StoreManager do složky Zobrazení projektu.
- Přidá do třídy Album zobrazení Create.cshtml, Delete.cshtml, Details.cshtml, Edit.cshtml a Index.cshtml.
Nová třída kontroleru StoreManager zahrnuje akce kontroleru CRUD (vytvoření, čtení, aktualizace, odstranění), které vědí, jak pracovat s třídou modelu Album a používat kontext Entity Frameworku pro přístup k databázi.
Úprava vygenerovaného zobrazení
Je důležité si uvědomit, že zatímco tento kód byl pro nás vygenerován, je to standardní ASP.NET kód MVC, stejně jako jsme psali v tomto kurzu. Jeho účelem je ušetřit čas, který byste strávili psaním často používaného kódu kontroleru a ručním vytvářením zobrazení se silnými typy, ale nejedná se o typ vygenerovaného kódu, který jste možná viděli s hroznými upozorněními v komentářích o tom, jak nesmíte kód změnit. Toto je váš kód a očekává se, že ho změníte.
Začněme tedy rychlou úpravou zobrazení indexu StoreManager (/Views/StoreManager/Index.cshtml). Toto zobrazení zobrazí tabulku se seznamem Alb v našem obchodě s odkazy Upravit / Podrobnosti / Odstranit a obsahuje veřejné vlastnosti alba. Odebereme pole AlbumArtUrl, protože v tomto zobrazení není moc užitečné. V <části table> kódu zobrazení odeberte <prvky th> a <td> , které obklopují odkazy AlbumArtUrl, jak je uvedeno na zvýrazněných řádcích níže:
<table>
<tr>
<th>
Genre
</th>
<th>
Artist
</th>
<th>
Title
</th>
<th>
Price
</th>
<th>
AlbumArtUrl
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Genre.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Artist.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.AlbumArtUrl)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) |
@Html.ActionLink("Details", "Details", new { id=item.AlbumId }) |
@Html.ActionLink("Delete", "Delete", new { id=item.AlbumId })
</td>
</tr>
}
</table>
Upravený kód zobrazení se zobrazí takto:
@model IEnumerable<MvcMusicStore.Models.Album>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create
New", "Create")
</p>
<table>
<tr>
<th>
Genre
</th>
<th>
Artist
</th>
<th>
Title
</th>
<th>
Price
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Genre.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Artist.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) |
@Html.ActionLink("Details", "Details", new { id=item.AlbumId }) |
@Html.ActionLink("Delete", "Delete", new { id=item.AlbumId })
</td>
</tr>
}
</table>
První pohled na Správce obchodu
Teď spusťte aplikaci a přejděte na /StoreManager/. Zobrazí se index správce obchodu, který jsme právě upravili, a zobrazí seznam alb v obchodě s odkazy na Upravit, Podrobnosti a Odstranit.
Kliknutím na odkaz Upravit se zobrazí formulář pro úpravy s poli pro album, včetně rozevíracích seznamu Žánr a Interpret.
Klikněte na odkaz Zpět do seznamu v dolní části a pak klikněte na odkaz Podrobnosti pro album. Zobrazí se podrobné informace o jednotlivých albech.
Znovu klikněte na odkaz Zpět do seznamu a pak klikněte na odkaz Odstranit. Zobrazí se potvrzovací dialogové okno s podrobnostmi o albu a dotazem, jestli ho opravdu chceme odstranit.
Kliknutím na tlačítko Odstranit v dolní části album odstraníte a vrátíte se na stránku Index, na které se zobrazí odstraněné album.
Nemáme hotovou práci se Store Managerem, ale máme funkční kontroler a kód zobrazení pro operace CRUD, od kterých se mají začínat.
Zobrazení kódu kontroleru správce úložiště
Kontroler Store Manageru obsahuje velké množství kódu. Pojďme si to projít shora dolů. Kontroler obsahuje některé standardní obory názvů pro kontroler MVC a také odkaz na obor názvů Models. Kontroler má privátní instanci MusicStoreEntities, kterou každá akce kontroleru používá pro přístup k datům.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcMusicStore.Models;
namespace MvcMusicStore.Controllers
{
public class StoreManagerController : Controller
{
private MusicStoreEntities db = new MusicStoreEntities();
Akce indexu a podrobností Store Manageru
Zobrazení indexu načte seznam alb, včetně informací o žánrech a interpretech jednotlivých alb, jak jsme viděli dříve při práci na metodě Store Browse. Zobrazení indexu sleduje odkazy na propojené objekty, aby bylo možné zobrazit název žánru a jméno interpreta jednotlivých alb, aby kontroler byl efektivní a dotazuje se na tyto informace v původním požadavku.
//
// GET: /StoreManager/
public ViewResult Index()
{
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist);
return View(albums.ToList());
}
Akce kontroleru Podrobnosti kontroleru StoreManager funguje úplně stejně jako akce Store Controller Details, kterou jsme napsali dříve – dotazuje se na album podle ID pomocí metody Find() a pak ho vrátí do zobrazení.
//
// GET: /StoreManager/Details/5
public ViewResult Details(int id)
{
Album album = db.Albums.Find(id);
return View(album);
}
Metody vytvoření akce
Metody akce Vytvořit se trochu liší od metod, které jsme zatím viděli, protože zpracovávají zadávání formulářů. Když uživatel poprvé navštíví /StoreManager/Create/, zobrazí se mu prázdný formulář. Tato stránka HTML bude obsahovat <prvek formuláře> , který obsahuje vstupní prvky rozevíracího seznamu a textového pole, do kterých mohou zadat podrobnosti o albu.
Jakmile uživatel vyplní hodnoty formuláře Album, může stisknout tlačítko Uložit a odeslat tyto změny zpět do naší aplikace a uložit je do databáze. Když uživatel stiskne tlačítko Uložit, <formulář> provede http-POST zpět na adresu URL /StoreManager/Create/ a odešle <hodnoty formuláře> jako součást HTTP-POST.
ASP.NET MVC nám umožňuje snadno rozdělit logiku těchto dvou scénářů vyvolání adresy URL tím, že nám umožňuje implementovat dvě samostatné metody akce "Create" v rámci třídy StoreManagerController – jednu pro zpracování počáteční http-GET přejděte na adresu URL /StoreManager/Create/ a druhou pro zpracování HTTP-POST odeslaných změn.
Předávání informací do zobrazení pomocí ViewBag
Použili jsme ViewBag dříve v tomto kurzu, ale moc jsme o tom nemluvili. ViewBag nám umožňuje předat informace do zobrazení bez použití objektu modelu silného typu. V tomto případě musí naše akce Upravit kontroler HTTP-GET předat do formuláře seznam žánrů a interpretů, aby se rozevírací seznamy naplní, a nejjednodušším způsobem, jak to udělat, je vrátit je jako položky ViewBag.
ViewBag je dynamický objekt, což znamená, že můžete zadat ViewBag.Foo nebo ViewBag.YourNameHere bez psaní kódu pro definování těchto vlastností. V tomto případě kód kontroleru používá ViewBag.GenreId a ViewBag.ArtistId, takže hodnoty rozevíracího seznamu odeslané s formulářem budou GenreId a ArtistId, což jsou vlastnosti Album, které budou nastaveny.
Tyto hodnoty rozevíracího seznamu jsou vráceny do formuláře pomocí objektu SelectList, který je vytvořen právě pro tento účel. K tomu se používá kód podobný tomuto:
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
Jak je vidět z kódu metody akce, k vytvoření tohoto objektu se používají tři parametry:
- Seznam položek, které bude rozevírací seznam zobrazovat. Všimněte si, že se nejedná jen o řetězec – předáváme seznam žánrů.
- Dalším parametrem předaným do SelectList je Vybraná hodnota. Tímto způsobem selectList ví, jak předem vybrat položku v seznamu. To bude snadněji pochopitelné, když se podíváme na formulář pro úpravy, který je dost podobný.
- Poslední parametr je vlastnost, která se má zobrazit. V tomto případě to znamená, že se uživateli zobrazí vlastnost Genre.Name.
S ohledem na to je pak akce HTTP-GET Create poměrně jednoduchá – do ViewBagu se přidají dva SelectLists a formuláři se nepředá žádný objekt modelu (protože ještě nebyl vytvořen).
//
// GET: /StoreManager/Create
public ActionResult Create()
{
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
return View();
}
Pomocné rutiny HTML pro zobrazení rozevíracích seznamu v zobrazení pro vytvoření
Vzhledem k tomu, že jsme mluvili o tom, jak se hodnoty rozevíracího seznamu předávají do zobrazení, pojďme se na toto zobrazení rychle podívat, jak se tyto hodnoty zobrazují. V kódu zobrazení (/Views/StoreManager/Create.cshtml) uvidíte následující volání, které zobrazí rozevírací seznam Žánr.
@Html.DropDownList("GenreId",
String.Empty)
To se označuje jako pomocník HTML – metoda nástroje, která provádí běžnou úlohu zobrazení. Pomocné rutiny HTML jsou velmi užitečné k tomu, aby byl kód zobrazení stručný a čitelný. Pomocnou rutinu Html.DropDownList poskytuje ASP.NET MVC, ale jak uvidíme později, je možné vytvořit vlastní pomocné rutiny pro kód zobrazení, které v naší aplikaci znovu použijeme.
Volání Html.DropDownList stačí říct dvě věci – kde se má seznam zobrazit a jaká hodnota (pokud existuje) by měla být předem vybraná. První parametr, GenreId, říká DropDownList, aby v modelu nebo ViewBag hledal hodnotu s názvem GenreId. Druhý parametr se používá k označení hodnoty, která se má zobrazit jako původně vybraná v rozevíracím seznamu. Vzhledem k tomu, že tento formulář je formulář Pro vytvoření, není k dispozici žádná hodnota, kterou by bylo možné předem vybrat, a předá se řetězec String.Empty.
Zpracování hodnot zaúčtovaného formuláře
Jak jsme probrali dříve, ke každému formuláři jsou přidruženy dvě metody akcí. První zpracuje požadavek HTTP-GET a zobrazí formulář. Druhý zpracovává požadavek HTTP-POST, který obsahuje odeslané hodnoty formuláře. Všimněte si, že akce kontroleru má atribut [HttpPost], který ASP.NET MVC informuje, že by měla reagovat pouze na požadavky HTTP-POST.
//
// POST: /StoreManager/Create
[HttpPost]
public ActionResult Create(Album album)
{
if (ModelState.IsValid)
{
db.Albums.Add(album);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
return View(album);
}
Tato akce má čtyři povinnosti:
-
- Čtení hodnot formuláře
-
- Zkontrolujte, jestli hodnoty formuláře projdou nějakým ověřovacím pravidlem.
-
- Pokud je odeslání formuláře platné, uložte data a zobrazte aktualizovaný seznam.
-
- Pokud odeslání formuláře není platné, znovu ho můžete přehrát s chybami ověření.
Čtení hodnot formulářů pomocí vazby modelu
Akce kontroleru zpracovává odeslání formuláře, které obsahuje hodnoty pro GenreId a ArtistId (z rozevíracího seznamu) a hodnoty textového pole pro Title, Price a AlbumArtUrl. I když je možné získat přímý přístup k hodnotám formulářů, lepším přístupem je použít funkce vazby modelu integrované do ASP.NET MVC. Když akce kontroleru převezme typ modelu jako parametr, ASP.NET MVC se pokusí naplnit objekt tohoto typu pomocí vstupů formuláře (a také hodnot tras a řetězce dotazů). Dělá to tak, že hledá hodnoty, jejichž názvy odpovídají vlastnostem objektu modelu, například při nastavování hodnoty GenreId objektu nového alba hledá vstup s názvem GenreId. Když vytváříte zobrazení pomocí standardních metod v ASP.NET MVC, budou se formuláře vždy vykreslovat pomocí názvů vlastností jako vstupních názvů polí, takže se názvy polí budou shodovat.
Ověření modelu
Model se ověří jednoduchým voláním ModeluState.IsValid. Do třídy Album jsme zatím nepřidali žádná ověřovací pravidla – uděláme to za chvíli – takže teď tato kontrola nemá moc co dělat. Důležité je, aby se tato kontrola ModelStat.IsValid přizpůsobila ověřovacím pravidlům, která jsme do modelu nasadili, takže budoucí změny ověřovacích pravidel nebudou vyžadovat žádné aktualizace kódu akce kontroleru.
Uložení odeslaných hodnot
Pokud odeslání formuláře projde ověřením, je čas uložit hodnoty do databáze. U Entity Frameworku stačí přidat model do kolekce Alba a volat SaveChanges.
db.Albums.Add(album);
db.SaveChanges();
Entity Framework vygeneruje příslušné příkazy SQL pro zachování hodnoty. Po uložení dat se přesměrujeme zpět na seznam Alb, abychom viděli naši aktualizaci. Provede se to tak, že se vrátí RedirectToAction s názvem akce kontroleru, kterou chceme zobrazit. V tomto případě se jedná o metodu Index.
Zobrazení neplatných odeslání formulářů s chybami ověření
V případě neplatného vstupu formuláře se hodnoty rozevíracího seznamu přidají do ViewBagu (jako v případě HTTP-GET) a hodnoty vázaného modelu se předají zpět do zobrazení pro zobrazení. Chyby ověření se automaticky zobrazují pomocí pomocníka @Html.ValidationMessageFor HTML.
Testování formuláře pro vytvoření
Chcete-li to otestovat, spusťte aplikaci a přejděte na /StoreManager/Create/ – zobrazí se prázdný formulář vrácený metodou StoreController Create HTTP-GET.
Vyplňte některé hodnoty a kliknutím na tlačítko Vytvořit odešlete formulář.
Zpracování úprav
Dvojice akcí Upravit (HTTP-GET a HTTP-POST) se velmi podobají metodám akcí Vytvořit, na které jsme se právě podívali. Vzhledem k tomu, že scénář úprav zahrnuje práci s existujícím albem, načte metoda Edit HTTP-GET album na základě parametru "id", který se předává trasou. Tento kód pro načtení alba pomocí AlbumId je stejný, jak jsme se dříve podívali v akci Kontroleru podrobnosti. Stejně jako u metody Create / HTTP-GET jsou hodnoty rozevíracího seznamu vráceny prostřednictvím ViewBag. To nám umožňuje vrátit album jako objekt modelu do zobrazení (které je silně zadáno do třídy Album) a současně předávat další data (např. seznam žánrů) prostřednictvím ViewBag.
//
// GET: /StoreManager/Edit/5
public ActionResult Edit(int id)
{
Album album = db.Albums.Find(id);
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
return View(album);
}
Akce Upravit HTTP-POST je velmi podobná akci Vytvořit HTTP-POST. Jediným rozdílem je, že místo přidání nového alba do databáze. Kolekce Alb: Aktuální instanci alba hledáme pomocí databáze. Entry(album) a nastavení jeho stavu na Změněno. To říká Entity Frameworku, že upravujeme existující album, nikoli vytváříme nové album.
//
// POST: /StoreManager/Edit/5
[HttpPost]
public ActionResult Edit(Album album)
{
if (ModelState.IsValid)
{
db.Entry(album).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
return View(album);
}
To můžeme otestovat spuštěním aplikace a přechodem na /StoreManger/ a následným kliknutím na odkaz Upravit pro album.
Zobrazí se formulář pro úpravy zobrazený metodou Edit HTTP-GET. Vyplňte některé hodnoty a klikněte na tlačítko Uložit.
Tím odešlete formulář, uložíme hodnoty a vrátíme se do seznamu Alba, kde se zobrazí, že hodnoty byly aktualizovány.
Zpracování odstranění
Odstranění se řídí stejným vzorem jako Pro úpravy a vytvoření, přičemž se k zobrazení formuláře potvrzení používá jedna akce kontroleru a další akce kontroleru pro zpracování odeslání formuláře.
Akce kontroleru HTTP-GET Odstranit je přesně stejná jako naše předchozí akce kontroleru podrobností Store Manageru.
//
// GET: /StoreManager/Delete/5
public ActionResult Delete(int id)
{
Album album = db.Albums.Find(id);
return View(album);
}
Pomocí šablony odstranit obsah zobrazení zobrazíme formulář, který je silně zadaný na typ Album.
Šablona Odstranit zobrazuje všechna pole pro model, ale můžeme to trochu zjednodušit. Změňte kód zobrazení v souboru /Views/StoreManager/Delete.cshtml na následující.
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Delete";
}
<h2>Delete Confirmation</h2>
<p>Are you sure you want to delete the album titled
<strong>@Model.Title</strong>?
</p>
@using (Html.BeginForm()) {
<p>
<input type="submit" value="Delete" />
</p>
<p>
@Html.ActionLink("Back to
List", "Index")
</p>
}
Zobrazí se zjednodušené potvrzení odstranění.
Kliknutí na tlačítko Odstranit způsobí, že formulář bude odeslán zpět na server, který provede akci DeleteConfirmed.
//
// POST: /StoreManager/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Album album = db.Albums.Find(id);
db.Albums.Remove(album);
db.SaveChanges();
return RedirectToAction("Index");
}
Naše akce HTTP-POST Delete Controller (Odstranit kontroler HTTP-POST) provede následující akce:
-
- Načte album podle ID.
-
- Odstraní album a uloží změny.
-
- Přesměruje na index, který ukazuje, že album bylo odebráno ze seznamu.
Pokud to chcete otestovat, spusťte aplikaci a přejděte na /StoreManager. V seznamu vyberte album a klikněte na odkaz Odstranit.
Zobrazí se potvrzovací obrazovka Odstranění.
Kliknutím na tlačítko Odstranit odeberete album a vrátíme se na stránku Index správce obchodu, která ukazuje, že album bylo odstraněno.
Použití vlastního pomocníka HTML ke zkrácení textu
Máme jeden potenciální problém se stránkou indexu Store Manageru. Vlastnosti Název alba a Jméno interpreta můžou být dostatečně dlouhé, aby mohly odhodit formátování tabulky. Vytvoříme vlastní pomocník HTML, který nám umožní snadno zkrátit tyto a další vlastnosti v zobrazeních.
Syntaxe Razoru @helper usnadňuje vytváření vlastních pomocných funkcí pro použití ve vašich zobrazeních. Otevřete zobrazení /Views/StoreManager/Index.cshtml a přidejte následující kód přímo za @model řádek.
@helper Truncate(string
input, int length)
{
if (input.Length <= length) {
@input
} else {
@input.Substring(0, length)<text>...</text>
}
}
Tato pomocná metoda přijímá řetězec a maximální délku, aby byla povolena. Pokud je zadaný text kratší než zadaná délka, pomocník ho vypíše tak, jak je. Pokud je delší, zkrátí text a vykreslí "..." pro zbytek.
Teď můžeme pomocí pomocné rutiny Truncate zajistit, aby vlastnosti Název alba i Jméno interpreta byly kratší než 25 znaků. Níže se zobrazí kompletní kód zobrazení pomocí našeho nového pomocníka Truncate.
@model IEnumerable<MvcMusicStore.Models.Album>
@helper Truncate(string input, int length)
{
if (input.Length <= length) {
@input
} else {
@input.Substring(0, length)<text>...</text>
}
}
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create
New", "Create")
</p>
<table>
<tr>
<th>
Genre
</th>
<th>
Artist
</th>
<th>
Title
</th>
<th>
Price
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Genre.Name)
</td>
<td>
@Truncate(item.Artist.Name, 25)
</td>
<td>
@Truncate(item.Title, 25)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) |
@Html.ActionLink("Details", "Details", new { id=item.AlbumId }) |
@Html.ActionLink("Delete", "Delete", new { id=item.AlbumId })
</td>
</tr>
}
</table>
Když teď procházíme adresu URL /StoreManager/, alba a názvy jsou pod naší maximální délkou.
Poznámka: Tady vidíte jednoduchý případ vytvoření a použití pomocné rutiny v jednom zobrazení. Další informace o vytváření pomocných rutin, které můžete používat na celém webu, najdete v mém blogovém příspěvku: http://bit.ly/mvc3-helper-options