2014. február 1., szombat

MVC: Egyszerre több partial view frissítése

Online demo és letöltés: pulzonic.com/multipartial
Nuget csomag: www.nuget.org/packages/Multipartial

Bevezetés


Nemrégiben volt egy projektünk, amelyen nagyon kevesen dolgoztunk fejlesztők. Fontos szempont volt, hogy a webalkalmazásunknak Facebook-szerű, komplex UI-a legyen, de semmiképpen sem szerettünk volna nekiállni bonyolult kliensoldali kódot írni, ezért elhatároztuk, hogy minimalizáljuk a JavaScript mennyiségét, és lehetőleg minden html kódot a szerveroldalon renderelünk ki. Az elképzelésem az volt, hogy a Html tartalmat felszabdaljuk sok, egymásba ágyazott partial view-ra (akár egy lista egyetlen listaeleme is egy partial view lehet), ezeket view-kat frissítjuk, így mindössz annyi JavaScriptre lesz szükségünk, ami elposztolja a kérést, majd a visszakapot html snipetet egyszerűen a helyére rakja.

Az gyorsan kiderült, hogy ez a beépített ActionResult-okkal nem fog menni, ezért csináltam egy saját megoldást.



A megoldás


Készítettem egy saját AcionResult osztályt, amely segítségével egyszerre lehet a weboldalnak több, egymástól teljesen független részét frissíteni. Ennek a neve MultipartialResult lett.

Tegyük fel, hogy egy webes levelező alkalmazáson dolgozol. Amikor itt a felhasználó kiválaszt egy levelet, és rákattint a Törlés gombra, a következő dolgok történnek egyszerre:

  • Az aktuális kijelölt levél eltünik a listából, és a következő jelölődik ki.
  • Az Előnézet dobozban az újonnan kijelölt levél tartalma jelenik meg
  • A levelek számát jelző szám megváltozik
  • A böngésző címsora is megváltozik, mivel ott is fel van tüntetve az olvasatlan levelek száma
Ebben az esetben mind az email-ek listája, mind az Előnézet doboz egy-egy partial view. A levelek száma egy egyszerű szöveg a DOM-ban.

A MultipartialResult használatával a Delete gomb eseménykezelő action-ja valahogy így néz ki:

public ActionResult OnDelete(long EmailId)
{
     //... does the deleting
     //... creates the model for the new InboxList partial view (InboxListModel)
     //... creates the model for the PreviewPane partial view (PreviewPaneModel)
     //... calculates the number of the emails (EmailCount)
     //... renders the browser title with the updated unread email number (BrowserTitle)
    
     MultipartialResult result = new MultipartialResult();
     result.AddView("_InboxList","InboxListDiv",InboxListModel);
     result.AddView("_PreviewPane","PreviewDiv",PreviewPaneModel);
     result.AddContent(EmailCount.ToString(),"EmailCountDiv");
     result.AddScript(string.Format("document.title='{0}';",BrowserTitle));
     return result;
}

Az AddView eredményeként az _InboxList view tartalma az InboxListDiv elemben fog megjelenni.
Az AddContent eredményeként a megadott string az EmailCountDiv-be kerül bele.
Az AddScript eredményeként a kliensoldalon lefut a megadott JavaScript.

A kliensoldalon az egyetlen teendő van, meghívni a MultipartialUpdate JS függvényt az OnSuccess eseménykezelőben:

@Ajax.ActionLink("Delete", "OnDelete", new { EmailId = Model.CurrentEmail.Id }, new AjaxOptions { OnSuccess = "MultipartialUpdate" })

vagy, Ajax formban így:

@using (Ajax.BeginForm("OnDelete", 
 new { EmailId = Model.CurrentEmail.Id }, new AjaxOptions { OnSuccess = "MultipartialUpdate" }))

vagy, jQuery .post vagy .ajax függvényben így:

function deleteClicked(emailId) { 
    $.ajax({
        url: "/inbox/ondelete",
        type: "POST",
        data: { emailId: emailId },
        success: function (result) {
            MultipartialUpdate(result);
        },
    });

Háttér


A Multipartial működési elve nagyon egyszerű. A JsonResult osztályból van örököltetve, lerendereli a megadott view-kat stringekbe, ezeket összegyűjti, és egy json-ba csomagolva elküldi a kliensoldalra. Ott pedig egy JS függvény szépen végigmegy rajtuk, és mindegyiket a helyére rakja a DOM-ban.

Amikor a szerveroldalon összegyűjti, mindegyik megjelöli tartalom alapján:


public MultipartialResult AddView(string viewName, string containerId, object model = null)
{ 
        views.Add(new View() { Kind = ViewKind.View, 
        ViewName = viewName, ContainerId = containerId, Model = model });
  return this;
}
public MultipartialResult AddContent(string content, string containerId)
{
  views.Add(new View() { Kind = ViewKind.Content, Content = content, ContainerId = containerId });
  return this;
} 
public MultipartialResult AddScript(string script)
{ 
  views.Add(new View() { Kind = ViewKind.Script, Script = script });
  return this;
}

Mikor az action visszatér az ActionResult osztállya, az Mvc keretrenszer meghívja az ExecuteResult függvényt, amely elkészíti ezt a json-t:


public override void ExecuteResult(ControllerContext context)
        {
            List<object> data = new List<object>();
            foreach (var view in views)
            {
                string html = string.Empty;
                if (view.Kind == ViewKind.View)
                {
                    //view result
                    html = RenderPartialViewToString(mController, view.ViewName, view.Model);
                    data.Add(new { updateTargetId = view.ContainerId, html = html });
                }
                else if (view.Kind == ViewKind.Content)
                {
                    //content result
                    html = view.Content;
                    data.Add(new { updateTargetId = view.ContainerId, html = html });
                }
                else if (view.Kind == ViewKind.Script)
                {
                        //script result
                    data.Add(new { script = view.Script });
                }
            }
            Data = data;
            base.ExecuteResult(context);
        }


A view-k string-be renderelésébe most inkább nem mennék bele...

A kliensoldalon már csak egy kis egyszerű JS függvényre van szükség, amely megkapja ezt a json-t, végigmegy rajta és mindegyik elem esetében frissíti a DOM-t, vagy futtatja a JS-t.


function MultipartialUpdate(views) {
    for (v in views)
        if (views[v].script) {
            eval(views[v].script);
        }
        else {
            $('#' + views[v].updateTargetId).html(views[v].html);
        }
    return false;
}

Remélem, van még rajtam kívül valaki, aki ezt hasznosnak találja... :)

7 megjegyzés:

  1. Betway Casino | Free Play | No deposit | $25 Free + 150 FS
    Play the latest games with Betway Casino 12bet | Get $25 planet win 365 Free + 150 FS or 150 FS Bonus at Gold Casino - Instant Play! betway

    VálaszTörlés
  2. Sports betting is authorized in a majority of the states within the US. On this web page, you'll find out the place you can to|you possibly can} place a sports activities wager online within the USA. A money line wager is a wager on a particular group to win a contest without a a|with no} point unfold to cover. The favourite (-) and underdog (+) are given odds primarily based on a $100 wager. If you ever hear 메리트카지노 the term “straight bet” it's referring to a particular wager on a sports activities contest with a win or loss on the wager decided by a degree unfold, money line or total (over/under). Ted Dahlstrom works within the Seattle area as an Evergreen & Commercial Content Manager for Better Collective.

    VálaszTörlés
  3. The mildew cavity is the formed part in the mildew plates which give the plastic components its ultimate form. When the molten plastic flows into the cavity, it takes up the shape of the hole area and acquires its volume. This injection system has separate barrels for melting and injecting the plastic into the mildew. Once the plastic passes by way of the first barrel, it proceeds to the second barrel that makes use of a plunger to switch the molten plastic to the mildew. The stylus pen for computer size of the tie bar limits the dimensions of the mildew that can be be} placed in an injection molding machine.

    VálaszTörlés
  4. Emotions are key, be relaxed, be alert, and take your time to be good, and you have got} a good likelihood of profitable. truly have} withdrawn money in the last few|the earlier few|the earlier couple of} months; that's fairly good so that it can be be} carried out. Have you ever been steadily profitable taking part in} sure amount|a specific amount|a certain quantity}, e.g., $1, so that you resolve to wager extra to win extra and enhance your wager per spin to $2. The machine "immediately" stops paying and turns into deader than a Dodo bird! Strange, is not it, considering slots are imagined to thecasinosource.com be so-called "random" .

    VálaszTörlés
  5. Thus, a deposit and withdrawal in an online on line casino with PayPal certainly one of the|is amongst the|is likely certainly one of the} safest methods for transferring money. It is even a good signal when an internet on line casino provides this fashion of payment. This is as a result of|as a outcome of} PayPal checks very fastidiously with which on-line on line casino or gaming hall it cooperates. Most loyalty applications are comprised of tiers, which 토토사이트 gamers climb by incomes points enjoying in} real money video games. Thankfully, bonus money does not stop flowing after initial welcome provides.

    VálaszTörlés