View Components

Prawie każda aplikacja powinna mieć jakieś menu, aby ułatwić użytkownikowi poruszanie się po tej aplikacji. Program WPM także będzie posiadała takie udogodnienie. Szczerze mówiąc, zacząłem budowanie widoków aplikacji WPM nie od wyświetlania listy elementów pobranych z bazy, ale właśnie od menu, co by łatwiej przełączać się pomiędzy widokami. Moje menu miało być dynamicznie generowane, czyli w zależności od zalogowanego użytkownika, powinny być różne opcje do wyboru. Potrzebne mi było rozwiązanie w stylu partial view – tu na arenę wkracza nowość w MVC Core czyli tytułowe View Components.

View Component jest lepszą (wierząc dokumentacji) wersją Child Actions i Partial Views. Szczegóły tego nowego elementu MVC są dostępne w powyższym linku, ja natomiast przejdę do konkretów.

Tworzenie klasy ViewComponent

W katalogu projektu tworzymy katalog ViewComponents, a w nim dodajemy nową klasę Navigation.cs:
vs1
Aby klasa była View Componentem:

  • musi ona dziedziczyć po klasie Microsoft.AspNet.Mvc.ViewComponent
  • lub musi być udekorowana atrybutem [ViewComponent] lub dziedziczyć po klasie z takim atrybutem
  • lub nazwa klasy musi kończyć się suffiksem ViewComponent (NavigationViewComponent)

Ja w swojej aplikacji będę po prostu dziedziczył po ViewComponent. Dodatkowo klasa musi implementować metodę Invoke lub InvokeAsync:

    public class Navigation : ViewComponent
    {
        public IViewComponentResult Invoke(string menu)
        {
            string[] model = {"menu1","menu2","menu3",menu};
            return View(model);
        }
    }

Metoda Invoke może zawierać dowolne parametry dowolnego typu, w tym przypadku użyłem pojedynczego stringa, który uzupełni wygenerowane menu o dodatkową pozycję.

Dodanie pliku z widokiem

Powyższa klasa powinna zwracać kawałek kodu html, więc trzeba gdzieś dodać plik z kodem Razor. W projekcie więc tworzymy następującą ścieżkę katalogów: /Views/Shared/Components/Navigation/Default.cshtml

vs2
Zawartość Default.cshtml wygląda tak:

@model string[]
<div style="background: chocolate">
    <h3>Moje menu1</h3>
    <ul>
        @foreach (string menu in Model)
        {
            <li>@menu</li>
        }
    </ul>
</div>

Do widoku przekazuję model, i na jego podstawie renderuję listę menu.

Wywołanie View Component z innego widowku

Teraz, aby wywołać ten komponent należy do jakiegokolwiek widoku dodać:

@Component.Invoke("Navigation","Moje Dodatkowe Menu")

A niezbyt urodziwym efektem jest:
menu1

View Component bez pliku widoku

Html-a nie musimy umieszczać w oddzielnym pliku Default.cshtml, lecz możemy, na wzór HtmlHelperów, wygenerować w samej metodzie komponentu. Metoda Invoke w takim przypadku musi zwracać obiekt ContentViewComponentResult:

        public IViewComponentResult Invoke(string menu)
        { 
            string[] model = {"menu1","menu2","menu3",menu};
            string html = "<div style = 'background: chocolate'><h3>Moje menu2</h3><ul>";
            for (int i = 0; i < model.Length; i++)
            {
              html += $"<li>{model[i]}</li>";
            }
            html += "</ul></div>";
            return new ContentViewComponentResult(new HtmlString(html)); 
        }

Inne możliwości View Component

View Componentem może zawierać konstruktor taki sam jak w zwykłych kontrolerach, pozwalający na wstrzyknięcie odpowiedniego obiektu do wnętrza klasy:

        public Navigation (IWPMRepository repository)
        {
            _repository= repository;
        }

View Component może także zawierać asynchroniczną metodę InvokeAsync. Taką metodę wywołuje się podobnie jak synchroniczną:

 @await Component.InvokeAsync("Navigation","Moje Dodatkowe Menu")

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *