donderdag 24 november 2011

Aanpassen van lijst- en bibliotheekformulieren zonder SharePoint Designer of InfoPath

Kent u de frustratie? Geen InfoPath voorhanden, geen SharePoint Designer voorhanden, en toch een vriendelijk doch dringend verzoek om het invullen van een formulier (b.v. voor een lijst- of bibliotheek-item) aan te passen. Valide redenen voor dit soort verzoeken zat; vooringevulde velden, speciale checks op de veldwaarden (b.v. een ELF check voor bankrekeningnummers), waarschuwingen, extra hulp voor gebruikers, et cetera.
En met InfoPath kun je zulke functionaliteit redelijk simpel implementeren in formulieren, en middels SharePoint designer kun je de standaard lijst- en bibliotheek invulformulieren relatief simpel aanpassen. Maar zonder deze tools... tsja... het Edit page - menu (onder het Site actions - menu ontbreekt nueenmaal bij deze standaard lijst- en bibliotheek invulformulieren. En wat doe je dan?

Gelukkig bestaat er een manier om toch, zonder InfoPath en Designer, en gewoon "met de browser" de standaard lijst- en bibliotheek invulformulieren kunt wijzigen.

De truuk bestaat eruit om de URL van het betreffende invulformulier te voorzien van de parameter ToolPaneView=2.

ToolPaneView en andere parameters
Voor de volledigheid: de parameter ToolPaneView kent de volgende waarden:
- ToolPaneView=2: Toevoegen van Webparts (browse)
- ToolPaneView=3: Add Web Parts (zoeken)

Naast de ToolPaneView zijn de volgende parameters beschikbaar:
- mode=view: View Mode
- mode=edit: Edit Mode

- PageView=Shared: Shared Mode, voor iedere gebruiker zichtbaar
- PageView=Personal: Personal Mode, voor de huidge gebruiker zichtbaar

Terug naar onze casus: ToolPaneView=2...
Wat we willen bereiken is dat we meer controle hebben over de invoer van gegevens in bijvoorbeeld een lijst. Hiertoe zijn twee standaard webpagina's beschikbaar:
NewForm.aspx: voor het aanmaken van een nieuw item in een lijst
EditForm.aspx: voor het wijzigen van een item in een lijst

Voorbeeld:
Stel, we willen het standaard formulier voor het aanmaken van een nieuw item in de lijst "Taken" wijzigen. We gebruiken dan de URL:

http://portal.demo.intra/DigitaalLoket/Lists/Taken/NewForm.aspx?ToolPaneView=2

Aanpassingen aan het standaard formulier
Zoals ik in mijn artikel JavaScript in Inhoudseditor webonderdelen: eenvoudige uitbreidingen op webpagina's heb beschreven kan de inhoud van een webpagina worden gewijzigd door gebruik te maken van JavaScript dat in het Inhoudseditor webonderdeel (Content Editor webpart) kan worden ondergebracht. Hiermee kan extra functionaliteit (lees: controles, wijzigingen in veldwaarden) worden geimplementeerd.

Gewenste aanpassingen
Wat in een formulier aangepast zou kunnen worden zijn, bijvoorbeeld, de volgende zaken:
- Controles op veldwaarden
- Invullen van standaard waarden, immers: deze kunnen via de standaard mogelijkheden van SharePoint slechts 1 maar ingesteld worden en dat is vaak onvoldoende, zelfs met het gebruik van berekende velden (Calculated fields).
- Geven van extra toelichting bij de invoer van gegevens (als een soort online hulp).

Middels JavaScript kunnen bovenstaande aanpassingen uitgevoerd worden. Dit kan gebeuren door triggers te definieren op velden en waarden van velden aan te passen door deze direct in het DOM object model aan te passen. Wat hierbij natuurlijk van belang is is het terugvinden van de velden in het DOM object model. Dat kan door de HTML broncode te analyseren, maar ook door het bekijken van het DOM object model achter de betreffende webpagina middels een tool: de IE Developer Toolbar.

IE Developer Toolbar
Wat in dergelijk generd enorm helpt is de IE Developer Toolbar, een add-on op Internet Explorer waarin je de DOM objectstructuur van een webpagina kunt bekijken en doorzoeken. Het verdeelt het browser window in twee delen: een bovenliggend deel met de opgemaakte HTML pagina, en een onderliggend deel waarin de eigenschappen van de DOM-elementen worden weergegeven. De IE Developer Toolbar is te downloaden op de volgende lokatie: http://www.microsoft.com/download/en/details.aspx?id=18359.

Wat hierin natuurlijk van belang is dat dit soort aanpassingen niet lastig onderhoudbaar worden en dat het niet ten koste gaat van de stabiliteit van de webformulieren. Wat dat laatste betreft: een webpagina kan door een slecht functionerend JavaScript de browser "ophangen". Neem als voorbeelden hiervan een JavaScript dat bestaande functionaliteit vervangt of zo lang duurt dat het laden van een pagina een eeuwigheid laat duren. En dat kan niet de bedoeling zijn. Wees er dus voorzichtig mee. Mocht een pagina toch slecht gaan functioneren, kan het web onderdeel dat het JavaScript bevat altijd middels een speciale view (zie hiervoor mijn artikelen: Handige URL's en Help, ik heb wat fout gedaan! Eerste hulp bij SharePoint problemen... (onderdeel "Herstel van web pagina's die niet correct worden weergegeven") uit de pagina worden verwijderd.

Een praktisch voorbeeld
Stel: we willen bij het aanmaken van een lijst-item de volgende zaken realiseren:
- Bepaalde velden een standaard waarde meegeven
- Op bepaalde velden controles uitvoeren

Allereerst moeten we ervoor zorgen dat deze velden in JavaScript te benaderen zijn. Dit kan door een JavaScript toe te voegen in een Content Editor webpart onderaan de pagina (onderaan omdat dan de bovenliggende velden beschikbaar en dus ook benaderbaar zijn in het DOM object model). Dat script zoekt de velden op in het DOM model van de betreffende webpagina. De velden zijn in de HTML code van de pagina terug te vinden door te zoeken op de HTML tag en de title van het veld (zoals die bekend is als column naam in de SharePoint lijst), bijvoorbeeld een input veld met als title "Achternaam". Voorbeeld: input ... title="Achternaam".
Het JavaScript zoekt deze velden op en houdt verwijzingen ernaar bij zodat ze te gebruiken zijn als objecten en derhalve bewerkt kunnen worden.

Hiervoor kan de volgende JavaScript functie worden gebruikt:

function GetFieldObject( iTagName, iTitle ) {
var vObject;
var vObjects = document.getElementsByTagName( iTagName );
var i = 0;

for ( i = 0; i < vObjects.length; ++i ) {

if ( vObjects[i].getAttribute("title") == iTitle ) {
vObject = vObjects[i];
}

}

return( vObject );
}


Deze functie kan als volgt worden gebruikt:

var vFieldTitle = GetFieldObject( "input", "Title" );


Als we van ieder veld een verwijzing (variabele) beschikbaar hebben kunnen we daar verschillende dingen mee:
- Veldwaarden uitlezen en instellen (standaard waarden).
- Functies aan toewijzen, die bijvoorbeeld worden uitgevoerd als een veld wordt gewijzigd.
- Velden verbergen en zichtbaar maken
- Veldkleur veranderen, als een veld bijvoorbeeld een verkeerde waarde heeft

Enkele voorbeelden:

Uitvoeren van de functie EvaluateForm nadat een veld is ingevuld:

vFieldTitle.onblur = EvaluateForm;

Houd er rekening mee dat andere veldtypen ook andere event triggers gebruiken. Wanneer een combo box van waarde verandert, moet je onchange gebruiken in plaats van onblur.

Instellen van een veldwaarde:

vFieldTitle.value = vGeselecteerdFormulier;


Veranderen van kleur van een veld:

vFieldTitle.style.color = "#00ff00";


Sommige velden zijn wat lastiger...
Datum/tijd velden bestaan in Sharepoint uit meerdere delen: een datum-, uren- en minuten veld. Bovendien zijn de waarden van deze velden ook nog eens beperkt:
Uren velden (combobox) kunnen alleen waarden bevatten als "10 AM" en "12 PM", terwijl minuten velden (combobox) alleen waarden bevatten als "00", "05", .. "55". En deze waarden zijn ook nog eens afhankelijk van de versie van SharePoint en instellingen (reden te meer om voorzichtig te zijn met dit soort oplossingen). Om deze velden te kunnen manipuleren en dit ook nog eens in leesbare JavaScript code te implementeren, kun je gebruik maken van JavaScript objecten die de betreffende veldverwijzingen bevatten. Heb je zo'n object nueenmaal aangemaakt kun je de data/tijden manipuleren. Wat daarbij ook handig is is een functie waarmee je JavaScript data/tijden kunt converteren naar waarden in je JavaScript object. Al met al een hele klus.

Zichtbaar maken of verbergen van velden
Hiertoe moet een gehele rij in de tabel (TR) worden verborgen of zichtbaar worden gemaakt (style.display = "none" of "").

Dit kan gebeuren door een functie te maken die als volgt wordt aangeroepen:

HideViewFieldRow( "WorkflowStatus_Timestamp_Ingevoerd", true );

De eerste parameter is de naam die voor het betreffende veld in de webpagina staat, bijvoorbeeld "Title".
De tweede parameter geeft de zichtbaarheid aan van het betreffende veld:
- true: zichtbaar
- false: onzichtbaar

Onderstaande functies realiseren dit:

function HideViewFieldRow( iLabel, iVisible ) {
var vFieldRow = GetFieldRow( iLabel );

if ( iVisible )
vFieldRow.style.display = "";
else
vFieldRow.style.display = "none";

}

function GetFieldRow( iLabel ) {

// Scan op

var vObjects = document.getElementsByTagName( "TD" );
var i = 0;

for ( i = 0; i < vObjects.length; ++i ) {

if ( vObjects[i].className == "ms-formlabel" &&
vObjects[i].innerHTML.indexOf( iLabel ) != -1 ) {
// Return parent node ()
return( vObjects[i].parentNode );
}

}

// iLabel Niet gevonden
return( null );

}


Instellen van standaard waarden / instellingen a.d.h.v. URL parameters
De default waarde van een veld of andere instellingen kunnen eenvoudig worden gerealiseerd door parameters aan de URL van de webpagina toe te voegen die in het JavaScript worden opgevangen. Hiermee kunnen velden worden ingevuld, aan- en uit worden gezet, et cetera.

Voorbeeld:
Een URL met parameters:

http://portal.demo.intra/DL2/Lists/TestLijst1/NewForm.aspx?iFormulierNaam=Categorie%203

Hierin wordt voor de parameter iFormulierNaam de waarde "Categorie 3" meegegeven.

En middels het onderstaande JavaScript worden de parameters ingelezen en gebruikt; de parameter iFormulierNaam wordt gebruikt om de waarde van de combobox vFieldCategorie in te stellen.

function GetParm (testing) {

testing = testing.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+testing+"=([^&#]*)";
var regex = new RegExp( regexS );

var vURL = window.location.href;
vURL = vURL.replace("%20", " ");

var results = regex.exec( vURL );
if( results == null )
return "";
else
return results[1];
}

function GetAndSetDefaults () {

var vGeselecteerdFormulier = GetParm( "iFormulierNaam" );
vFieldCategorie.value = vGeselecteerdFormulier;

}


Let op: in het bovenstaande script moet de URL encoding (zie ook: Handig: URL encoder) ook worden uitgefilterd. Dit is in het voorbeeld deels gedaan; de %20 wordt vervangen door een spatie.

Bewerken van meerdere velden tegelijk
Door gebruik te maken van arrays (van objecten) kunnen meerdere velden tegelijk worden bewerkt:

var vFormulierDeel1 = [ vFieldCategorie, vFieldTitle, vFieldAchternaam ];


Deze array kan als parameter worden doorgespeeld aan functies die deze velden tegelijk bijvoorbeeld verbergen of zichtbaar maken. Dit is bruikbaar wanneer verschillende personen verschillende delen van een formulier moeten invullen en de rest van het formulier niet mogen zien en/of bewerken.

Een stapje verder: een primitieve workflow met JavaScript
SharePoint ondersteunt standaard maar een beperkt aantal workflow typen. Vaak bieden deze mogelijkheden net wat te veel beperkingen. Goed alternatief is natuurlijk gebruik te maken van SharePoint Designer waarin je zelf workflows kunt definieren, of InfoPath waarin je workflow kunt simuleren door een formulier een bepaalde status mee te geven. Echter: deze tools zijn niet altijd voorhanden.
In die gevallen kun je overwegen om workflow te simuleren door de status van een formulier als veld (lijstkolom) op te nemen en op basis hiervan middels JavaScript delen van het formulier te tonen of te verbergen voor personen die in deze workflow betrokken worden. Ook is het mogelijk om aan de verschillende stappen in de workflow een timestamp toe te voegen (voor iedere stap een aparte kolom/veld) die automatisch gevuld wordt wanneer het formulier in een bepaalde status wordt ingevuld.

Een stap verder: gebruik JQuery
JQuery is een JavaScript bibliotheek waarmee relatief simpel het DOM object model van een HTML pagina kan worden bewerkt. De bovenstaande voorbeelden kunnen hiermee gemakkelijker worden gemplementeerd. Het is het zeker waard je eens te verdiepen in de mogelijkheden ervan. In een komende blogpost zal ik hier wat voorbeelden van geven. De JQuery JavaScript bibliotheek kan aan SharePoint Masterpages worden toegevoegd, of opgenomen worden in een SharePoint bibliotheek (als dat is toegestaan), waarna de JQuery functies in Web pagina's (Content Editor Web onderdelen) kunnen worden gebruikt. Voor een eerste kennismaking met JQuery, zie http://jquery.com/.

Kanttekeningen
Ofschoon het aanpassen van de "standaard" gebruikersinterface technisch mogelijk is, is het niet altijd wenselijk. In het algemeen geldt voor SharePoint (maar ook alle andere standaard platformen die door niet ICT specialisten kunnen worden aangepast en uitgebreid) dat zoveel mogelijk gestreefd moet worden naar een "standaard", dat wil zeggen: uitzonderingen zoveel mogelijk vermijden. Reden hiervan is dat uitzonderingen moeite (en dus: geld en doorlooptijd) kosten. En die moeite komt meestal ongelegen, bijvoorbeeld tijdens migratie naar een nieuwe versie van het platform of tijdens een upgrade waarin over het hele platform wijzigingen worden doorgevoerd. Ook kunnen versieverschillen (talen, regionale instellingen) roet in het eten gooien. Tijdens dergelijke acties moeten voor iedere uitzondering op de standaard voorzieningen getroffen worden om de uitzondering nog te laten functioneren na de wijziging. En als iedereen ongecontroleerd uitzonderingen kan doorvoeren kan dit tot veel onvoorzien werk leiden.

Een voorbeeld:
In een platform zijn door eindgebruikers een aantal functies aangepast, zonder overleg met de ICT afdeling. Tijdens de migratie lijkt alles goed te gaan, de ICT afdeling voert een automatische upgrade uit en de nieuwe versie van het platform gaat live. Tijdens het gebruik van de nieuwe versie van het platform blijkt al gauw dat sommige functies niet naar behoren functioneren. Hiervan worden meldingen gedaan ("de nieuwe versie doet het niet") en na analyse komen de aanpassingen aan het licht. Vervolgens moet bekeken worden hoe de aanpassingen weer functioneel gemaakt kunnen worden en er ontstaat een discussie of deze wijzigingen nog wel wenselijk zijn. De gebruikers zien de aanpassingen als "vervorven rechten" en de ICT afdeling zal onder druk gezet worden deze wijzigingen als maatwerk te implementeren. En intussen is de functionaliteit voor de eindgebruiker niet te gebruiken.
Een onwenselijke situatie dus.

Om dit soort situaties te voorkomen zullen, voordat aanpassingen uitgevoerd worden, de volgende overwegingen gemaakt moeten worden:
- Is de aanpassing echt noodzakelijk? Kan de functionaliteit echt niet op een geaccepteerde "SharePoint standaard" wijze worden geimplementeerd?
- Als aanpassing noodzakelijk is, is er meer vraag naar deze functionaliteit zodat voor iedere vraag een standaard oplossing (aanpassing) kan worden geimplementeerd? Kijk hiervoor ook verder dan SharePoint sites, zie hiervoor ook mijn artikel Gebruik je hele gereedschapskist (dus niet alleen SharePoint websites)!
- Hoe moet met deze wijziging worden omgegaan wanneer platform brede wijzigingen (b.v. upgrade, migratie) worden doorgevoerd? Zie hiervoor ook mijn artikel over maatwerk Out-of-box of maatwerk, that's the question (HansR on Architecture).

In het algemeen geldt: eerst nadenken, dan doen. Da's een stuk goedkoper dan andersom.

(een collega was het ten dele eens met de bovenstaande stelling. Zijn punt: "fouten maken kunnen inderdaad kostbaar zijn maar kunnen ook heel veel extra (nuttige) kennis opleveren.". Daarmee kan ik het helemaal eens zijn: van fouten maken leer je. Een kleine kanttekening hierbij: bij het ondernemen heb je ruimte nodig om te experimenteren, maar om levensvatbaar te blijven moet deze ruimte wel gemanaged (lees: beperkt) worden.)

En nu in SharePoint 2010, met een betere opzet
Intussen heb ik een vervolg blogpost op deze post gepubliceerd met daarin bescheven hoe de bovenstaande truuks in SharePoint 2010 kunnen worden toegepast. Ik heb daarin een wat betere opzet gebruikt waarin de SharePoint velden in een JavaScript object model worden gezet. Dit als een soort tussenlaag tussen het DOM objectmodel en de intelligentie in de web pagina. Dit is te lezen in Aanpassen van lijst- en bibliotheekformulieren in SharePoint 2010, zonder SharePoint Designer of InfoPath.




1 opmerking:

  1. Hoi HansR,

    Had er wel wat gelezen over het toepassen van ToolpaneView maar nooit gedacht dat te kunnen combineren met JS. Ik ben benieuwd naar je resultaat.

    Groeten,

    AB

    BeantwoordenVerwijderen