Partial Views
Standard metoden for at indlejre partial views er via TagHelperen <partial> hvor du via name og model attributterne kan styre indholdet.
Vi har nogen gange brug for at kunne lidt mere, inspireret af fx. single file components i Vue, og derfor er der lavet vores egen TagHelper til partial views.
Med den kan du udover at definere name og model (og de øvrige ting standard helperen kan), også bruge child content, og sætte nøgler i den tilhørende ViewDataDictionary.
Et eksempel er at du gerne vil have en komponent partial til fx. en modal. Den kunne have en markup ala følgende:
<div class="fixed inset-0 bg-white bg-opacity-50 flex items-center justify-center" x-data="{visible: false}" x-show="visible"> <div class="bg-white shadow-xl"> <div class="text-3xl"><!-- overskrift her --></div> <div><!-- indhold her --></div> </div></div>I dette eksempel er der en masse ting, man helst ikke vil have duplikeret i flere forskellige views, fx. klasserne, og alpine-direktiverne. Derudover er der to steder, hvor indholdet gerne skal være dynamisk.
Et normalt partial view vil typisk have en bestemt model at arbejde med, lad os bare som eksempel bruge følgende:
public class MyPartialViewModel{ public string Title { get;set; } public string Content { get;set; }}Derved kunne vi i princippet godt lave en ny instans af MyPartialViewModel og sende den ind i viewet. Men det ville begrænse os ved at Content nu kun kan være en string. Hvad hvis vi fx. har brug for mere komplekst indhold, måske en tabel eller noget dynamisk fra serveren?
Det er dette problem vores egen partial helper løser.
Tag Helper <ec-partial>
Sektion kaldt “Tag Helper <ec-partial>”Denne er en overstyring af default partial helperen i .net, og kan i udgangspunktet det samme som den, med nogle tilføjelse.
Der er tilføjet en attribut der gør det muligt at binde værdier til partial viewets ViewData dictionary, så du kan skrive <ec-partial name="MyPartialView" view-data:title="@Model.TitleInModal"></ec-partial> eller <ec-partial name="MyPartialView" view-data.string:title="Overskrift her"></ec-partial>.
Attributten er bygget op af en “trigger”; view-data: samt den nøgle i ViewDataDictionaryen du vil styre. Nøglen skal skrives i kebab-case (et-eksempel), og konverteres i TagHelperen til camelCase (etEksempel).
Da attributten ikke kan skelne mellem en string og en reference, er der en modifier så hvis du skal indsætte en ren stringværdi, skal du bruge view-data.string: som trigger.
Herved tilføjes “Overskrift her” som “title” i partial viewets ViewDataDictionary. I Ecreo.Essentials ligger en extensionmetode så du kan hente det ud, med en fallback værdi. Det bruges som her:
<div class="fixed inset-0 bg-white bg-opacity-50 flex items-center justify-center" x-data="{visible: false}" x-show="visible"> <div class="bg-white shadow-xl"> <div class="text-3xl">@(ViewData.GetValue<string>("title", "Her er fallback overskriften"))</div> <div><!-- indhold her --></div> </div></div>Så langt så godt.
Vue eksempel
Sektion kaldt “Vue eksempel”Men vi vil også gerne kunne definere indholdet, fra der hvor vi indlejrer partial viewet. I single file components i Vue, gøres det, ved ganske enkelt at sende child content med, fx:
<MyComponent> <h2>Overskrift</h2> <p>Tekst tekst tekst</p></MyComponent>og i Vue-componenten har du så et <slot/> som bliver erstattet af child-indholdet.
Med <ec-partial>
Sektion kaldt “Med <ec-partial>”Med <ec-partial> kan du gøre noget lignende:
<ec-partial name="MyPartialView" view-data:title="@Model.TitleInModal"> <h2>Overskrift</h2> <p>Tekst tekst tekst</p></ec-partial>I partial viewet indsættes så et <ec-slot/> tag, der hvor child indholdet skal placeres, så viewet nu bliver:
<div class="fixed inset-0 bg-white bg-opacity-50 flex items-center justify-center" x-data="{visible: false}" x-show="visible"> <div class="bg-white shadow-xl"> <div class="text-3xl">@(ViewData.GetValue<string>("title", "Her er fallback overskriften"))</div> <div> <ec-slot/> </div> </div></div>Slutresultat
Sektion kaldt “Slutresultat”Og når serveren renderer siden bliver det så til
<div class="fixed inset-0 bg-white bg-opacity-50 flex items-center justify-center" x-data="{visible: false}" x-show="visible"> <div class="bg-white shadow-xl"> <div class="text-3xl">Overskirft her</div> <div> <h2>Overskrift</h2> <p>Tekst tekst tekst</p> </div> </div></div><ec-partial> merger sine almindelige attributter med første HTML-element i partialen. Det vil sige, hvis du har en partial fx. MyPartial.cshtml der ser sådan her ud:
<div class="my-partial"> <ec-slot/></div>Og kalder den via <ec-partial> med:
<ec-partial name="MyPartial" class="extra-class" id="my-partial-id"> <div>test</div></ec-partial>Så vil outputtet være:
<div class="my-partial extra-class" id="my-partial-id"> <div>test</div></div>Brug override:*, hvis en attribut skal overskrives i stedet for at merges:
<ec-partial name="MyPartial" override:class="only-this-class"></ec-partial>Brug if-true:* til boolean-attributter:
<ec-partial name="MyInput" if-true:disabled="@isDisabled"></ec-partial>Named slots
Sektion kaldt “Named slots”Et partial kan have flere slots:
<header><ec-slot name="header"></ec-slot></header><main><ec-slot></ec-slot></main>Kald partialet med named slot content og default content:
<ec-partial name="Card"> <ec-slot-content name="header">Titel</ec-slot-content> <p>Brødtekst</p></ec-partial>Manglende slots
Sektion kaldt “Manglende slots”Named slot content renderes kun, hvis partial viewet har et matchende <ec-slot name="...">.
Hvis kaldet sender et slot, som partialet ikke implementerer, bliver indholdet ignoreret.
<ec-partial name="Card"> <ec-slot-content name="footer">Læs mere</ec-slot-content> <p>Brødtekst</p></ec-partial>Hvis Card.cshtml kun har default slot:
<article> <ec-slot></ec-slot></article>Bliver output:
<article> <p>Brødtekst</p></article>footer bliver ikke renderet, fordi partialet ikke har <ec-slot name="footer">.
Hvis partialet har et named slot, men kaldet ikke leverer indhold til det, bruges fallback-indholdet inde i slot-tagget.
<article> <header><ec-slot name="header">Standardtitel</ec-slot></header> <ec-slot></ec-slot></article>Kald:
<ec-partial name="Card"> <p>Brødtekst</p></ec-partial>Output:
<article> <header>Standardtitel</header> <p>Brødtekst</p></article>Hvis slot-tagget er self-closing, er fallback tom:
<ec-slot name="header" />