MVC - V jak Widok - Edycja, podgląd, dodawanie

Widok - edycja oraz dodawanie
Oprócz opisanych wcześniej list musimy jeszcze operować na poszczególnych rekordach. Mamy do dyspozycji Create, Details, Edit z standardowych templatów. O ile dla Details czyli podglądu sprawa jest prosta to dla pozostałych akcji standardowo generowane są dwie metody. Jedna odpowiedzialna na wysyłanie danych do widoku GET, druga odpowiedzialna za przetwarzanie danych zwróconych przez widok POST.
Dla podglądu oczywiście wystarczy dostarczyć dane które mają być prezentowane (tylko GET).

Dla Create czyli dodania nowego rekordu w metodzie Get powinniśmy zapewnić niezbędne dane pomocnicze jak zawartość list rozwijalnych, czy jakieś tytuły opisy.
Natomiast w metodzie POST dostaniemy nowo utworzony obiekt, który zapewne należało by wysłać do bazy danych aby nie zginął.
W metodzie POST jako parametr widnieje obiekt Risk bo dla takiego stworzyłam sobie ten widok, widoczna wcześniej składnia "[Bind(Exclude="RiskID")]" oznacza że nie potrzebujemy ID, ono nam się gdzieś indziej z automatu utworzy.
   public ActionResult Preview(int? id)
   {
        ViewData["title"] = "Edycja ryzyka";   
        var riskToEdit = (from m in edul.Risks
                          where m.RiskID == id
                          select m).First();
        //wyciagniecie z bazy rekordu dla wskazanego id

        return View(riskToEdit);
    }


        // GET: 
    public ActionResult Create()
    {
        ViewData["ddl"] = new SelectList(edul.RiskTypes.ToList(),"RiskTypeID","RiskTypeCode");
        // przekazanie zrodla danych do ddl
        return View();
    }

        //
        // POST: /Risk/Create
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create([Bind(Exclude="RiskID")]NPEduLinqDataAccess.Risk riskToInsert )
    {
        try
        {
            if (!ModelState.IsValid)
                return View();
            
            edul.Risks.InsertOnSubmit(riskToInsert); 
            edul.SubmitChanges(); //zapisanie dodanego rekordu do bazy danych
                               
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
Edit. Edycja jest połączeniem podglądu i dodania. W metodzie Get musimy zapewnić nie tylko dane pomocnicze do list, ale rónież rekord który ma być edytowany, natomiast gdy wraca do nas zmodyfikowany rekord w metodzie POST musimy się nim zająć i zapisać go do bazy.
W poniższym przykładzie wykorzystany jest model danych LinqToSql dla którego nie znalazłam metody która aktualizowała by pola orginalnego rekordu, w EntityFramework wywołalibyśmy jedną metodę zamiast zmieniać wszystkie property po kolei (być może jest lepsze rozwiązanie jednak ja zbytnio go nie szukałam).
    // GET: /Risk/Edit/5

    public ActionResult Edit(int id)
    {
        ViewData["title"] = "Edycja ryzyka";
        ViewData["ddl"] = new SelectList(edul.RiskTypes.ToList(), "RiskTypeID", "RiskTypeCode"); //zrodlo danych dla DDL
        var riskToEdit = (from m in edul.Risks
                           where m.RiskID == id
                           select m).First();
                           //rekord o przekazanym id do wyswietlenia

        return View(riskToEdit);
    }

    //
    // POST: /Risk/Edit/5

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(int id, NPEduLinqDataAccess.Risk riskToEdit)
    {
        try
        {
            var originalRisk =  edul.Risks.First(x =>x.RiskID == riskToEdit.RiskID);
            //pobranie orginalnego rekordu przed edycja                                  

            if (!ModelState.IsValid)
                return View(originalRisk );

                
            originalRisk.RiskCode  = riskToEdit.RiskCode;
            originalRisk.RiskDesc = riskToEdit.RiskDesc;
            originalRisk.RiskTypeID  = riskToEdit.RiskTypeID;
            //aktualnizacja danych
            edul.SubmitChanges ();//zapisanie zmodyfikowanego rekordu do bazy 

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
Testując różne konfiguracje warstwy dostępu do danych okazało się że w przypadku typowanych DataSetów pojawia się problem. Metoda POST wymaga domyślnego konstruktora dla obiektu, natomiast wiersz z takiego DataSeta niestety bezparametrowego konstruktora nie posiada.
Nadal możemy korzystać z DataSetów jako źródła danych dla widoków MVC jednak stracimy silne typowanie ponieważ jako obiekt zwracany najlepiej będzie nam użyć typu FormCollection, w którym odnosimy się do kolekcji poprzez nazwy pól w modelu (nazwy pól w wierszu z dataSeta). Poniżej pokomplikowany przykład z DataSetem
        //
        // GET: /Policy/Create

        public ActionResult Create()
        {
            var variant = from c in edul.Variants
                          select new { id = c.VariantID, text = string.Format("{0}, {1}", c.VariantCode, c.VariantDesc) };
            ViewData["ddl"] = new SelectList(variant.ToList(), "id", "text");

            return View();
        }

        //
        // POST: /Policy/Create

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(FormCollection collection)
        {
//NPEduBaseObjects.Policy.PolicyDS.PolicyRow newPolicy)  czyli po typie NPEduBaseObjects.Policy.PolicyDS+PolicyRow
//-> zwraca blad Dla tego obiektu nie zdefiniowano konstruktora bez parametrˇw.
            try
            {

                //wyciagniecie period
                var period = (from c in edul.VariantPeriods
                              where c.Variant.VariantID == System.Convert.ToInt32(collection["PolicyVariantID"])
                              select c.VariantPeriodID).Max();

                NPEduServerObjects.Policy.Policy pol = new NPEduServerObjects.Policy.Policy();
                NPEduBaseObjects.Policy.PolicyDS.PolicyRow newPolicy = pol.BeginAddPolicy(
                    System.Convert.ToDateTime(collection["PolicyDate"]),
                    System.Convert.ToDateTime(collection["PolicyEndDate"]),
                    System.Convert.ToInt32(collection["PolicyInsuranceSumAmount"]),
                    System.Convert.ToDateTime(collection["PolicyStartDate"]),
                    System.Convert.ToInt32(collection["PolicyTotalFee"]),
                    System.Convert.ToInt32(collection["PolicyVariantID"]), period);
//bez walidacji - jesli mamy tutaj puste stringi - najprawdopodobniej dostaniemy bledy!! 
                
               
                pol.Update();

                return RedirectToAction("Index");
            }
            catch (Exception e)
            {
                return View();
            }
        }

Tak naprawdę wszystko powyżej odnosiło się tylko i wyłącznie do kontrolera. A jak to wygląda od strony wygenerowanego widoku? Bardzo prosto. System.Web.MVC.HtmlHelper udostępnia nam garstkę metod generujących TextBox, DropDownList, CheckBox, ListBox, RadioButton, TextArea i ValidationMessage.
Z tej niewielkiej ilości standardowych elementów można stworzyć w miarę funkcjonalną stronę. Oczywiście możemy napisać swoje metody rozszerzające gamę generowanych elementów.
Przyznam że nie przetestowałam wszystkich elementów, zatrzymałam się na chwile nad DropDownList. W wyżej prezentowanych przykładach wysyłam sobie dane do takiej listy sformatowane do typu SelectListItem . Metoda Html.DropDownList przyjmuje dwa parametry, według opisu "name" czyli "The name of the form field" i "selectList".
I tutaj wielkie fiasko myślenia WebForms. Name nie jest nazwą kontrolki. Myśląc logicznie po pewnym czasie dochodzi się do wniosku że przecież tu nie ma kontrolki bo właśnie generujemy kod HTML, jednak odruchy pozostają.
Koniec końców okazuje się że Name jest to nazwa pola z obowiązującego modelu, do którego wybrana z DDL wartość ma być podbindowana.
< %@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
< %@ Import  Namespace="MvcContrib.Binders" %>

 Create




    

Create

< %= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") % > < % using (Html.BeginForm()) { % >
Fields

< label for="RiskCode">RiskCode: < %= Html.TextBox("RiskCode") %> < %= Html.ValidationMessage("RiskCode", "*") %>

< label for="RiskDesc">RiskDesc: < %= Html.TextBox("RiskDesc") %> < %= Html.ValidationMessage("RiskDesc", "*") %>

< label for="RiskTypeID">RiskType: < %= Html.DropDownList("RiskTypeID", ViewData["ddl"] as SelectList)%> < %-- < %= Html.TextBox("RiskTypeID") %> < %= Html.ValidationMessage("RiskTypeID", "*") %> --% >

< % } % >
< %=Html.ActionLink("Back to List", "Index") %>

O samym widoku nie ma wiele więcej do powiedzenia z wyjątkiem walidacji (tutaj bym rzuciła hasłem xVal ale nie sprawdzałam sprawy).

Komentarze

Popularne posty