lørdag den 14. juli 2012

Forskellige views til samme action i MVC3


Jeg har i forlængelse af mit indlæg omkring Lister og modeller i MVC3 (Razor Engine) begyndt at gå ud på dybere og dybere vand, for at lære mere og se hvor meget jeg egentligt kan, men lige så meget fordi det er spændende og der kommer nye spørgsmål konstant.

Jeg havnede i en situation hvor jeg begyndte at tænke på hvad nu hvis man vil have en action som KAN tage input-parametre, men det er optional - og du gerne vil levere et view til uden input-parametre, og et andet til når der er input-parametre.
Forstil dig følgende:
{Controller}/{action}/{input-parameter} og input-parameter er optional.

Dette kunne være
Produkter/Kamera/
og her vises aller kamera'er du har. Dette er et view der har sin helt egen struktur og visning.

Så tilføjer du input-parameter så du får:
Produkter/Kamera/CanonEosD70/
og nu vil du gerne vise detaljerne for dette kamera og her vil du vise det på en helt anden måde og dermed have et helt andet view.

Problemet er bare at du kan ikke have en Index()-action og en Index(string cameraID)-action fordi så ved Controlleren ikke hvilken den skal forvente.
Så det man gør er at lave en Index som tager input, og da input-parameteren er optional vil du automatisk få denne parset som null, hvis der ikke er skrevet noget cameraID på.

Og så kan man rent faktisk godt lave to view til en og samme action, og ud fra input vil du få det ene eller det andet.
Se på eksempel herunder:

Hvis vi tager udgangspunkt i ovenstående eksempel med
Produkter/Kamera/ og Produkter/Kamera/CanonEosD70/

Så svarer Produkter til din Controller, Kamera til din action og CanonEosD70 som dit input til din action.
I første eksempel : Produkter/Kamera/ har du intet input til din action (Kamera)
I andet eksempel: Produkter/Kamera/CanonEosD70/ har du input til din action (Action = Kamera, Input = CanonEosD70)

Problemet i dette er at du ikke kan overloade din action, så du kan ikke lave en
public ActionResult Kamera()
{
        return View();
}
og så samtidigt have:

public ActionResult Kamera(string kameraname)
{
        return View();
}

for dette kan din Controller ikke finde ud af. Så det man gør er at lave en action der kan klare begge dele, og det er dette jeg vil vise herunder:

1) Lave din action i din Controller
Skriv følgende:
public ActionResult Kamera(string kameranavn)
{
        return View();
}

2) Lave dit standart view.
Du højreklikker på View, og vælger "Add view". Dette kan kaldes "StandartView" (gør vi i dette eksempel).
Heri laver du det som skal vises ved Produkter/Kamera/

3) Lave dit detaljerede view
Du vil nu gerne levere det som skal vise detaljerne for produktet. Dette kan være et universelt view for alle produkter som altid vil vise det samme, eller have flere forskellige for kategorier (actions), men det er jo op til en selv.
Dette laves ved at du højreklikker på View og vælger "Add view" (ligesom step 2) og kalder dette "DetaljeretView" (i dette eksempel).

4) Sørge for din action kan klare med og uden parametre eller input
Da du bruger en string som input (kameranavn) er dette automatisk et nullable object, men ellers skulle du bruge ? for at være sikker på den var nullable - i tilfælde af du ikke skrive noget efter din action. Det smarte ved dette er at selv når der ikke er skrevet noget så sættes denne input-parameter blot til null.



5) Lave en route der forstår dine parametre
Åben Global.asax og udkommenter default-routen.
Indskriv derefter:

routes.MapRoute(
                "Test", // Route name
                "{controller}/{action}/{kameranavn// URL with parameters
                new { controller = "Home", action = "Index", kameranavn = UrlParameter.Optional } // Parameter defaults
            );
Hermed siger du at der skal startes i Home-controlleren, med Index-action, men alle andre request's vil blive valideret imod ovenstående. Så alt efter din action vil indsættes i kamera-navn.

6) Rette din action så den kan levere to views
Ofte vil du have en model som sikrer du får data rigtigt igennem og du kan arbejde med objekter den rigtige måde.
Jeg vil ikke gå i detaljer omkring dette fordi det findes der masser af guides derude omkring og er ikke hvad dette handler om, men vil vise princippet uden modellen, men når man har forstået dette princip vil det være meget nemt at få denne del erstattet med en model. Se blandt andet dette eksempel fra udvikleren.dk som er rigtigt godt til at lære det basale i MVC 3.
Ret din action Kamera således:
public ActionResult Kamera(string kameranavn)
{
        if (kameranavn == null)
                return View("StandartView");
        Kamera visKamera = new Kamera() { navn = kameranavn }
        return View(visKamera);
}

7) Test dit StandartView
Start din applikation og naviger til
/Produkter/Kamera
Her skulle dit standart view gerne vises.

8) Test dit DetaljeretView
Tilføj nu et kamera navn som du ved at din model kan vise eller som du har hardcodet ind i din controller ligesom det jeg har gjort i step 6. Nu skulle du gerne få vist dit detaljerede view.

Er noget som man rimeligt hurtigt kommer til at få brug for synes jeg og som er rigtigt vigtigt og fedt at kunne i forbindelse med arbejde med MVC 3.


Så ja det kan sagtens lade sig gøre, man skal bare lige vide hvordan. Derfor jeg deler med jer derude og vil hjælpe jer som mig selv til at forstå sådanne ting og blive bedre.

Ingen kommentarer:

Send en kommentar

Kan du lide mit indlæg, har en kommentar, forslag eller andet på hjerte så skriv venligst