16 juli 2015

Display Templates: Accordion

In deze blogpost ga ik uitleggen hoe je door middel van een Display Template een Accordion kan maken. Ik ga daar de Accordion van Unify voor gebruiken. Dat is een leuke, ruimtebesparende oplossing en meteen geschikt voor mobiele devices. Unify is gebaseerd op Bootstrap, wat een veel gebruikt responsive platform is, een aanrader.

We gaan de Accordion baseren op het Search Results Web Part. Hij komt er uiteindelijk zo uit te zien:



Start

De eerste stap die we nemen is het downloaden van de Starter Display Templates, die vind je in mijn andere blogpost. Sla de bestanden op onder een duidelijk herkenbare naam. In het geval van de Accordion zou dat iets als 'AccordionControl' en 'AccordionItem' kunnen zijn.

Upload de Display Templates (via de browser) naar Display Templates -> Search, in de Masterpage Gallery (Site Settings -> Web Designer Galleries -> Master pages and page layouts). Als je de bestanden hebt geüpload, zie je dat er vanzelf JS bestanden bij worden gegenereerd. Zo niet, dan is er iets niet goed gegaan.

Je kan ook via de 'New' button in de Display Templates-map nieuwe Display Templates aanmaken. De keuzes 'Control Display Template' en 'Item Display Template' zijn te vinden in de dropdown lijst.

Je kan vanaf nu het beste de Masterpage Gallery mappen (als je dat nog niet hebt gedaan, lees dan hier hoe je dat doet). De betreffende Display Templates kan je vanaf nu direct vanuit de verkenner openen in Notepad++ of een andere editor naar keuze.

Content

De 'vulling' van de Accordion gaan we uit een Custom List halen. In de Custom List hebben we niet veel meer nodig dan wat er standaard al wordt aangemaakt door SharePoint, maar we moeten wel 1 veld extra hebben, namelijk die voor de content van de Accordion items. In deze content willen we elementen zoals images, tabellen, etc. kunnen toevoegen, dus we hebben een Rich Text Field nodig. Er bestaat nog geen veld die representatief is voor ons doel, dus gaan we er zelf één aanmaken. Dat doen we niet in de Custom List, maar we maken het veld aan als Site Column. Waarom? 1. Omdat het dan de site-scope heeft en dus ook buiten onze Custom List gebruikt kan worden en 2. Omdat een zelf aangemaakte Site Column automatisch wordt gemapped naar een (nieuwe) Managed Property en die hebben we nodig om het veld in onze Display Template aan te kunnen roepen.

  1. Ga naar de Site Columns pagina (Site Settings -> Web Designer Galleries -> Site Columns).
  2. Klik op Create.
  3. Geef je Site Column een representatieve naam (ik heb gekozen voor 'Content', ivm de herbruikbaarheid van de column), Selecteer Multiple lines of text, zet de optie Number of lines for editing ruim in (bijvoorbeeld 25) en controleer of de optie Enhanced rich text (Rich text with pictures, tables, and hyperlinks) is geselecteerd.
  4. Klik op OK.
  5. Je ziet je Site Column nu in de lijst staan, default onder 'Custom Columns', tenzij je iets anders hebt ingevuld. Ga nu naar de Managed Properties pagina (https://[JouwDomein].sharepoint.com/_layouts/15/listmanagedproperties.aspx?level=sitecol) en zoek op je column naam. Maak een screenshot van de pagina (dit heb je later nodig ter vergelijking, dit is de makkelijkste manier). Werk je On Premise, dan moet je nu een crawl starten, werk je met SPO, dan zal je nu moeten wachten tot er een crawl wordt uitgevoerd (dit kan tussen de 15 minuten en 24 uur duren). Na de crawl zal je Site Column als Managed Property in de lijst verschijnen. SharePoint geeft een eigen naam aan de Managed Property en persoonlijk vind ik het nogal lastig die te achterhalen. De snelste manier is om je screenshot er weer bij te pakken, terug te gaan naar de Managed Properties pagina, weer te zoeken op je columnnaam en te vergelijken welk veld erbij is gekomen. Noteer/Kopieer de naam van de nieuwe Managed Property, die heb je straks nodig in je Display Template.


  6. Maak nu een Custom List aan en geef deze een repesentatieve naam.
  7. Ga naar de List Settings (Ribbon -> List -> List Settings).
  8. Scroll naar beneden naar de Columns section en klik op Add from existing site columns, zoek je zojuist aangemaakte Site Column op en voeg hem toe.
  9. Maak wat list items aan en vul deze met wat content.

Web Part

Om de resultaten te kunnen zien van de aanpassingen die je straks in de Display Templates gaat maken, moeten we eerst het Web Part aanmaken. Zoals eerder vermeldt gebruiken we hiervoor het Search Results Web Part.

  1. Ga naar de pagina waar je de Accordion wilt plaatsen.
  2. Voeg een Web part toe aan een Web Part zone naar keuze.
  3. Kies het Search Results Web Part en klik op Add.
  4. De volgende stap is het maken van de query zodat de juiste gegevens worden opgehaald.


  5. Ga naar het Edit Web Part menu (zie het pijltje rechts bovenin het Web Part)
  6. Klik op Change Query
  7. In het tabje Basics (zorg dat de Quick mode aan staat, dat zie aan het linkje rechts bovenin het tabje Switch to Advanced Mode/Switch to Quick Mode) selecteer je bij Select a query de optie Items matching a Tag (System).
  8. Bij Restrict by app kies je voor Specify a URL en geef je de volledige url naar je eerder aangemaakte Custom List in.
  9. Restrict by tag moet blijven staan op Don't restrict by any tag.
  10. Klik op OK.
  11. Klik in het Web Part menu op Apply (nog niet op OK!).
  12. Waarschijnlijk wint wat je nu ziet niet de schoonheidsprijs, maar je zou wel wat content uit de Custom List moeten zien nu. Klik het Web Part Edit menu nog niet weg, want we gaan nu de juiste Display Templates instellen.


  13. Klik nu op de + bij Display Templates.
  14. Als eerste zie je nu een dropdown met Results Control Display Template staan. In die dropdown zou je je eigen Control Display Template moeten zien, die je eerder hebt aangemaakt. Selecteer die. (Zie je hem niet? Heb je hem gepubliceerd?)
  15. Er onder staan twee radiobuttons. Selecteer de onderste waarbij staat: Use a single template to display items.
  16. Hieronder zie je weer een dropdown menu. Ook hier zou je eigen Item Display Template tussen de opties moeten staan. Selecteer die.
  17. Klik de + bij Display Templates nu weer dicht.
  18. De Display Templates zijn nu ingesteld, maar er zijn ook nog wat instellingen die andere dingen weergeven buiten de Templates. Die willen we niet zien, dus dat moeten we nog even uitschakelen.


  19. klik op de + bij Settings.
  20. Vink alles uit, behalve Show ranked results (Als we die ook uit zouden zetten, zouden we helemaal geen data zien in het Web Part).
  21. Het getal bij Number of results per page doet er niet toe, dat regelt jQuery straks. Kan je dus laten staan zoals t staat.
  22. Klik de + next bij Settings weer dicht.
  23. Standaard laat een SharePoint Web Part nog wat eigen opmaak. Bij de Accordion willen we dat beperken tot alleen de Title, dus dat passen we ook nog even aan.


  24. Klik de + bij Appearance open.
  25. Vul bovenin bij title een naam voor je Accordion in.
  26. Onderin zie je nu Chrome Type staan, met een dropdown menu. Kies de optie Title Only.
  27. Klik nu op OK en sla de pagina op.

Zo, dat was het v.w.b. de instellingen. Het lijkt nu nog helemaal niet op een Accordion, dus we gaan aan de slag met de invulling van de Display Templates.

Display Templates

Zoals ik in mijn eerdere blogpost heb vermeld, werken Display Templates met z'n tweeën, één als 'hoesje' voor het geheel (Control Display Template) en de ander voor individuele items (Item Display Template). Laten we beginnen met de eerste.

Control Display Template

De Control Display Template is niet alleen maar de markup voor het Web Part, het bevat ook alle referenties naar CSS en Javascript bestanden. Dat laatste beginnen we mee. Hieronder kan je de betreffende bestanden downloaden (upload ze zelf naar de gewenste locatie in SharePoint):

Open je Control Display Template in Notepad++ (of een andere editor naar keuze) en vervang alles tussen de <script> tags met onderstaande:
$includeScript(this.url, "~sitecollection/[Pad naar het bestand]/jquery.min.js");
$includeCSS(this.url, "~sitecollection/[Pad naar het bestand]/bootstrap.css");
$includeCSS(this.url, "~sitecollection/[Pad naar het bestand]/style.css");

De volgende stap is het inladen en gebruiken van de Bootstrap Javascript. Dat voegen we toe binnen de <!--#_ en _#--> tags, onder de regel var siteURL = SP.PageContextInfo.get_siteAbsoluteUrl();. Verder maken we een array aan, die de nummer-namen toe gaat voegen aan de Accordion items door middel van een for-loop. Dit is nodig om te bepalen welk item van de accordion 'expanded' staat en dat de rest dus 'collapsed' is.
AddPostRenderCallback(ctx, function() {
$.getScript(siteURL + "/[pad naar het bestand]/bootstrap.min.js");

var itemNumbers = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"];

for (var i = 0; i < ctx["CurrentItems"].length; i++) {
$("a.accordion-toggle").eq(i).attr("href", "#collapse-" + itemNumbers[i]);
$(".panel-collapse").eq(i).attr("id", "collapse-" + itemNumbers[i]);
}
});

We hebben nu alles ingeladen en geprogrammeerd wat we nodig hebben om de Accordion werkend te krijgen. Nu moeten we de Accordion zelf nog maken, de HTML dus. Voeg als eerste een class 'accordion' aan de allereerste <div> toe (die staat boven de code waarmee we de externe files hebben ingeladen). Vervang daarna de HTML vanaf de <div> met CSS-class 'container' door onderstaande HTML:
<div class="panel-group acc-v1" id="accordion-1">

</div>

Let op: Laat wel de buitenste <div> (waaraan je de class 'Accordion' hebt toegevoegd) helemaal intact! Als je die weg haalt gaat het stuk.

Als laatste voegen we de code toe die het Item Display Template straks gaat inladen. Zet onderstaande code in de <div> die je zojuist hebt aangemaakt:
_#= ctx.RenderItems(ctx) =#_

Om het geheel af te maken kan je nog een titel invullen tussen de <title> tags. Dat was het v.w.b. de Control Display Template, we gaan nu verder met het Item Display Template.

Item Display Template

In het Item Display Template moeten we als eerste aan gaan geven welke velden we willen ophalen. Dat doen we in de <mso:ManagedPropertyMapping msdt:dt="string"> tag. Je ziet hierin al wat velden staan. We missen er echter nog één, namelijk het custom Content veld wat we eerder hebben aangemaakt. We hebben het veld op Site-level aangemaakt, wat betekent dat het na de eerstvolgende crawl automatisch een Managed Property is geworden. Eerder in deze tutorial heb ik je al een screenshot laten maken van de Managed Properties pagina, nu moet je wederom naar deze pagina gaan en vergelijken welk veld erbij is gekomen. In mijn geval was dat 'Content1OWSMTXT'. Die Managed Property moet je nu als volgt toevoegen aan het Display Template:
'Content1OWSMTXT':'Content1OWSMTXT' Zorg ervoor dat deze setjes steeds door een komma gescheiden blijven.

Vervolgens moeten we het 'Content1OWSMTXT' veld aan een Javascript variabele koppelen. Dat doe je binnen de <!--#_ en _#--> tags, onder de regel var siteURL = SP.PageContextInfo.get_siteAbsoluteUrl();:
var content = $getItemValue(ctx, "Content1OWSMTXT");

Als laatste voegen we de HTML toe die we per item willen renderen. Vervang alle HTML vanaf de <div> met de CSS-class 'item' door onderstaande:
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="collapse-One" href="#collapse-One">
_#= $htmlEncode(title) =#_
</a>
</h4>
</div>

<div id="collapse-One" class="panel-collapse collapse">
<div class="panel-body">
_#= STSHtmlDecode(content.value) =#_
</div>
</div>
</div>

Let op: Laat wel de buitenste <div> intact! Als je die weg haalt gaat het stuk.

zie ook hier weer alle code stukjes die beginnen met '_#='. Hierin worden, via de variabelen, de SharePoint velden aangeroepen.

Dat was m! Als je nu de pagina ververst waarop je de Accordion hebt geplaatst, dan zou hem nu in al zijn glorie moeten kunnen bewonderen ☺

Voor het gemak zijn hier nog voorbeelden van de volledige bestanden te downloaden:

13 maart 2015

Display Templates: Slider

In deze blogpost ga ik uitleggen hoe je door middel van een Display Template een slider kan maken die de hele breedte van je scherm bedekt. Ik ga daar de Revolution Slider in Unify voor gebruiken. Dat is een hele mooie, responsive slider en daarmee meteen geschikt voor mobiele devices. Unify is gebaseerd op Bootstrap, wat een veel gebruikt responsive platform is, een aanrader.

We gaan de slider baseren op het Search Results Web Part, en omdat de slider even breed als ons scherm moet worden, gaan we ook een aangepaste Page Layout maken. De slider komt er uiteindelijk zo uit te zien:



Start

De eerste stap die we nemen is het downloaden van de Starter Display Templates, die vind je in mijn andere blogpost. Sla de bestanden op onder een duidelijk herkenbare naam. In het geval van de slider zou dat iets als 'SliderControl' en 'SliderItem' kunnen zijn.

Upload de Display Templates (via de browser) naar Display Templates -> Search, in de Masterpage Gallery (Site Settings -> Web Designer Galleries -> Master pages and page layouts). Als je de bestanden hebt geüpload, zie je dat er vanzelf JS bestanden bij worden gegenereerd. Zo niet, dan is er iets niet goed gegaan.

Je kan ook via de 'New' button in de Display Templates-map nieuwe Display Templates aanmaken. De keuzes 'Control Display Template' en 'Item Display Template' zijn te vinden in de dropdown lijst.

Je kan vanaf nu het beste de Masterpage Gallery mappen (als je dat nog niet hebt gedaan, lees dan hier hoe je dat doet). De betreffende Display Templates kan je vanaf nu direct vanuit de verkenner openen in Notepad++ of een andere editor naar keuze.

Maak nu een Picture library aan in SharePoint. Geef deze een naam zonder spaties! Dit is belangrijk, want SharePoint vind spaties niet zo leuk, dus als er spaties in de url voorkomen, werkt het niet. Upload vervolgens de afbeeldingen die je in de slider wilt zien, in de library. Let er op dat je slider heel breed kan worden (zo breed als je scherm), maar wel een vaste hoogte heeft. De afbeeldingen moeten dus laag en breed zijn. Vul ook de velden van de titels en beschrijvingen in, die gaan we ook gebruiken in de slider.

Page Layout

De slider die we gaan maken is flexibel in breedte, maar altijd net zo breed als je scherm. Omdat voor elkaar te krijgen, moeten we de markup(HTML) op de betreffende pagina aanpassen. We maken de pagina 80% breed, behalve de slider, die wordt 100% breed.

Maak een nieuwe Page Layout aan. Dat kan je doen door een bestaande te kopiëren, maar ook door in de browser naar de Masterpage Library te navigeren (~/_catalogs/masterpage/Forms/AllItems.aspx) en in de ribbon op het pijltje bij New Document te klikken. Je krijgt dan een lijst te zien waar ook de Page Layout in staat.
Een derde optie is om de Design Manager te openen en daarin een Page Layout aan te maken. Die optie gebruik ik zelf meestal.

Voeg nu onderstaande CSS code toe aan de <!--MS:<asp:ContentPLaceHolder id="PlaceHolderAdditionalPageHead" runat="server">--> van de Page Layout (helemaal onderaan, dus vlak voor de sluit-tag): <!--MS:<style type="text/css">-->
/* De standaard contentBox heeft margins. Dat willen we niet, want de slider moet de hele paginabreedte innemen. De margins halen we dus weg. */
#contentBox {
margin: 0;
}

/* De sidenav staat nu standaard boven de slider. Die willen we er graag onder hebben, naast de rest van de content. Doen we dat niet, dan zal de sidenav de slider omlaag duwen en dat is niet mooi. De slider is nu flexibel in hoogte, maar die gaan we later nog beperken tot max 400px, vandaar deze waarde bij top. */
#sideNavBox {
position:relative;
top:500px;
}

/* Omdat de slider flexibel is (met een max-height van 400px), wordt hij steeds kleiner en minder hoog naarmate je scherm kleiner wordt. De mediaqueries gebruiken we om de relatieve afstand van de sidenav hierop aan te passen. In geval van IE werkte het alleen vanaf versie 9 en hoger.*/
@media screen and (max-width: 1024px) {
#sideNavBox {
top:450px;
}
}

@media screen and (max-width: 880px) {
#sideNavBox {
top:450px;
}
}

@media screen and (max-width: 730px) {
#sideNavBox {
top:450px;
}
}

/* Het is zeer waarschijnlijk dat er meer inhoud op je pagina komt dan alleen de slider. De contentPositioner positioneert een <div> op een breedte van 80% van je scherm en centreert deze op de pagina */
.contentPositioner {
margin: 0 auto 0 220px;
padding-top: 15px;
}

/* Hieronder staan 3 Web Part zones, twee smallere aan de zijkanten en een bredere in het midden */
.wpzLeft {
float: left;
width:25%;
margin:0 2% 0 0;
}

.wpzCenter {
float: left;
width: 46%;
}

.wpzRight {
float: left;
width: 25%;
margin: 0 0 0 2%;
}
<!--ME:</style>-->

Het is 'best practise' om zo min mogelijk inline CSS te gebruiken, dus normaal gesproken kun je de styling van Page Layouts het beste in je 'algemene' style sheet vanuit de custom Masterpage, of de Additional CSS instelling definiëren. Nu doe ik het even zo, omdat we ons hier willen richten op deze specifieke pagina, zonder alle rompslomp eromheen. In de CSS heb ik d.m.v. comments aangegeven waar de regels precies voor dienen, mocht je dat interessant vinden :-)

De volgende stap is de HTML op de Page Layout. Die vind je hier.
Vervang alle code die in de <!--MS:<asp:ContentPlaceHolder id="PlaceHolderMain" runat="server">--> tag staat, op de Title snippet na. In de code staan de Web Part zones er al in. Die hebben ieder een eigen ID. Het zou kunnen dat dat op jouw installatie problemen geeft. Als dat zo is, genereer dan zelf nieuwe IDs via de Snippet Tool of SharePoint Designer.

Als laatste moet je je Page Layout instellen op de gewenste pagina. Dat doe je door naar die pagina te navigeren, op het PAGE tabje te klikken van de ribbon en vervolgens op de Page Layout knop te klikken. You zou hier je custom Page Layout moeten kunnen kiezen, maar alleen als je hem eerst hebt gepubliceerd.

Web Part

Om de resultaten te kunnen zien van de aanpassingen die je straks in de Display Templates gaat maken, moeten we eerst het Web Part aanmaken. Zoals eerder vermeldt gebruiken we hiervoor het Search Results Web Part.

  1. Ga naar de pagina waar je de slider wilt plaatsen.
  2. Voeg een Web part toe aan de zone Slider Zone.
  3. Kies het Search Results Web Part en klik op Add.
  4. De volgende stap is het maken van de query zodat de juiste gegevens worden opgehaald.


  5. Ga naar het Edit Web Part menu (zie het pijltje rechts bovenin het Web Part)
  6. Klik op Change Query
  7. In het tabje Basics (zorg dat de Quick mode aan staat, dat zie aan het linkje rechts bovenin het tabje Switch to Advanced Mode/Switch to Quick Mode) selecteer je bij Select a query de optie Pictures (System).
  8. Bij Restrict by app kies je voor Specify a URL en geef je de volledige url naar je eerder aangemaakte Pictures library in.
  9. Restrict by tag moet blijven staan op Don't restrict by any tag.
  10. Klik op OK.
  11. Klik in het Web Part menu op Apply (nog niet op OK!).
  12. Waarschijnlijk wint wat je nu ziet niet de schoonheidsprijs, maar je zou wel wat content uit de Pictures Library moeten zien nu. Klik het Web Part Edit menu nog niet weg, want we gaan nu de juiste Display Templates instellen.


  13. Klik nu op de + bij Display Templates.
  14. Als eerste zie je nu een dropdown met Results Control Display Template. staan. In die dropdown zou je je eigen Control Display Template moeten zien, die je eerder hebt aangemaakt. Selecteer die. (Zie je hem niet? Heb je hem gepubliceerd?)
  15. Er onder staan twee radiobuttons. Selecteer de onderste waarbij staat: Use a single template to display items.
  16. Hieronder zie je weer een dropdown menu. Ook hier zou je eigen Item Display Template tussen de opties moeten staan. Selecteer die.
  17. Klik de + bij Display Templates nu weer dicht.
  18. De Display Templates zijn nu ingesteld, maar er zijn ook nog wat instellingen die andere dingen weergeven buiten de Templates. Die willen we niet zien, dus dat moeten we nog even uitschakelen.


  19. klik op de + bij Settings.
  20. Vink alles uit, behalve Show ranked results (Als we die ook uit zouden zetten, zouden we helemaal geen data zien in het Web Part).
  21. Het getal bij Number of results per page doet er niet toe, dat regelt jQuery straks. Kan je dus laten staan zoals t staat.
  22. Klik de + next bij Settings weer dicht.
  23. Standaard laat een SharePoint Web Part een titlebar zien, die willen we natuurlijk niet bij de slider, dus dat passen we ook nog even aan.


  24. Klik de + bij Appearance open.
  25. Onderin zie je nu Chrome Type staan, met een dropdown menu. Kies de optie None.
  26. Voor de netheid kan je bovenin bij title nog even een naam voor je slider invullen. Die naam is niet direct zichtbaar, want dat hebben we net uitgezet.

Zo, dat was het v.w.b. de instellingen. Het lijkt nu nog helemaal niet op een slider, dus we gaan aan de slag met de invulling van de Display Templates.

Display Templates

Zoals ik in mijn eerdere blogpost heb vermeld, werken Display Templates met z’n tweeën, één als 'hoesje' voor het geheel (Control Display Template) en de ander voor individuele items (Item Display Template). Laten we beginnen met de eerste.

Control Display Template

De Control Display Template is niet alleen maar de markup voor het Web Part, het bevat ook alle referenties naar CSS en Javascript bestanden. Dat laatste beginnen we mee. Hieronder kan je de betreffende bestanden downloaden (upload ze zelf naar de gewenste locatie in SharePoint):

Als eerste gaan we de slider even beperken tot maximaal 400px hoogte, alles daaronder zal hij flexibel blijven. Open hiervoor het bestand 'plugins.css'. Op regel 76 vind je de selector '.revolution-mch-1:after'. Voeg hierin de regel 'max-height:400px;' toe en sla op.

Open je Control Display Template in Notepad++ (of een andere editor naar keuze) en vervang alles tussen de <script> tags met onderstaande:
$includeScript(this.url, "~sitecollection/[Pad naar het bestand]/jquery.min.js");
$includeCSS(this.url, "~sitecollection/[Pad naar het bestand]/style.css");
$includeCSS(this.url, "~sitecollection/[Pad naar het bestand]/settings.css");

Dan is er nog een fallback voor oude IE browsers, die voeg je als volgt direct na de </script> tag toe:
<!--[if lt IE 9]>
<script>
$includeCSS(this.url, "~sitecollection/[pad naar het bestand]/settings-ie8.css");
</script>
<![endif]-->

Er is hier nog wel een potentieel addertje. In het bestand 'style.css' zijn via @import verwijzingen opgenomen naar een aantal andere css bestanden. Die bestanden staan in dezelfde map, dus het pad bestaat uit slechts de bestandsnaam. Nu wil het wel eens zo zijn dat SharePoint deze paden relatief aan de siteroot ziet i.p.v. relatief aan de map waarin ze staan. Dat kan dus betekenen dat je de gehele url moet specificeren in de @import verwijzingen.
Daarnaast heb ik op één van mijn SPO omgevingen dat bij het navigeren zonder server refresh (dus F5 ipv CTRL + F5), de aanvullende CSS bestanden ineens helemaal niet meer worden geladen. Mocht je hetzelfde probleem ervaren, dan kan je de plugins.css op dezelfde manier in je Control Display Template aanroepen als de style.css.
Je ziet het overigens heel gemakkelijk aan de slider als het laden van deze aanvullende CSS bestanden niet werkt, dan gaat de slider zich raar gedragen en de titel is bijvoorbeeld heel klein.
Zelf heb ik dit probleem op de ene SharePoint Online omgeving wel en op de andere SharePoint Online omgeving niet. Het is me een raadsel waarom… Dus wie het weet mag het zeggen!

De volgende stap is het inladen en gebruiken van de Javascript voor de slider zelf. Dat voeg je toe binnen de <!--#_ en _#--> tags, onder de regel var siteURL = SP.PageContextInfo.get_siteAbsoluteUrl();:
AddPostRenderCallback(ctx, function() {
$.getScript(siteURL + "/[pad naar het bestand]/jquery.themepunch.revolution.min.js", function(){
$.getScript(siteURL + "/[pad naar het bestand]/jquery.themepunch.tools.min.js", function(){
$.getScript(siteURL + "/[pad naar het bestand]/revolution-slider.js", function(){
jQuery(document).ready(function() {
RevolutionSlider.initRSfullWidth();
});
});
});
});
});

Om te zorgen dat de slider foutloos werkt, moeten de javascript bestanden in een bepaalde volgorde worden ingeladen. Aangezien SharePoint alles asynchroon inlaadt tussen de <script> tags, ontstaan er bugs (sommige js bestanden worden niet altijd geladen, waardoor de slider stuk gaat). Met bovenstaande code maken we dus telkens een function die een bestand inlaadt en vervolgens weer een nieuwe function aanroept, die op zijn beurt weer een bestand inlaadt, etc. Net zo lang tot we alle bestanden hebben geladen.

We hebben nu alles ingeladen en geactiveerd wat we nodig hebben om de slider werkend te krijgen. Nu moeten we de slider zelf nog maken, de HTML dus. Voeg als eerste een class 'RevolutionSlider' aan de allereerste <div> toe (die staat boven de code waarmee we de externe files hebben ingeladen). Vervang daarna de HTML vanaf de <div> met CSS-class ‘container’ door onderstaande HTML:
<div class="tp-banner-container">
<div class="tp-banner">
<ul>

</ul>
<div class="tp-bannertimer tp-bottom"></div>
</div>
</div>

Let op: Laat wel de buitenste <div> (waaraan je de class 'RevolutionSlider' hebt toegevoegd) helemaal intact! Als je die weg haalt gaat het stuk.

Als laatste voegen we de code toe die het Item Display Template straks gaat inladen. Zet onderstaande code tussen de <ul> tags:
_#= ctx.RenderItems(ctx) =#_

Om het geheel af te maken kan je nog een titel invullen tussen de <title> tags. Dat was het v.w.b. de Control Display Template, we gaan nu verder met het Item Display Template.

Item Display Template

In het Item Display Template moeten we als eerste aan gaan geven welke velden we willen ophalen. Dat doen we in de <mso:ManagedPropertyMapping msdt:dt="string"> tag. Je ziet hierin al wat velden staan. We missen er echter nog één, namelijk de afbeelding. Voeg de volgende code toe aan de ManagedPropertyMapping tag:
‘PictureURL’:’ PictureURL’ Zorg ervoor dat deze setjes steeds door een komma gescheiden blijven.

Vervolgens moeten we het 'PictureURL' veld aan een Javascript variabele koppelen. Dat doe je binnen de <!--#_ en _#--> tags, onder de regel 'var siteURL = SP.PageContextInfo.get_siteAbsoluteUrl();':
var pictureURL = $getItemValue(ctx, "PictureURL");

Als laatste voegen we de HTML toe die we per item willen renderen. Vervang alle HTML vanaf de <div> met de CSS-class 'item' door onderstaande:
<li class="revolution-mch-1" data-transition="fade" data-slotamount="5" data-masterspeed="1000" data-title="_#= $htmlEncode(title) =#_">
<img src="_#= pictureURL =#_" alt="_#= $htmlEncode(title) =#_" data-bgfit="cover" data-bgposition="left top" data-bgrepeat="no-repeat">
<div class="tp-caption revolution-ch1 sft start"
data-x="center"
data-hoffset="0"
data-y="100"
data-speed="1500"
data-start="500"
data-easing="Back.easeInOut"
data-endeasing="Power1.easeIn"
data-endspeed="300">
_#= $htmlEncode(title) =#_
</div>

<div class="tp-caption revolution-ch2 sft" style="z-index: 6"
data-x="center"
data-hoffset="0"
data-y="190"
data-speed="1400"
data-start="2000"
data-easing="Power4.easeOut"
data-endspeed="300"
data-endeasing="Power1.easeIn"
data-captionhidden="off">
_#= $htmlEncode(description) =#_
</div>

<div class="tp-caption sft" style="z-index: 6"
data-x="center"
data-hoffset="0"
data-y="310"
data-speed="1600"
data-start="2800"
data-easing="Power4.easeOut"
data-endspeed="300"
data-endeasing="Power1.easeIn"
data-captionhidden="off">
<a href="_#= linkURL =#_" class="btn-u btn-brd btn-brd-hover btn-u-light">Read More</a>
</div>
</li>

Let op: Laat wel de buitenste <div> intact! Als je die weg haalt gaat het stuk.

zie ook hier weer alle code stukjes die beginnen met '_#='. Hierin worden, via de variabelen, de SharePoint velden aangeroepen.

Dat was m! Als je nu de pagina ververst waarop je de slider hebt geplaatst, dan zou hem nu in al zijn glorie moeten kunnen bewonderen ☺

Voor het gemak zijn hier nog voorbeelden van de volledige bestanden te downloaden:

20 februari 2015

Display Templates - Tips & Tricks

In mijn vorige blogpost heb ik al een introductie geschreven over Display Templates. Deze blogpost is meer een verzameling van kleine dingetjes waar ik tegenaan ben gelopen tijdens het werken met de Display Templates.

Soorten Display Templates

Er zijn verschillende soorten display templates en voor iedere soort zijn er al standaard een aantal verschillende aangemaakt in SharePoint. Het loont dus de moeite om eerst even te checken of er niet al een geschikt template bestaat voor wat je wilt bereiken (Zelf heb ik altijd wel wat te zeuren, dus ik maak toch wel weer eigen templates ☺). Als je ook maar iets afwijkt van de standaard, wijzig dan niet het standaard Template, maar kopieer hem en maak een nieuwe aan.

Je vindt hier een overzicht van soorten en standaard Display Templates.

Managed Properties

Managed Properties zijn de SharePoint velden die je uit kan lezen in de Display Templates. Deze zijn er in alle soorten en maten en daarmee zijn er allerlei verschillende methoden om ze weer te geven. Daarover later in deze blogpost meer.

Er zijn in SharePoint veel meer properties dan alleen de Managed properties, deze heten Crawled Properties. Je kunt die echter niet direct uitlezen in een Display Template. Je moet ze eerst mappen naar een (bestaande of zelf aangemaakte) Managed Property. Hoe je dat doet lees je hier.

Omdat ik in SharePoint Online werk en dus geen Central Admin heb, hier nog even de link naar de Managed Properties lijst:
https://[JouwDomein].sharepoint.com/_layouts/15/listmanagedproperties.aspx?level=sitecol

Managed Properties uitlezen

In de <head> sectie van het Item Display Template Staat een tag <mso:ManagedPropertyMapping msdt:dt="string">. In deze tag moet je de Managed Properties definiëren die je uit wilt lezen. Dit ziet er ongeveer zo uit:
<mso:ManagedPropertyMapping msdt:dt="string">'Link URL'{Link URL}:'Path','Line 1 code'{Line 1}:'Title','Line 2 code'{Line 2}:'Description'</mso:ManagedPropertyMapping>

De definitie van een Managed Property is als volgt:
'Property Display Name'{Property Name}:'Managed Property Name'

  1. Property Display Name is volgens Microsoft de naam van de Property die te zien is in het Web Part bewerkingsmenu wanneer het Display Template is geselecteerd. Persoonlijk snap ik niet wat ze hiermee bedoelen. Ik zie het nergens terug. Als iemand hier meer van weet, hoor ik het heel graag!
    Voor zover ik weet is dit de waarde waarmee je de property aanroept in het script in je Display Template.
  2. Property Name is een identifier die gekoppeld is aan de Managed Property. Deze is zichtbaar als veld in het Web Part bewerkingsmenu onder 'Property Mappings'. Hier kan je ook een andere Manged Property aan datzelfde veld koppelen (dat zie je overigens niet terug in het Display Template, daarin stel je alleen de default waarde in).

    Deze Property Name is dus alleen van waarde als het Web Part de bewerkingsoptie 'Property Mappings' bevat. Is dat niet zo, dan kan je dit ook weglaten en de syntax als volgt gebruiken:
    'Property Display Name':'Managed Property Name'
  3. Managed Property Name is de werkelijke Managed Property, zoals het SharePoint systeem hem herkend. Het kunnen één of meer Managed Properties zijn, gescheiden door een puntkomma (;). Tijdens runtime wordt de lijst (die dus één of meerdere items kan bevatten) van links naar rechts uitgelezen en het eerste item dat een waarde van een Managed Property ophaalt, wordt toegepast.

Nadat je een Managed Property hebt gemapped, kan je het uitlezen door in de <body> van het Display Template een variabele (javascript) aan te maken:
<!--#_
var title = $getItemValue(ctx, "Line 1 code");
_#-->
Ik heb hier even deels de standaard TwoLine Item Display Template van SharePoint gekopieerd (en een beetje aangepast), omdat hierin het verschil goed duidelijk is.

Om de waarde van de Managed Property vervolgens weer te geven in je HTML, roep je de variabele aan op deze manier:
_#= variabele =#_
In het geval van Tekst waarden is het verstandig om de volgende syntax aan te houden:
_#= $htmlEncode(variabele) =#_
De htmlEncode zorgt ervoor dat alle special tekens die een script kunnen laten klappen, gecodeerd worden. Zo wordt een quote (') bijvoorbeeld omgezet naar &#39;.

Neem een kijkje in de standaard Display Templates van SharePoint om te zien wat er allemaal mogelijk is. Ook op deze website staat een hoop waardevolle informatie over scripten in Display Templates.

Afbeeldingen weergeven

De Managed Properties van afbeeldingen en iconen bestaan eigenlijk gewoon uit tekst, namelijk een url. Om dit om te zetten naar een afbeelding moet je de Managed Property dus aanroepen in de src van een <img> tag. De syntax zou er zo uit kunnen zien:
<img src="_#= variabele =#_" alt="" />
Er zit wel een valkuil in: SharePoint vindt urls die zijn onderbroken met een spatie niet zo leuk… Normaal worden die spaties opgevuld met een %20, maar hier dus niet. Zorg er dus voor dat je de Picture Library waar je de afbeeldingen uit wilt halen, GEEN spaties in de naam bevatten, of knutsel wat met JavaScript om de spatie te vervangen voor een %20 (geen idee hoe, niet geprobeerd).

Datums weergeven

Dit is ook een leuke, want je hebt hierin de vrijheid om het door jou gewenst format te gebruiken. Dit zou er bijvoorbeeld zo uit kunnen zien: _#= variabele.format("d MMMM yyyy") =#_ Maar je kan de datum ook splitsen. Zo heb ik bijvoorbeeld eens een gekleurd vakje gemaakt, met de datum daarin opgeknipt in twee stukken. Zo staan de dag en maand onder elkaar ipv naast elkaar: <div class="date-formats">
<span>_#= variabele.format("d") =#_</span> <!-- dag in cijfers -->
<small>_#= variabele.format("MMMM") =#_</small> <!-- maand in woorden -->
</div>

Een overzicht van alle beschikbare formats vind je hier.

File Type Icon uitlezen

Een gevalletje apart, want dit werkt, in ieder geval bij Search Result Display Templates, niet zoals je zou verwachten (mij een raadsel waarom niet, maar het is zo). Het file type icon is het icoontje dat je in bijvoorbeeld document libraries ziet staan als eerste kolom van ieder document. Het kan bijvoorbeeld een MS Word-icoontje zijn, of Excel, PDF, etc.

Om het toch voor elkaar te krijgen, stelen we hem gewoon even van een ContentBySearch Display Template. Dat doe je zo:

  1. In de Control Display Template voeg je het volgende script in: <script>
    $includeScript(this.url, "/_layouts/15/search.cbs.js");
    </script>
  2. In het Item Display Template voeg je de volgende regel code toe: var iconUrl = Srch.ContentBySearch.getIconSourceFromItem(ctx.CurrentItem);
  3. Roep de variabele aan in een <img> tag: <img src="_#= $urlHtmlEncodeString(iconURL) =#_" />

En klaar is Kees! Ik heb hierbij overigens geen styling meegenomen, dus het kan zijn dat je dat nog moet fixen. Binnenkort post ik een gedetailleerde tutorial over het maken van een 'Mijn Documenten' Display Template, waarin ik ook het file type icon meeneem.

Dit was het weer even voor nu, hopelijk heb je er wat aan ☺

Prefer to read this in English?

SharePoint 2013 - Display Templates

Display Templates zijn op zichzelf staande bestanden waarin Managed Properties (SharePoint velden, zoals Title, Description, etc) worden uitgelezen en HTML, CSS en JavaScript kan worden verwerkt. Deze bestandjes worden vervolgens gerenderd in een of meerdere pagina's van je SharePoint site. Je gebruikt ze om de weergave van Web Parts te bepalen. Ze bestaan uit twee HTML-bestanden en bij ieder van deze bestanden wordt automatisch een JS-bestand gegenereerd en gekoppeld. Met deze JS-bestanden doe je zelf niets, dat gaat allemaal automatisch.

Het eerste HTML bestand is de Control Display Template en de tweede is het Item Display Template. De Control Display Template bepaalt de algemene structuur van hoe de resultaten worden gepresenteerd in het Web Part (zoals lijsten, lijsten met paginering, sliders, etc). Bijvoorbeeld een <ul> waar je <li>'s in wilt gaan renderen. Daarnaast wordt het gebruikt om JavaScript en CSS bestanden in te laden.

Het Item Display Template bepaalt hoe elk resultaat in de set wordt weergegeven (zoals lijst items, afbeeldingen, tekst, etc). Dat zou dan dus een <li> (inc inhoud) zijn als we het bovenstaande voorbeeld aanhouden. Één <li>? Ja, het is een template, dus er gaat straks een lus doorheen die steeds diezelfde <li> gebruikt om het geheel op te bouwen. De Web Part instellingen bepalen hoeveel items dat zijn, Display Templates gaan daar niet over.

De reden dat er twee losse (Control en Item) bestanden zijn in plaats van alles in één, is dat je Control- en Item templates willekeurig kan combineren. Het zijn dus niet persé vaste setjes. Het kan heel goed zijn dat je voor dezelfde Control Display Template, meerdere Item Display Templates maakt, die bijvoorbeeld weer steeds andere SharePoint velden (Managed Properties) aanroepen, maar wel dezelfde JS/CSS en (container)markup gebruiken.

Leuk verhaal, maar hoe werkt dit nou in de praktijk?
Laten we beginnen bij het begin. Omdat ik zelf gebruik heb gemaakt van een SharePoint Online omgeving (waar je dus niet wilt deployen vanuit Visual Studio), ga ik daar in deze blogpost ook even vanuit. We gaan zodoende gebruik maken van de SharePoint Design Manager en Notepad++.

Persoonlijk vind ik de 'Search Results' methode het makkelijkst werken. Dat is slechts één en hetzelfde Web Part (namelijk het Search Results Web Part), waar je letterlijk en figuurlijk alle kanten mee op kan. Je plaatst dan dus voor ieder Web Part dat je wilt hebben op je pagina, een Search Results Web Part met een eigen query en laat de Display Templates bepalen hoe en wat er zichtbaar is. Zo kan hetzelfde Web Part er telkens compleet anders uitzien en andere data weergeven.
Nou moet ik toegeven dat ik nog niet van alle soorten Display Templates heb bekeken hoe en waar ze worden toegepast en of er in sommige gevallen dus betere alternatieven zijn dan Search Results. Wat ik wel zeker weet is dat Search Results in ieder geval goed werkt voor wat ik wilde bereiken.

Start

Je vindt de Search Results Display Templates hier:
https://[JouwDomein].sharepoint.com/_catalogs/masterpage/Display%20Templates/Search/

Dit gaat op SiteCollection niveau, dus als je een onderliggende SiteCollection hebt, zou het pad er zo uitzien:
https://[JouwDomein].sharepoint.com/sites/[JouwSiteCollection]/_catalogs/masterpage/Display%20Templates/Search/

Map Network Drive

Het werkt t makkelijkst om de Masterpage Gallery te mappen naar je computer, zodat je deze vanuit de verkenner kan openen. Lees hier hoe.
Let op dat: Je IE moet gebruiken, je bij het inloggen het 'ingelogd blijven' vinkje AAN moet zetten, je SharePoint domein/site aan je trusted sites toe moet voegen en je een willekeurige library moet openen dmv de 'Open in Explorer' optie in de ribbon (alleen mogelijk met IE). Na die stappen zou je moeten kunnen mappen. Zo lang als dat je ingelogd bent op de site, kan je via de verkenner de MP Gallery benaderen. Log je uit, dan kan je er niet meer bij. In de MP Gallery navigeer je naar Display Templates -> Search voor de juiste locatie.

Starter Display Templates

Via de links hieronder kan je 'kale' Starter Templates downloaden om mee te beginnen. De Control bevat een heading en een container voor de items, de Item Template toont de Title en Description.


Inderdaad, de JS files ontbreken. Klopt, die maakte SharePoint namelijk zelf aan, als je bovenstaande bestanden upload naar de Display Template Gallery. Je moet dit dan wel via de SharePoint user interface doen (dus via de browser).

Hoe nu verder?

Omdat het een heeeeel erg lange lap tekst wordt als ik de verschillende uitwerkingen allemaal in deze blogpost ga beschrijven, heb ik losse blogposts gemaakt voor een aantal individuele uitwerkingen:

Dan heb ik nog een blogpost met tips & tricks. Natuurlijk ben ik zelf tegen issues aangelopen waarmee ik heb geworsteld om het op te lossen. Om jullie dit leed te besparen staan in deze blogpost de oplossingen van deze issues en best practices om problemen te voorkomen.

Wat ook heel interessant is, is deze pagina. Je leest hier uitgebreid over het hoe en waarom en de opbouw van Display Templates.

Want to read this in English?

09 juli 2014

SharePoint 2013 - Access Denied voor users met volledig beheer rechten

Dit keer geen blog over design of development, maar een probleem dat ik laatst ben tegen gekomen bij een key user van mijn klant. De betreffende klant maakt sinds kort gebruik van Office365 met SharePoint (2013) Online.

Probleem

De key user zit in de site owners groep in een SharePoint (2013) Online site collection, maar had plotseling geen toegang meer tot zijn sites.

Het was al snel duidelijk dat het probleem zat in het feit dat de key user de rechten op de site collection heeft gebroken, waarbij hij de standaard (EN) [sitenaam] Owners/(NL) Eigenaren van [sitenaam] groep alle rechten heeft ontnomen en in plaats daarvan een nieuwe groep heeft aangemaakt met een andere naam (ivm richtlijnen van het bedrijf).

Je zou dus zeggen dat de stap om dit te herstellen, het herstellen van de rechten van de (EN) [sitenaam] Owners/(NL) Eigenaren van [sitenaam] groep is. Dit bleek echter niet alles op te lossen. De key user kon nu wel weer bij de site, maar bleef op bepaalde items in de site settings een 'Acces Denied' krijgen. Hij kon onder andere geen rechten meer instellen, wat een blocking issue was.

Na een tijdje zoeken en proberen (browser cache weg gooien, appdata cache weggooien, andere browser proberen, andere computer proberen) kwam ik dit artikel van Microsoft Support tegen.

Oorzaak

Het blijkt dat, als de rechten van de standaard (EN) [sitenaam] Owners/(NL) Eigenaren van [sitenaam] groep worden ontnomen en daarna weer worden teruggezet, de rechten niet overal worden hersteld. Op bepaalde lijsten is er nu geen enkele groep meer die nog rechten heeft. Hieronder valt bijvoorbeeld ook de (EN) Access requests/(NL) Toegangsaanvragen lijst (Dit is dus het geval wanneer bij het aanmaken van de site collection is gekozen om de (EN) Allow access requests/(NL) Sta toegangsaanvragen toe setting in te schakelen). De lijsten waarop de rechten nog ontbreken, veroorzaken tevens dat een aantal andere functionaliteiten niet meer werken. In het geval van de 'Pending requests' lijst, wordt behalve de lijst zelf, ook de (EN) Site permissions/(NL) Site machtigingen geblokkeerd.

Oplossing

Nu kan je natuurlijk de hele webapplicatie weg gooien en opnieuw beginnen, maar het kan ook wat minder drastisch. De oplossing voor dit probleem is dat je alle rechten op de getroffen lijsten handmatig moet gaan herstellen. Omdat SharePoint wil voorkomen dat gebruikers (die niet weten waar ze mee bezig zijn) onherstelbare schade aanrichten aan deze onmisbare lijsten, is het niet makkelijk om bij de instellingen van deze lijsten te komen. Hieronder leg ik uit hoe je dat toch voor elkaar krijgt. We gaan beginnen met de (EN) Access Requests/(NL) Toegangsaanvragen lijst. Deze vind je hier:

  • (EN) https://URL-van-de-betreffende-site-collection/Access%20Requests/pendingreq.aspx
  • (NL) https://URL-van-de-betreffende-site-collection/Toegangsaanvragen/pendingreq.aspx
  1. Log in op de getroffen site collectie met een user die administrator rechten (op SharePoint dus, niet op je computer) heeft, en navigeer naar de (EN) Access Requests/(NL) Toegangsaanvragen lijst. Gebruik hiervoor Internet Explorer.
  2. Druk op F12 om de Developer Tools in IE te openen.
  3. Klik op de Network-tab en druk op F5 of klik op het groene pijltje links bovenin de Developer tools (IE10+) om het netwerk verkeer te volgen.
  4. Ververs de pagina in de browser. Als de pagina weer geladen is, stop dan het volgen van het netwerk verkeer door op SHIFT+F5 te drukken of op het rode blokje te klikken.
  5. In het venster van de Developer tools staat een url lijst. Dubbelklik op het bovenste resultaat (dat moet eindigen op pendingreq.aspx).
  6. Klik in het venster van de Developer tools op Request body.
  7. Wederom in de Developer tools, vul 'pageListId:' in het zoekvenster en druk op ENTER.
  8. Het zoekresultaat zal geel gemarkeerd worden weergegeven. Kopieer de GUID die bij het pageListId: staat. De GUID is de combinatie van letters en cijfers die tussen de {} staat. Kopieer de {} ook mee. De GUID is het identificatiemiddel van de lijst. Iedere lijst heeft een unieke GUID.
  9. Open een nieuwe tab in IE en voer de volgende url in de adres balk:
    https://URL-van-de-betreffende-site-collection/_layouts/15/ListEdit.aspx?List={GUID}
    (Vul bij {GUID} het nummer in dat je in de vorige stap hebt gekopieerd, voorbeeld:
    https://voorbeeld.sharepoint.com/sites/voorbeeld1/_layouts/15/ListEdit.aspx?List={3536637D-E28A-4F12-9749-0B789E0A2448}
  10. Je bent nu op de pagina voor de (EN) List settings/(NL) Lijst instellingen. Klik nu op (EN)Permissions for this list/(NL)Machtigingen voor dit lijstitem.
  11. Er is nu niets te zien, wat betekend dat niemand rechten heeft op deze lijst. Voeg nu de groep (EN) [sitenaam] owners/(NL) Eigenaren van [sitenaam] toe en geef deze groep volledig beheer.

Dit was het herstelproces voor de 'Pending requests' lijst. Als je nu met een user uit de (EN) [sitenaam] Owners/(NL) Eigenaren van [sitenaam] groep inlogt en naar de (EN) Site permissions/(NL) Sitemachtigingen navigeert, zal je zien dat alles nu weer goed gaat. Je bent echter nog niet helemaal klaar. Het probleem doet zich ook nog voor op 2 andere lijsten:

  • (EN) Device Channels/(NL) Apparaat kanalen lijst: (EN/NL) https://URL-van-de-betreffende-site-collection/DeviceChannels/AllItems.aspx
  • (EN) Translation Status/(NL) Vertaalstatus lijst: (EN/NL) https://URL-van-de-betreffende-site-collection/Translation%20Status/Alle%20gebruikers.aspx

Om deze lijsten ook te herstellen doe je hetzelfde als wat je zojuist voor de 'Pending requests' lijst hebt gedaan.

Tip

Loop je nou vaak tegen dit probleem aan, dan kan het ophalen van de GUID's ook wat eenvoudiger. Je kunt hier een tool downloaden welke na het invoeren van de url van je site, de site kan uitlezen. Deze tool leest bijvoorbeeld ook de schema.mxl uit, waarin de GUID is vermeld. Onderstaande stappenplan geldt in dit geval als vervanging voor de stappen 1 t/m 8 van de handleiding eerder in dit artikel.

  1. Open de 'SharePoint 2013 Client Browser' tool.
  2. Geef de url van de getroffen site op.
  3. Klik in het linker venster op de + bij 'Lists' en selecteer (EN) Access Requests/(NL) Toegangsaanvragen.
  4. Klik in het rechter venster op de tab Schema XML.
  5. In de code die je nu ziet, staat een <List> tag met een property genaamd 'ID', dat is de GUID. Voorbeeld: ID="{AE3ED198-0E26-47F2-B611-27E89FE00831}" Kopieer de GUID (Inc {}) en ga verder met stap 9 van de handleiding eerder in dit artikel.

25 april 2014

SharePoint 2013 List Item Attachment

Het heeft even een tijdje geduurd, maar hier ben ik dan weer met een nieuwe blogpost. Het onderwerp waar ik het dit keer over ga hebben is de functionaliteit in SharePoint waarbij een document als attachment bij een list item gevoegd kan worden.

Het probleem waar ik mee geconfronteerd werd, was dat men de attachments graag als lijstje van korte klikbare links in een SharePoint 2013 app wilde weergeven. Omdat dit ietwat ingewikkelder is dan het weergeven van een willekeurige column/field uit een lijst, vind ik het de moeite waard om in een blog uit te leggen hoe je bovenstaande voor elkaar krijgt. SharePoint apps bestaan uitsluitend uit client side code, dus we gaan met javascript aan de slag.

Voor ik begin wil ik nog even vermelden dat ik deze blogpost heb kunnen schrijven dankzij mijn collega’s Mirjam van Olst en Laurens Ruijtenberg, die mij hebben geholpen het mysterie op te lossen.

Wat je nodig hebt

In deze blogpost ga ik er vanuit dat je al een werkende SharePoint omgeving hebt en een SharePoint solution, waarin je (onder andere) de list item attachments wil gaan tonen. Zelf werk ik met Visual Studio 2013, dat is het makkelijkst om SharePoint code te debuggen. De gratis versie heet Visual Studio Express en is hier verkrijgbaar.

Om list item attachments op te halen, heb je vanzelfsprekend een SharePoint list nodig. Zelf heb ik een list met de naam ‘My Items’. Deze naam zal ik, voor de duidelijkheid, ook blijven gebruiken in de code. Je kan de list aanmaken via de solution (best practice), of een list aanmaken via de user interface van SharePoint. Vul je SharePoint list alvast met wat list items en voeg wat attachments aan die items toe. Dat scheelt later weer een hoop hersenkraken over waarom het niet werkt (als er geen attachments zijn, kunnen ze immers ook niet worden weergegeven).

Verder heb je jQuery en de ‘jQuery library for SharePoint Web Services’ nodig. De laatste vind je hier. jQuery zelf kan je via Visual Studio installeren (Tools -> Extensions and Updates).

We gaan in deze blogpost uit van 3 bestanden:

  • Een HTML template waarin we onze content gaan weergeven.
  • Een Javascript bestand welke bepaald wat we gaan weergeven, hoe we het gaan weergeven en waar we het gaan weergeven. Omdat dat ik zelf met de MVC methode heb gewerkt, is in mijn geval de Javascript verdeeld over 2 lossen bestanden. Doe wat je het prettigst vind.
  • Een CSS bestand om de noodzakelijke opmaak toe te voegen.

Beginnen

In het HTML template gaan we een korte structuur aanmaken, zodat we straks een plekje hebben om de list item attachments weer te geven. Ik schrijf niet de complete SharePoint pagina uit, alleen het stukje waar het hier om gaat.

<div class="container">
<h3 id="title">Attachments</h3>
<h3 id="listAttachments"></ul>
</div>

Het is niet veel: Een div om het geheel te positioneren, een header en een lijst waarin ieder attachment straks als list item wordt ingevoegd.

Data aanroepen

Dan komen we nu toe aan het grootste en moeilijkste deel, de javascript code. Er zijn een aantal dingen die we met javascript moeten gaan regelen:

  • We moeten de applicatie gaan vertellen wat we willen zien
    De query bestaat uit XML en die moeten we gaan opbouwen via Javascript.
  • We moeten de applicatie gaan vertellen hoe we het willen weergeven.

Query

De eerste stap is het aanroepen van de SharePoint list en definiëren wat we willen zien van die list.

var MyItemsRepository = function () {
this.QueryListOptions = function (query, viewFields, options) {
var result;

$().SPServices({
operation: "GetListItems",
async: false,
listName: "My Items",
webURL: commonSiteCollectionUrl,
CAMLQuery: query,
CAMLViewFields: viewFields,
CAMLQueryOptions: options,
completefunc: function (xData, Status) {
result = xData;
}
});

return result;
}

// Verderop in de tutorial maken we nog een stukje code aan dat nodig is om de attachments op te roepen, zet die code hier
}

var myItemsRepository = new MyItemsRepository();

In dit stukje code wordt een call gemaakt naar SharePoint en wordt de list met de naam ‘My Items’ aangeroepen. Hier wordt achter de schermen de ‘jQuery library for SharePoint Web Services’ voor gebruikt. Vervolgens zien we een aantal parameters Waar de lettercombinatie CAML in staat. CAML staat voor ‘Collaborative Application Markup Language’. Dit is een op XML gebaseerde taal die in SharePoint wordt gebruikt om fields en views te definiëren. De waarden van deze CAML parameters die je in de bovenstaande code ziet, zijn variabelen die we later gaan definiëren.

CamlDesigner2013

Als je veel verstand hebt van CAML en/of XML, zou je de queries zelf kunnen schrijven. Dit is echter niet nodig, want er bestaat een heel handige tool voor: CamlDesigner2013. Deze vind je hier.

Omdat ik niet zo goed ben in CAML en XML, ga ik deze tool gebruiken om de juiste query te genereren. Als je de tool wilt gebruiken is het van belang dat je hem installeert op een machine die toegang heeft tot je SharePoint site. De CamlDesigner2013 gaat namelijk een connectie maken met de site, om de site (en dus ook onze list) uit te kunnen lezen.

Omdat deze tutorial niet over CamlDesigner gaat, ga ik niet uitgebreid beschrijven hoe het werkt. Ik vertel slechts kort welke stappen je moet nemen in de tool om het voor nu gewenste resultaat te bereiken.

  1. Verbind CamlDesigner als eerste met de SharePoint site waarin de betreffende list staat.
    Rechts bovenin staat een knop ‘Connection’.
  2. Selecteer links in het menu de juiste list (in mijn geval ‘My Items’).
  3. Nu gaan we de code genereren:
    1. Klik, in het middelste venster bovenin, op ‘Where’.
      Sleep het field ‘ID’ naar de rechterkant en typ ‘id’ in de input.
      Je ziet nu onderin de code verschijnen die je hebt gegenereerd.
    2. Klik, weer in het middelste venster bovenin, op ‘ViewFields’.
      Sleep nu het field ‘Attachments’ naar de rechterkant.
      (zie de code weer verschijnen onderin)
    3. Klik, weer in het middelste venster bovenin, op ‘Query Options’.
      Vink ‘Include Attachments URL’s’ aan.

De XML code die we nodig hebben is nu gegenereerd. We kunnen het nu gaan toepassen in het volgende stukje javascript.

Query Part II

In de Javascript code hieronder komt de code die we met de CamlDesigner hebben gemaakt weer terug. De output van de CamlDesigner is hier als waarde toegevoegd aan de variabelen (query, viewFields en options) die we in het volgende stukje code hebben aangeroepen.

Vergeleken met wat de CamlDesigner heeft uitgespuugd, maken we nog een paar kleine wijzigingen:

  1. Rondom de <Where> tag zetten we nog een <Query> tag. Dat heeft de CamlDesigner namelijk nog niet voor ons gedaan.
  2. In de <Value> tag (binnen de <Where> tag), heeft de CamlDesigner een foutje gemaakt. Die heeft er namelijk Type='Counter' van gemaakt, maar wij willen graag Type='Text' zien.
  3. In dezelfde <Value> tag willen we niet ‘id’ als onderdeel van de XML, maar we willen dat daar via Javascript de id wordt aangeroepen. Verander daarom ‘id’ naar ‘" + id + "’ zoals in onderstaande code.

Je uiteindelijke code moet dus vergelijkbaar zijn met onderstaande code.

// Plaats onderstaande code op de plaats waar de comment in het stuk code eerder in deze tutorial dat aangeeft

this.GetById = function (id) {
var query = "<Query>
<Where>
<Eq>
<FieldRef Name='ID'/>
<Value Type='Text'>" + id + "</Value>
</Eq>
</Where>
</Query>";

var viewFields = "<ViewFields>
<FieldRef Name='Attachments' />
</ViewFields>";

var options = "<QueryOptions>
<IncludeAttachmentUrls>TRUE</IncludeAttachmentUrls>
</QueryOptions>";

var data = this.QueryListOptions(query, viewFields, options);

var count = $(data.responseXML).SPFilterNode("rs:data").attr("ItemCount");

if (count > 0) {
return data;
}

return null;
}

Voor de leesbaarheid van deze tutorial heb ik wat extra linebreaks en spacing aan de code toegevoegd. Normaal gesproken staat de gehele XML code op één regel.

Back to the point: Wat doet deze code nou precies?
Als eerste wordt een anonieme function gedefinieerd, die verwijst naar de variabele ‘MyItemsRepository’ (zie het stukje javascript eerder in deze tutorial) via het this keyword. this.GetById roept dus een item uit de list ‘My Items’ aan, aan de hand van de ID’s van de items. Vervolgens zorgen de variabelen ‘query’, ‘viewFields’ en ‘options’ dat de CAML query wordt samengesteld, die de juiste gegevens uit onze SharePoint list haalt.
Hierna maken we een variabele ‘ data’ aan, die de bovenstaande 3 variabelen samenvoegt en als laatste wordt van het geselecteerde item ieder (kunnen er meerdere zijn) attachment opgehaald. Het if statement op het eind kijkt of er überhaupt attachments zijn. Als dat zo is worden ze opgehaald en als er geen attachments zijn is de output null.

Data weergeven

Nu dat we de data hebben opgehaald, gaan we door middel van Javascript bepalen hoe we die data willen weergeven. We gaan de attachments in HTML list items weergeven, we gaan er klikbare links van maken en we gaan de URL’s inkorten.

De code die dat doet ziet er als volgt uit:

var MyItemsController = function () {

var MyItem;

this.showMyItemDetails = function (I_ID) {
if (myItem != "0") {

var xData = MyItemsRepository.GetById(I_ID);

if (xData != null) {
$(xData.responseXML).SPFilterNode("z:row").each(function () {

// Attachments weergeven
if ($(this).attr("ows_Attachments")) {
liHtml = [];

var attachments = $(this).attr("ows_Attachments").split(';#');

if (attachments !== undefined && attachments != null) {
for (var i = 0; i < attachments.length; i++) {
if (attachments[i] !== undefined && attachments[i] != null) {
if (attachments[i].length > 1) {
var fileName = attachments[i].split('/');

liHtml.push('<li><a href="' + attachments[i] + '">' + fileName
[fileName.length - 1] + '<a/></li>');

}
}
};
}

$('#listAttachments').html(liHtml.join(""));
}
});
}
}
}
}

Deze code begint met het kijken of er list items zijn, en als dat zo is worden die list items opgeroepen. Vervolgens begint onder de comment ‘Attachments weergeven’ de code die de Attachments aanroept en weergeeft. Als eerste wordt het field ‘ows_Attachments’ (zo heet het attachments field in de SharePoint list) opgezocht, waarvan de inhoud vervolgens wordt omgezet in een array.

Daarna wordt de variabele ‘attachments’ aangemaakt, waarin de opgehaalde attachments worden gesplitst. Dat is nodig omdat de attachments standaard gezamenlijk als één lange string worden weergegeven. Ieder attachment begint met ;#, dus daar gaan we op splitsen. Omdat de ;# voor ieder attachment staat, inclusief voor het eerste attachment, denkt de code dat ook voor het eerste attachment nog een item is. Die moeten we eruit filteren om te voorkomen dat het resulteert in een leeg eerste (HTML) list item in de uiteindelijke output.

De volgende stap is dat we met de for loop door de attachments heen gaan. In attachments[i] zit nu de URL van het attachment. De code vervolgt zich met twee if statements. De eerste kijkt of er überhaupt attachments aanwezig zijn, de tweede kijkt of de lengte van de attachment URL (attachments[i]) groter is dan 1. Met deze laatste if filteren we het eerste lege array item dat door de split in de array terecht is gekomen.

Vervolgens gebruiken we var fileName = attachments[i].split('/'); welke zorgt dat de totale URL van het attachment wordt gesplit op de /. De fileName variabele bevat nu een array met in elk item van de array een stukje van de URL. Met behulp van fileName[fileName.length - 1] vragen we het laatste stukje van de URL van het attachment op, de echte bestandsnaam.

Hoe werkt dit dan?
Nou, fileName.length geeft het totaal aantal items in de array terug. Als de array 1 item zou bevatten dan zou fileName.length ‘1’ zijn. Omdat de index van een array bij ‘0’ begint, verwijst fileName[fileName.length] naar een niet bestaand item en dus ontstaat er een foutmelding.

Ter illustratie:

laten we nu de ‘- 1’ weg, dan zou de code, in het geval van 4 items in de array, gaan zoeken naar item nummer 4 terwijl hij nummer 3 moet hebben.

Enfin, Door bovenstaande kan je dus in plaats van een hele lange URL, alleen de bestandsnaam weergeven, wat het lijstje attachments een stuk leesbaarder maakt.

In de regel erna worden de attachments in een <li> en een <a> gestopt, zodat de output een keurige HTML list wordt met een klikbare link in ieder list item. De laatste regel vervolgens, koppelt de output aan de <ul> met het id (#) listAttachments, zodat onze output in dat element wordt weergegeven.

Afronden

We zijn er bijna. Het laatste wat we nu nog gaan doen is een paar regeltjes CSS toevoegen, zodat onze HTML output toonbaar is. Natuurlijk kan je dit zelf naar wens aanpassen.

#container {
float:left;
height:200px;
width:300px;
}

#container h3 {
float:left;
width:100%;
}

#listAttachments {
float:left;
width:100%;
margin:10px 0;
padding:0;
}

#listAttachments li {
float:left;
width:100%;
margin:5px 0;
}

Bovenstaande CSS zorgt voor een box van 200x300 pixels met bovenin de header ‘Attachments’ en daaronder de lijst met attachments, keurig onder elkaar weergegeven met wat ruimte tussen ieder element.

Nu is het tijd om je solution te deployen. Als je solution is geïnstalleerd en de feature(s) is/zijn geactiveerd, zie je nu je attachments op de pagina waarop je de HTML hebt toegevoegd.

08 november 2012

Managed Metadata Navigatie in SharePoint 2013

In deze blogpost leg ik uit hoe je de nieuwe Managed Metadata navigatie functionaliteit van SharePoint 2013 kan configureren op een hiërarchie met meerdere site collecties. Ik ga er in deze handleiding van uit dat je al meerdere site collecties hebt, waarin je de Managed Metadata navigatie wilt toepassen.

Content Type hub

In het geval van meerdere site collecties is het aan te raden een ‘Content Type hub’ aan te maken. Dit is een site collectie die functioneert als host voor al je metadata, waaronder content types, fields/columns, terms, tags, etc. De overige site collecties kunnen gebruik maken van de metadata die opgeslagen is in de content type hub.
Een Content Type hub maak je als volgt aan:
  1. Open Central Administration en navigeer naar Applicaton management -> Create site collections.
  2. Maak een site collectie aan die je als Content Type hub gaat gebruiken. Geef de site collectie een herkenbare naam zoals ‘cth’ (afkorting voor Content Type hub). Je kunt gewoon een willekeurig template gebruiken, want je doet verder niets met deze site (je gebruikt hem alleen als host).
  3. Navigeer binnen Central Administration naar Application Management -> Manage Service Applications.
  4. Klik in de ribbon op New -> Managed Metadata Service.
  5. Vul het formulier in. Geef het wederom een herkenbare naam, zodat je je nieuwe Managed Metadata Service Application straks makkelijk terug vind. Vul verder de juiste Database Server in en stel een Application pool in. In het veld Content Type hub vul je de URL van de site collectie uit stap 2 in. Klik ten slotte op Save.
  6. De nieuwe Managed Metadata Service staat nu in het overzicht. Hierbij zijn twee regels zichtbaar, waarbij het onderscheid zichtbaar is onder de kolom Type’. Hier kan je zien dat er een Managed Metadata Service is, met daaronder een Managed Metadata Service Connection.
  7. Controleer of je Managed Metadata Service de status Started (rechts in beeld) heeft en publiceer hem nog even voor de zekerheid. Je kunt het publiceren door de bovenste regel (onder Type staat Managed Metadata Service) aan te klikken, en vervolgens in de ribbon op Publish te klikken.
  8. Klik nu op de onderste regel (onder Type staat Managed Metadata Service Connection).
    Je Term Store Management Tool wordt nu geopend, hier gaan we straks mee verder.
  9. Open, in een nieuw venster, de site collection die als Content Type hub dient.
  10. Ga naar Site Settings en klik op Site Collection Features (te vinden onder het kopje Site Collection Administration).
  11. Activeer de feature Content Type Syndication Hub.
De Content Type hub is nu aangemaakt en klaar voor gebruik. Voor het gemak van deze handleiding heb ik je in stap 7 alvast de Term Store Management Tool laten openen. Hierin gaan we nu onze navigatie in aanmaken.

Navigatie aanmaken

De navigatie bestaat uit Terms welke verzameld zijn in een Term Set. Term Sets worden weer verzameld in Groups. Laten we beginnen:
  1. Als je in de Term Store Management Tool in het linker venster kijkt, zie je de onderdelen die al in de Term Store staan. Waarschijnlijk zie je nog niets, behalve een regel met de naam van de Managed metadata Service en een mapje dat System heet. Hover met je muis over de naam van je Managed Metadata Service en je ziet een pijltje verschijnen aan de rechterkant. Klik op het pijltje en selecteer New Group.
  2. Geef de nieuwe Group een herkenbare naam zoals ‘Site Navigation’.
  3. Hover nu met de muis over de nieuwe Group en klik wederom op het pijltje. Selecteer nu New Term Set.
  4. Een van de problemen die ik tegen ben gekomen is dat maar 1 site collectie gebruik kan maken van een term set. Om deze reden zullen we dus voor iedere site collectie een nieuwe Term Set aan moeten maken. Gelukkig kunnen in die Term Sets, de Terms hergebruiken. We gaan nu dus eerst de verschillende Term Sets aanmaken, maar we gaan slechts in 1 Term Set de Terms aanmaken. Als dat klaar is, dan hergebruiken we die Terms in de overige Term Sets.
  5. Geef de nieuwe Term Set die je in stap 3 hebt aangemaakt een herkenbare naam. Houdt hierbij rekening met het feit dat iedere site collectie een eigen Term Set krijgt. Het is dus handig om je Term Set te vernoemen naar de site collectie waar je hem straks op gaat toepassen.
  6. Klik op de Term Set en klik in het grote rechter venster bovenin op het tabje INTENDED USE. Zet een vinkje bij Use this Term Set for Site Navigation.
  7. Herhaal stap 3, 4 en 5 voor iedere site collectie waarop je de navigatie wilt toepassen.
  8. Hover nu over 1 van je Term Sets en klik weer op het pijltje. Selecteer New Term en geef de nieuwe Term een naam.
  9. Je hebt nu de eerste echte link voor het menu aangemaakt. De naam van de Term is wat je straks ziet in het menu, houdt hier dus rekening mee als je de Term een naam geeft.
  10. Herhaal Stap 7 tot je alle gewenste links voor het menu hebt aangemaakt.
  11. Klik op een Term en klik op het tabje NAVIGATION in het grote scherm rechts. Klik de radiobutton bij Simple Link or Header aan en vul de URL in waar deze link straks in het menu naar moet gaan verwijzen. Deze URL komt uit een andere site collectie, dus de Browse-knop heeft hier geen zin. Zoek zelf de URL op en vul deze handmatig in.
  12. Klik op het tabblad GENERAL en controleer in het veld Member Of of de juiste Source Term is geselecteerd. Zo niet, verbeter deze dan.
  13. Herhaal stap 9 en 10 voor iedere term die in je menu moet komen.
  14. Hover over een van overige Term Sets die je hebt aangemaakt voor je andere site collections en klik op het pijltje. Selecteer nu Reuse Terms.
    Voeg alle Terms toe die je in het menu van de site collectie, waarop deze Term Set van toepassing is/wordt, wilt zien.
  15. Klik op de Term Set en selecteer het tabblad CUSTOM SORT. Klik de radiobutton bij Use custom sort order aan en zet de Terms in de gewenste volgorde.
  16. Herhaal stap 12 en 13 voor alle Term Sets.
De menu’s voor alle site collecties zijn nu klaar.

Navigatie toepassen

Nu dat de menu’s klaar zijn, moeten ze worden toegepast op de site collecties.
  1. Om de topnavigatie te kunnen bewerken moet een bepaalde feature aan staan. Ga naar de site collectie waarop je de navigatie wilt activeren.
  2. Ga naar Site Settings en vervolgens naar Site Collection Features (te vinden onder het kopje Site Collection Administration). Activeer de feature SharePoint Server Publishing Infrastructure.
  3. Ga nu (nog steeds binnen Site Settings) naar Navigation (te vinden onder het kopje Look and Feel).
  4. Klik, onder het kopje Global Navigation, de radiobutton bij Managed Navigation: The navigation items will be represented using a Managed Metadata term set aan.
  5. Scroll nu omlaag naar het kopje Managed Navigation: Term Set, zoek in het venstertje de juiste Term Set op en klik deze aan.
  6. Klik helemaal onderin het scherm op OK.
De navigatie zou nu zichtbaar moeten zijn op de pagina’s van je site collectie. Mocht dit niet het geval zijn, dan kan je nog even de timer job Application Server Administration Timer Job handmatig starten. Deze is te vinden in Central Administration onder Monitoring -> Check job status.