Client Server 2.0 met jquery en Grails



Vergelijkbare documenten
Methodology. Client Server 2.0 met jquery en Grails. De eerste generatie Client-Server applicaties

Technisch Ontwerp W e b s i t e W O S I

Gebruik van cryptografie voor veilige jquery/rest webapplicaties. Frans van Buul Inter Access

Selenium IDE Webdriver. Introductie

Websitecursus deel 3 JavaScript

Documentatie. InstantModules Q42. Versie 1.1

Een website maken met databasetoegang.

Les 9: formulier controle met javascript.

WEBSITE-DESIGN CHRIS VERMAAS & FJODOR VAN SLOOTEN B

Formulieren maken met Dreamweaver CS 4/CS 5

Een ASP.NET applicatie opzetten. Beginsituatie:

Dynamiek met VO-Script

HTML in Outlook Hoe zorgt u ervoor dat uw goed in beeld komt?

APEX Templates. OGH APEX dag 30 maart. Art Melssen. 31 maart 2010

Is APEX a worthy substitute for Oracle Forms?

Formulieren en waarden posten naar een view

INFITT01 - Internettechnologie WEEK 8

Web building gevorderden: CSS & JavaScript. Karel Nijs 2008/11

Foutcontrole met Javascript

Enterprise. RESTful Webservices. serieus alternatief voor SOAP?

Sparse columns in SQL server 2008

DrICTVoip.dll v 2.1 Informatie en handleiding

Technisch ontwerp. Projectteam 6. Project "Web Essentials" 02 april Versie 2.1.0

Voor de database wordt een Access 2000 bestand gebruikt, met voorlopig 1 tabel:

JSF webapplicatie performance

ASRemote WebService. Via deze webservice kunt u:

TaskCentre Web Service Connector: Creëren van requests in Synergy Enterprise

Naam project Lost And Found Animals Lokaal gehost Percentage van het totaal geleverde werk 1 Cindy Jansen 50% 2 Eline Steyvers 50%

NHibernate als ORM oplossing

Object Oriented Programming

Versie 0.4. Documentatie Onsweb Club plugin voor KNKV verenigingen. Laatste wijziging: 19 juli 2012 Auteurs: Marien Dongstra, Sebastian Huisman

Maximo Tips and Tricks

Service Data Objects. Wat is SDO? Dynamic data API

Copyright IBS Nieuwbouw. Vereenvoudigd en versnelt Java ontwikkeling. Huub Cleutjens

Frontend ontwikkeling

DNM-address. Quick Installation Guide

Versie 0.2. Documentatie Onsweb Club plugin voor NHV verenigingen. Laatste wijziging: 10 mei 2013 Auteurs: Marien Dongstra, Sebastian Huisman

Externe pagina s integreren in InSite en OutSite

Organiseer uw verschillende SOAP services in één scenario

HTML Graphics. Hans Roeyen V 3.0

Kleine cursus PHP5. Auteur: Raymond Moesker

AJAX (XMLHttpRequest)

Oracle Application Server Portal Oracle Gebruikersgroep Holland Oktober 2003

Exercise assistant on-line

Stappenplannen MailPlus SOAP API

Met een LightSwitch applicatie een OData service uit de Windows Azure Marketplace consumeren

Knowledgeable Referenceable Personable Accountable Scalable

icafe Project Joeri Verdeyen Stefaan De Spiegeleer Ben Naim Tanfous

APEX vs OutSystems, een vergelijking door een gebruiker

Gegevens uit een database tonen

Rapporten. Labels en Rapporten in Atlantis 1. Atlantis heeft twee manieren om output te genereren: 1. labels 2. rapporten (reports)

Zonnepanelen Hoe krijg je de data op je website?

De plug-in is heel eenvoudig te installeren met een setup-programma. Waarna je een aantal menu opties in het tools menu er bij krijgt.

Publicatie formulieren en surveys

Lab Webdesign: Javascript 7 april 2008

React en React Native voor websites en apps

Info-books. Toegepaste Informatica. Deel 35: XML - XSL HO35. Jos Gils Erik Goossens

Hand-out Introduction to Programming, werkcollege 7 Alex Reuneker 2013

Eigen Widgets in CRM. Introductie. Limitering. Widgets beschikbaar stellen. Tips & Tricks Eigen Widgets in CRM

Je hoeft je maar met twee bestanden bezig te houden:

Inhoud. Introductie tot de cursus

Kies File>New>Blank Page>PHP. Je kunt eventueel nog een stylesheet koppelen. Definieer nu eerst een site! Dat betekent: Site>New Site

Chris de Kok TDI 3. Vak: Software Architectuur Datum: Docent: Fons van Kesteren

Websitecursus deel 1 HTML

Dynamische Websites. Week 2

Workflows voor SharePoint met forms en data K2 VOOR SHAREPOINT

Powerpoint presentatie College 5 Gilbert van Lierop & Farshad Salamat

Handleiding: Whitelabel Customersite

Kennis na het volgen van de training. Na het volgen van deze training bent u in staat:

Handleiding RS Form! 1.0.4

HDN DARTS WEB AUTHENTICATIE

Gebruikershandleiding voor: Beperkte Password protectie met JavaScript

Formulier maken en opvangen met php

Session Beans.

JavaScript. 0 - Wat is JavaScript? JavaScript toevoegen

Samengaan van Geo-informatie en Service Oriëntatie

De categorie Forms in het paneel Insert

Bottleball Onderzoeksverslag MovingMonsters. Uitgevoerd door Arno Classens

Building rich user interfaces in Java

INHOUDSOPGAVE Het Boekenwinkeltje Registreer.aspx Opgaven... 97

NBTC html wijzigingen juni

XML. Alle tekortkomingen op een rijtje! (en een paar pluspunten...) Marc de Graauw

PHP-OPDRACHT SITE BOUWEN

De architect: in spagaat tussen mensen en technische details. Illustratie met een simpel voorbeeld

Javascript oefenblad 1

MADASTER PLATFORM. IFC export in BIM software. Archicad 21 & Revit 2019

Release datum: 11 juni 2012

Les 15 : updaten van gegevens in de database (deel2).

DECADE FINANCIALS. met APEX klaar voor de toekomst. Zeist

i ll take off to the cloud

HANDLEIDING DMS Plugin Installatie, configuratie & werking

APEX en JasperReports

J2EE/.NET en de rol Applicatie Architectuur

Software Design Document

Interactie: Document Object Model en JavaScript. Hoorcollege Webdesign 7 23 mei 2014 Christof van Nimwegen

Tutorial 1, Delphi: Geldspraak

Angular Best Practices Door Alex en Chris van Beek

Databanken en webtoepassingen in Java

Transcriptie:

Client Server 2.0 met jquery en Grails Web applicaties lijken steeds meer op Client-Server applicaties. Kijk naar voorbeelden als gmail of google documents. In deze architectuur is de client volledig verantwoordelijk voor de user interface en de server verantwoordelijk voor data en business logica. Er is nog geen overeenstemming over de naam van deze aanpak. Een aantal gebruikte namen zijn RIA, SOFEA, en SOUI. Voorlopig hou ik het bij Client-Server 2.0 omdat dit redelijk goed duidelijk maakt wat we aan het doen zijn. De eerste generatie Client-Server applicaties was gebaseerd op proprietary ontwikkeltools en technologieen als Oracle Forms en de Oracle database of Visual Basic en MS- SQLserver. Tegenwoordig is het mogelijk en eenvoudig om client server applicaties te realiseren op basis van open standaarden als HTML, Javascript en services. Browsers bieden tegenwoordig een volwassen applicatie container. Met Open standaarden als Javascript, HTML en CSS kun je complete applicaties schrijven, niet slechts webpagina's. HTML is een krachtige en eenvoudige layout engine, skinning is eenvoudig mbv CSS, en Javascript is een krachtige, performante en complete programmeertaal geworden. Feitelijk een complete set tools om applicaties mee te bouwen, niet slecht webpagina's. SOA wordt veel toegepast om herbruikbaarheid van software te vergroten. Door software in service vorm aan te bieden is hergebruik eenvoudiger. Nieuwe software kan sneller gerealiseerd worden, bestaande software kan eenvoudiger aangepast worden. Dit biedt bedrijven de mogelijkheid om IT sneller aan te passen aan de wensen van de business. Daarnaast biedt SOA de mogelijkheden tot applicatie-integratie op basis van open standaarden. Dit artikel illustreert hoe Client-Server 2.0 applicaties eenvoudig en productief gerealiseerd kunnen worden met jquery en Grails. jquery gebruiken we als belangrijkste framework voor de client kant van de applicatie. Grails gebruiken we om snel services te realiseren. jquery jquery is een javascript library. De belangrijkste kenmerken van jquery: eenvoudig manipuleren van DOM object, mbv een syntax die erg op die van CSS lijkt, statement chaining, maw het aan elkaar plakken van functie aanroepen, waardoor je compacte code krijgt, verbergen van browser verschillen. Jquery ondersteunt de belangrijkste browsers. Het volgende voorbeeld komt van de homepage van jquery. Deze ene regel code voegt aan alle paragrafen met de class neat een extra class ohmy toe, en vervolgens worden ze met een trage animatie getoond. $("p.neat").addclass("ohmy").show("slow"); Zoals je ziet kun je met jquery veel bereiken met weinig. Scheiden inhoud, opmaak en gedrag Veel ontwikkelaars zijn echter bezorgt dat je met Javascript geen onderhoudbare applicaties kunt bouwen. Een belangrijke stap om de onderhoudbaarheid te verbeteren is om inhoud, opmaak en gedrag goed te scheiden. Een HTML bestand hoort slechts inhoud te bevatten, een CSS stylesheet slechts opmaak, en een Javascript bestand slechts gedrag. Het volgende voorbeeld toont naast het scheiden van opmaak, inhoud en gedrag ook hoe je een single page applicatie kunt maken, waarbij dynamische gedeelten van de pagina toegevoegd worden met behulp van de jquery load functie. Eerst het statische gedeelte van de HTML pagina. Dit is het gedeelte dat de gebruiker niet verlaat. In de header worden de benodigde stylesheets en javascript bestanden gelinked. Verder bevat de pagina 1 button. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1- strict.dtd"> <html> <head> <link media="all" type="text/css" href="example1.css" rel="stylesheet" /> <script src="jquery-1.3.1.min.js" <script src="example1.js" </head> <body> <button type="button" id="showformbutton">show Form!</button> </body> </html> Het volgende HTML bestand, form.html, zal dynamisch in Andrej Koelewijn, IT-eye, 1/8

de pagina geplaatst worden nadat de gebruiker op de Show Form! button gedrukt heeft. <form name="form1"> <label for="namefield">name</label> <input id="namefield" value="" /> <button type="button" id="savebutton">save</ button> </form> Voor de opmaak hebben we een stylesheet, example1.css, dat ervoor zorgt dat het dynamische formulier een grijze achtergrond krijgt. #formpanel { background-color: #ddd; Tenslotte nog een Javascript document, example1.js, dat het gedrag achter de pagina implementeert. Het eerste gedeelte maakt gebruik van een jquery functie, ready, dat ervoor zorgt dat de code uitgevoerd wordt nadat de pagina is ingeladen. In de ready function wordt de Show Form! button voorzien van een onclick event handler. $(document).ready(function(){ $("#showformbutton").click( function() { showform(); ); ); De tweede functie wordt aangeroepen indien de gebruiker de knop indrukt. Eerst wordt de knop gedisabled, vervolgens wordt er een div in het document toegevoegd achter de knop, en wordt deze div gevuld met het document form.html. Zodra dit document geladen is, wordt de div met een animatie getoond, en wordt er een event handler aan de save knop gehangen. function showform(){ $("#showformbutton").attr("disabled","true") $("#showformbutton").after("<div id='formpanel'></div>"); $("#formpanel").hide().load("form.html", function(){ $("#formpanel").fadein("slow"); $("#savebutton").click( function() { hideform(); ); ); De functie hideform zorgt ervoor dat de div weer verwijderd wordt, en dat de Show Form! button weer bruikbaar wordt. function hideform(){ $("#formpanel").remove(); $("#showformbutton").removeattr("disabled"); Bovenstaand voorbeeld toont dat je inhoud en gedrag volledig kunt scheiden, er staat geen regel Javascript code in de HTML documenten. jquery maakt het verder vrij eenvoudig om een single page applicatie te realiseren, waarbij dynamisch DOM elementen worden toegevoegd of stukken HTML. Je kunt de HTML dus opdelen in verschillende bestanden, het is niet nodig om alle HTML dynamisch met Javascript te genereren. Hierdoor blijft de HTML beter onderhoudbaar. jquery componenten Het succes van jquery heeft er voor gezorgd dat er ondertussen honderden jquery componenten beschikbaar zijn, van formulier validatie functies, tot autocomplete componenten, tot hele complexe tabel componenten. Een complete lijst vind je op de jquery plugin pagina: http://plugins.jquery.com/. De meeste jquery componenten zijn onafhankelijk van de gebruikte technologie op de server. Dit zorgt ervoor dat er meer componenten zijn dan in server technologie specifieke componenten, zoals bijvoorbeeld JSF. JQuery componenten zijn ook een stuk eenvoudig te realiseren dan server componenten, omdat je slechts met 1 implementatie laag te maken hebt: de view laag in de browser. jquery accordion component Het is vrij eenvoudig om nieuwe jquery componenten te implementeren. Onderstaand voorbeeld toont hoe je een accordion menu kunt realiseren. We willen een component maken waarmee we een geneste unorderd list kunnen veranderen in een accordion menu. De eerste lijst bevat menu secties, daarbinnen wordt weer een unordered list gebruikt om de menu opties weer te geven, in de vorm van url links. Een semantisch correct geneste list dus. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1- strict.dtd"> <html> <head> <link media="all" type="text/css" href="example2.css" rel="stylesheet" /> <script src="jquery-1.3.1.min.js" <script src="example2-accordion.js" <script src="example2.js" </head> <body> <div id="mainmenu"> <ul> <li>afdeling <ul> Andrej Koelewijn, IT-eye, 2/8

id="toevoegenafdeling">toevoegen</a></li> id="wijzigafdeling">wijzigen</a></li> id="verwijderafdeling">verwijderen</a></li> id="zoekafdeling">zoeken</a></li> </ul> </li> <li>medewerker <ul> id="toevoegenmedewerker">toevoegen</a></li> id="wijzigmedewerker">wijzigen</a></li> id="verwijdermedewerker">verwijderen</a></li> id="zoekmedewerker">zoeken</a></li> </ul> </li> </ul> </div> </body> </html> Het accordion menu component, example2-accordion.js, bestaat uit 2 onclick event handlers, een om de secties op en dicht te klappen (toggle), en een om ervoor te zorgen dat onclick events op geneste list items, niet door de parent list items gedetecteerd worden. Het component zelf wordt gedefinieerd met de expressie $.fn.accordion. (function($){ $.fn.accordion = function(){ this.find("li:has(ul)").click(function(){ $(this).children().toggle("slow"); ); this.find("li ul li").click(function(event){ event.stoppropagation(); ); )(jquery); Nu hebben slechts één regel code nodig om van de unordered lists een accordion menu te maken: $("#mainmenu").accordion(); jquery form componenten Er zijn een aantal componenten die van pas kunnen komen voor het initialiseren, valideren en vereenvoudigen van formulieren. Een nuttige is de jquery validation plugin (http://bassistance.de/jquery-plugins/jquery-pluginvalidation/). Hiermee kun je eenvoudig de door de gebruiker ingevoerde data controleren. Je kunt validaties op 2 manieren specificeren, in de HTML code, en in Javascript. Enerzijds kun je de gewenste validatie toevoegen als CSS class: <input type="text" id="bsnveld" name="bsn" class="required" /> Je dient dan nog wel de validation plugin op het gewenste formulier te activeren. Dit doe je als volgt: $("#formpanel form").validate(); Invoer wordt nu automatisch gevalideerd: indien de gebruiker het veld verlaat zonder invoer, wordt er automatisch een label achter het veld geplaatst met een error melding. Deze wordt ook weer automatisch verwijderd als de gebruiker iets invoert in het veld. De toegevoegde error melding ziet er als volgt uit: <label class="error" for="bsnveld" generated=" true" style="display: inline-block;">this field is required.</label> Validaties kunnen ook in javascript gedefinieerd worden. De eerder genoemde validatie wordt dan als volgt gedefinieerd: $("#formpanel form").validate({ rules: { voornaam: "required", messages: { voornaam: { required: "Voornaam is een verplicht veld" ); Complexere validaties kunnen op een herbruikbare manier gedefinieerd worden: jquery.validator.addmethod("datenl",function(v alue,element){ return this.optional(element) /^[0-9]{2- [0-9]{2-[0-9]{4/.test(value);,"Voer een geldige datum in (dd-mm-yyyy)"); Datum velden zijn nu eenvoudig van validatie te voorzien: <input id="geboortedatumfield" name="geboortedatum" value="" class="datenl"/> Deze voorbeelden tonen slechts een klein gedeelte van de mogelijkheden van de validation plugin. Een andere nuttige plugin is de jquery masked input plugin (http://digitalbush.com/projects/masked-input-plugin/). Hiermee kun je eenvoudig aangeven wat het formaat van de invoer moet zijn, bijvoorbeeld voor een postcode of datum veld: Andrej Koelewijn, IT-eye, 3/8

$("#postcodefield").mask("9999 aa"); $("#geboortedatumfield").mask("99-99-9999"); Meestal zul je datums via een datepicker willen invoeren. Ook hiervoor zijn meerdere plugins beschikbaar. Het volgende voorbeeld maakt gebruik van de jquery UI datepicker plugin. Met dit component kun je een HTML input tag met één regel Javascript code veranderen in een datepicker veld: $ ('#geboortedatumfield').datepicker({ dateforma t: "dd-mm-yy" ); De kracht van jquery zit voor een groot deel in de grote hoeveelheid plugins die beschikbaar zijn. Je kunt met een paar simpele regels Javascript code semantisch correcte HTML veranderen in rijke gui componenten. Je orginele HTML code blijft eenvoudig en dus goed te onderhouden. Er zijn jquery componenten voor basis functionaliteiten als drag en drop, maar ook voor Google Maps integratie, het tekenen van diagrammen, tabellen, menu's, etc. We kunnen dus stellen dat de combinatie van HTML, CSS, en Javascript is gegroeid tot een technologie waarmee niet alleen webpagina's gemaakt kunnen worden, maar waarmee ook relatief complexe client applicaties gerealiseerd kunnen worden. Javascript frameworks maken dit ook nog eens relatief eenvoudig. Grails Grails is een complete web framework gebaseerd op de ideeen van Ruby on Rails, maar geimplementeerd op bewezen Java frameworks. Grails maakt namelijk gebruik van Spring en Hibernate. Daarnaast is er voor de programmeertaal Groovy gekozen. Deze dynamische programmeertaal draait op de JVM, maar is wat compacter dan Java en biedt ondersteuning voor bijvoorbeeld Closures. Ook kun je eenvoudig op runtime bestaande code uitbreiden met nieuwe functionaliteit. In dit artikel wordt slechts een klein gedeelte van de functionaliteit van Grails gebruikt. Grails blijkt namelijk een van de meest eenvoudige en productieve om REST services te realiseren. REST wordt meestal gezien als de simpele variant van Web Services. Services die via HTTP aangeroepen worden, zondere complexe SOAP XML toestanden, waarbij slechts de relevante data in XML of JSON formaat wordt gecommuniceerd. REST is echter een compleet andere manier van het beschikbaar stellen van services. Huidige SOA implementaties zijn meestal gebasseerd op een van de volgende concepten: Message Queueing de verschillende onderdelen van een gedistribueerde applicatie communiceren met elkaar door middel van het versturen van berichten. Remote procedure calls de verschillende onderdelen van een gedistribueerde applicatie communiceren met elkaar door middel van het aanroepen van functies via het netwerk. Dat REST echt anders is, kan misschien het best verduidelijkt worden door het te zien als een data-model. Resources zijn vergelijkbaar met entiteiten, of, beter nog, views. Deze views maken data beschikbaar, maar verbergen de daadwerkelijke implementatie. Het grote verschil tussen de twee eerder genoemde concepten en REST is dat resources in REST adresseerbaar zijn met behulp van een unieke URL. Iedere resource heeft een URL. Belangrijk is ook dat resource mbv deze URLs linken naar andere resource, niet alleen binnen een organisatie, maar ook naar externe resources. URLs zijn dus feitelijk de primary keys van dit datamodel. Je kunt krijgt daarmee een gedistribueerd datamodel. Om te zien waar dit heen gaat, is het aardig om een service als Yahoo Query Language (YQL) te bestuderen. YQL biedt een soort SQL voor internet resources zoals HTML pagina's. YQL queries zijn zelf ook weer benaderbaar via een URL, en vormen zo dus een soort views bovenop de originele REST resources. Met een dergelijke query engine kun je dus queries uitvoeren om verschillende REST resources van eventueel verschillende organisaties joinen. Het internet wordt zo één grote database. Of dit een juiste architectuur keuze is, zal per project en organisatie bepaald moeten worden. Er zitten natuurlijk ook behoorlijk wat nadelen aan. Maar het is in ieder geval interessant om een echt alternatief te hebben voor SOA projecten. Voor dit artikel is REST erg interessant omdat het goed past binnen het Client-Server verhaal. Domein Objecten Grails heeft een command line tool waarmee je snel een project kunt opzetten. Je kunt hiermee ook de basis van de benodigde domein classes genereren. Daarna is het slechts een kwestie van het invullen van de benodigde attributen. Grails domein classes zijn in feite POJOs die met hibernate gepersisteerd worden. Tabellen worden, indien gewenst, automatisch tijdens het starten van de applicatie gegenereerd. Voor dit voorbeeld voldoet de standaard tabel structuur, maar indien gewenst is deze wel volledig te Andrej Koelewijn, IT-eye, 4/8

configureren in de domein classe code. Ook kunnen validaties worden toegevoegd. class Patient { String voornaam String achternaam String straat String huisnummer String plaats String postcode GregorianCalendar geboortedatum Groovy zorgt zelf voor de benodigde getters en setters, en ook punt-komma's zijn niet nodig. Kort en bondig dus. Services Vervolgens hebben we een controller nodig. Deze handelt de binnenkomende HTTP verzoeken af. In de class UrlMappings kunnen we configureren welke controller welke url afhandeld. In het volgende voorbeeld is gespecificeerd dat de controller patient, geimplementeerd met de class PatientController, alle GET verzoeken voor de url /patient, uitvoert. class UrlMappings { static mappings = { "/patient"(controller:"patient"){ action = [GET:"show"] De patient controller zelf kunnen we ook weer met grails genereren, zodat we slechts de functie show hoeven toe te voegen. Grails voegt zelf aan domein objecten een aantal functies toe die je normaal in DAO objecten zou coderen. De functie list queried alle objecten. Vervolgens kan het resultaat eenvoudig in JSON geformateerd worden mbv render as JSON. import grails.converters.json class PatientController { def show = { def all = Patient.list() render all as JSON Bovenstaande code is feitelijk alles wat we nodig hebben aan de serverkant om een service te implementeren waarmee alle patienten opgehaald kunnen worden. Overzichtstabel De volgende stap is om een HTML tabel te voorzien van data uit bovenstaande patient service: <body> <table id="patienten"> <thead> <tr> <td>voornaam</td> <td>achternaam</td> </tr> </thead> <tbody> <tr> <td colspan="2">no data fetched!</td> </tr> </tbody> </table> <button id="refreshpatientsbutton" type="button">refresh patients</button> </body> Onder de tabel is een button geplaatst. De bedoeling is dat hiermee de tabel gerefreshed kan worden. Eerst definieeren we een onclick event handler voor de button. $(document).ready(function(){ $ ("#refreshpatientsbutton").click( function(){ refreshpatientstable(); ); ); De functie die vervolgens wordt aangeroepen maakt gebruik van de jquery ajax functie. De url die we aanroepen is patient/, deze geeft alle bekende patienten terug in JSON formaat. Vervolgens specificeren we ook wat er moet gebeuren nadat de data succesvol is opgehaald: de functie fillpatienttabledata wordt aangeroepen met de patient data, door jquery al vertaald naar Javascript objecten. function refreshpatientstable(){ $.ajax({ url:"patient/", datatype:"json", success: function(json) { fillpatienttabledata(json); ); De functie fillpatienttabledata loopt door de patienten objecten, en genereert de benodigde HTML voor in de tabel body. Vervolgens wordt de body van de tabel vervangen met de nieuwe HTML tags. function fillpatienttabledata(data){ var tbody = ""; for(var i=0; i<data.length; i++){ console.log("patient: " + data[i]); Andrej Koelewijn, IT-eye, 5/8

tbody += "<tr>"; tbody += "<td>" + data[i].voornaam + "</td>"; tbody += "<td>" + data[i].achternaam + "</ td>"; tbody += "</tr>"; ; if(data.length == 0){ tbody = "<tr><td colspan='2'>no data fetched!</td></tr>"; $("#patienten tbody").html(tbody); Onderstaande screenshot toont het resultaat in Firefox. Onder de html pagina ziet je Firebug plugin. Deze plugin biedt onder andere netwerk data debug mogelijkheden. Zo zie je in de screenshot het resultaat van de service aanroep, een aantal Javascript objecten in een array, in JSON formaat. De Firebug plugin is een onmisbaar tool bij het ontwikkelen van Javascript applicaties. Je kunt onder andere alle HTML wijzigingen live volgen, en CSS en Javascript debuggen. Daarnaast kun je ook all het netwerkverkeer debuggen, inclusief timing gegevens.. Patient details Volgende stap is om ervoor te zorgen dat de gebruiker een patient kan wijzigen. Eerst zorgen we ervoor dat de gebruiker de patient kan selecteren. Dit doen we door de volgende regel toe te voegen in de functie fillpatienttabledata. Iedere regel in de tabel bevat nu een Edit knop. tbody += "<td><button value='" + data[i].id + "' type='button'>edit</button></td>"; De onclick event handler voor deze button wordt in dezelfde functie gedefinieerd: $("#patienten tbody td button").click(function(){ showeditpatientform($(this).val()); ); De functie showeditpatientform roept de eerder gedefinieerde service aan, maar nu specificeren we in de URL ook de id van de gezochte patient. function showeditpatientform(patientid){ $.ajax({ url:"patient/" + patientid, datatype:"json", success:function(json) {initeditpatientform(json); ); De functie initeditpatientform wordt aangeroepen met de patient data van de service aanroep. Eerst wordt een div toegevoegd achter de patient tabel. Hierin wordt het HTML bestand met het edit formulier geladen. Mbv van de populate plugin worden de velden van het formulier geinitialiseerd met de patient gegevens. function initeditpatientform(data){ $("#patienten").after("<div id='patienteditform'></div>"); $ ("#patienteditform").hide().load("editpatientf orm.html",{cache:false, function(){ $("#geboortedatumfield").mask("99-99- 9999"); $("#patienteditform form").populate(data); $("#patienteditform").fadein("slow"); $("#savebutton").click( function(){ savepatient(); ); ); In de controller zorgen we ervoor dat indien er een id is gespecificeerd, alleen de bijbehorende patient wordt gequeried en geretourneerd: def show = { if(params.id &&!params.id.isempty()){ def patient = Patient.get(params.id) render patient as JSON else { def all = Patient.list() render all as JSON In de url mapping voegen we toe dat in de URL optioneel een id parameter meegegeven kan worden: class UrlMappings { static mappings = { "/patient/$id?"(controller:"patient"){ action = [GET:"show"] Andrej Koelewijn, IT-eye, 6/8

Ten slotte het edit formulier. Dit is een standaard, recht toe recht aan HTML formulier: <h2>patient</h2> <form name="form1"> <input type="hidden" name="id"/> <fieldset> <legend>naam</legend> <span> <label for="voornaamfield">voornaam</label> <input id="voornaamfield" name="voornaam" value=""/> </span> <span> <label for="achternaamfield">achternaam</label> <input id="achternaamfield" name="achternaam" value="" /> </span> </fieldset>... <fieldset> <button type="button" id="savebutton">save</button> </fieldset> </form> In onderstaande screenshot het resultaat. In de Firebug console zie je onder andere het resultaat van de service aanroep, de patient data in JSON formaat. Opslaan wijzigingen Tenslotte nog het opslaan van de wijzigingen. De functie serializearray plaatst alle form elementen in een JSON data structuur. Deze kan vervolgens in de ajax aanroep van de service meegegeven worden. Voor het wijzigen van resources wordt HTTP Post gebruikt. function savepatient(){ var patient = $("#patienteditform form").serializearray(); $.ajax({ url:"patient/", datatype:"json", data:patient, type:"post", success:function(json){ alert("patient saved!"); $("#patienteditform").remove();, error:function(xhr){ alert("failed to save patient!: " + xhr.status + ", " + xhr.statustext ); ); In de URL mappings definieeren we dat in het geval van een HTTP Post de save functie aangeroepen dient te worden in de controller. class UrlMappings { static mappings = { "/patient/$id?"(controller:"patient"){ action = [GET:"show",POST:"save"] De save functie bepaalt eerst of het om een nieuwe of reeds bestaande patient object gaat. Indien het object reeds bestaat wordt het gequeried. Daarna worden alle properties van het object voorzien van de waarden zoals meegegeven in de aanroep van de service. Datum waarden dienen bij de huidige aanpak nog handmatig van een string waarde naar een datum waarde omgezet te worden. Volgende stap is om het patient object te persisteren. Indien dit succesvol verloopt wordt het result weer als JSON teruggegeven. In het geval van een error wordt er gebruik gemaakt van de standaard faciliteiten van HTTP voor het communiceren van errors. def save = { def patientsaved try{ def patient params.id? (patient = Andrej Koelewijn, IT-eye, 7/8

Patient.get(params.id)) : (patient = new Patient()) patient.properties = params def dateformat = new SimpleDateFormat( "dd-mm-yyyy" ) def date = dateformat.parse(params.geboortedatum) patient.geboortedatum = (new GregorianCalendar()) patient.geboortedatum.settime(date) patientsaved = patient.save(flush:true) if(!patientsaved){ response.senderror(500,"failed to save patient") else { render patientsaved as JSON catch(error){ response.senderror(500,"failed to save patient") Conclusie jquery en Grails maken het mogelijk om productief en relatief eenvoudig complexe web applicaties te bouwen waarbij de de view laag volledig in de browser is geimplementeerd. Een web framework op de server wordt hiermee overbodig. De client applicatie is volledig stateful, wat ontwikkelen een stuk eenvoudiger maakt. Over de auteur Andrej Koelewijn is IT architect, werkzaam bij IT-eye. Hij is gespecialiseerd in JEE, Oracle en Open Source. Andrej is bereikbaar op het volgende email adres: andrej.koelewijn@it-eye.nl. Daarnaast schrijft Andrej regelmatig op zijn blog: http://www.andrejkoelewijn.com/ Andrej Koelewijn, IT-eye, 8/8