Explanation of how to build a application (3)


How to build a complicated application

In this previous guide we explain how to build 'default' apps in WaihonaPedia (like 'app within minutes' in XWiki)
But in this guide we go over a structure where we can speak of a parent-child application.
Examples of what we believe as 'complex applications' in WaihonaPedia are:

  • Page (sheet) for person with syndrome
  • Registration of medications (Scorecards)
  • Registration of development (like growth) (Scorecards)
  • Registration of public Ask the Expert questions
  • ...

As the example to illustrate we take the Registration of Public Ask the Expert Questions.

Data Model

Which classes are involved (datamodel of the application)
To find them navigate to XWikiClasses.

  • ATEPublicClass With this class we register the questions and answers that are deemed as 'frequently (enough) asked questions'. In other words multiple families are interested in this question
  • DiseaseTagClass With this class we tag the question with diseases for which they are relevant. 1
  • PageTopicTagClass  With this class we can tag the question with One or More (0/1:n) Topics. This allows the visitor to browse through the questions asked by Topic.

(There is actually a fourth 'class' with ATEPublic; the translations of each questions. But this can be considered as a next level complexity that will be out of scope of this guide) 

This translates to ONE wiki page ('the Question-page') having ONE object of class ATEPublicClass and 0, ONE or MORE objects of class DiseaseTagClass and 0, ONE or MORE objects of class PageTopicTagClass.

Visually the visitor could see a page like below;

screenShotATEPublic.png

figure: screenshot from ATE with two markers (1 and 2x2)
The screenshot show the data from Object ATEPublic (the question, the answer, is it checked? The regional area's the answer is valid in.
But it also shows that this question is valid with the Cornelia de Lange syndrome (1).
And it also show it is tagged with two topic's

The user (in this case a moderator) journey to create such a question

  1. Create a new page to hold this question and answer and if it is approved
  2. Tag the page with the disease it is associated with
  3. Tag the page with one or more Topics for Topic-browsing
  4. View the page as in above example

Note that we also add some 'window dressing' like

  • a short introduction to Ask the Expert (top two lines above the green text. 
  • a legal disclaimer, note the twitch it knows to link it to the relevant support group for Cornelia de Lange syndrome 
  • A blue box inviting the visitor to ask a NEW question 

This windowdressing is out-of-scope of this guide. 

1. Create a new page to hold this question and answer and if it is approved

To build this we tweak the default App-Within-Minutes slightly.
Functionally a app created with App-Within-Minutes will

  1. give you a button to add new questions and give a form to define the name, that will be the pagename. This we will modify
  2. then use a SHEET and a TEMPLATE to prepare a new page (not saved yet) with the required fields to fill in the data This we need to modify because we have computer populated fields
  3. SAVE button's to save the page

What will we modify?
We do not like user created pagename's, so we will use a auto-generated Identifier. This Identifier will result in a pagename but also we will store the identifier. This makes for more easier to move pages to different locations. We do not really appreciate the way App-Within-Minutes uses the pagename as a identifier. Because XWiki makes it easy to change page-names, move them to different locations, this could break applications that use the identifier (like ATEPublic that uses the identifier to maintain translations being linked to to the original translation).

The implication of storing the identifier in the newly created page is that we also need to set the value of a property before the save button is pressed (as we do not want that the user needs to enter it again).

1.1 give you a button to add new questions

We want to generate a pagename and ask the user to specify the page title in the page in step 2.
In this case we have a PREFIX: ATE and we want to autonumber increasing with 1 each time
Thus we query the wiki with an XWQL query for latest number, we decode the id to get the latest used number and add 1 to it
#set($ATELatestQueryDef = "from doc.object($ATEPublicClassName) as ate where doc.fullName <> '$ATEPublicTemplateName' and ate.questionID like 'ATE%' order by ate.questionID desc")
#set($latestCreatedQuestionList = $services.query.xwql($ATELatestQueryDef).setLimit(1).execute() )
#set($latestCreatedQuestionID = $xwiki.getDocument($latestCreatedQuestionList[0]).getObject($ATEPublicClassName).getProperty('questionID').getValue() )
#set($latestSequenceString = $stringtool.stripStart($latestCreatedQuestionID,'ATE') )
#set($latestSequenceNum = $numbertool.toNumber($latestSequenceString))
#set($newSeqNum = $latestSequenceNum + 1)
#set($newSeqString = $stringtool.leftPad($newSeqNum, 6, '0') )
#set($newID = "ATE${newSeqString}")

Next we create a button in an HTML form to benefit from the automatic behavior of html forms;
Notes:

  1. We set the form action url to the current document (page)
  2. We use method POST
  3. Some of the input name's target the fields that will be in the object to be created on the new page, thus they will be computer generated
  4. Other input name's are targeting the Xwiki document attributes: doc.name, doc.space
  5. We have hidden inputs, as all inputs are computer generated, just the action (press the button) is done by the user
  6. We could have used (might even be better) the XWiki naming conventions
  7. By pressing submit all the input-name's and the respective values will be in the new Request object
{{html clean=false}}
  <form action="$doc.getURL()" id="newQuestion" method="post">
    <div>
      <input type="hidden" name="ID" value="$newID"/>
      <input type="hidden" name="template" value="WaihonaCode.ATEPublic.ATEPublicTemplate"/>
      <input type="hidden" name="sheet" value="1"/>
      <input type="hidden" name="spaceName" value="ATEPublic"/>
      $services.localization.render('atepublic.overview.new.question.id.label'): <input type="text" name="docName" value="$newID"  size="10"/>
      <span class="buttonwrapper"><input type="submit" value="$services.localization.render('atepublic.overview.new.question.button')" class="button"/></span>
    </div>
  </form>
{{/html}}

The above form will trigger XWiki to put all in a $request object that will look like 

  $request.{
     'ID': 'ATE00001' ,
     'template': 'WaihonaCode.ATEPublic.ATEPublicTemplate' ,
     'sheet': '1' ,
     'spaceName': 'ATEPublic' ,
     'docName': 'ATE00001' }

After the button sends it's request-object to the page the code must check if the new page already exists and if not send the user to the new to be created page, if the page already exists show warning , last 

#if("$!request.docName" != '')
 ## Request for creating a new instance
 #set($docName = ${request.docName})
 #set($targetDocName = "${request.spaceName}.${docName}")
 #if(!$xwiki.exists($targetDocName) && $xwiki.hasAccessLevel('edit', $xcontext.user, $targetDocName))
    $response.sendRedirect($xwiki.getURL($targetDocName, 'edit', "template=${escapetool.url($request.template)}"))
   ## Stop processing, since we already sent a redirect.
   #stop
 #end
 #if("$!targetDocName" != '' && $xwiki.exists($targetDocName))
   {{warning}}$services.localization.render('atepublic.overview.warning.existing.question') [[$services.localization.render('atepublic.overview.warning.existing.question.label')>>$targetDocName]]{{/warning}}
 #elseif("$!targetDocName" != '' && !$xwiki.hasAccessLevel('edit', $xcontext.user, $targetDocName))
   {{warning}}$services.localization.render('atepublic.overview.warning.no.permission.new.question'){{/warning}}
 #end
#end
1.2 then use a SHEET and a TEMPLATE to prepare a new page (not saved yet) ====
  1. In the sheet we set the className and with that name we create a object 'class' having the meta date of the object in this page
  2. We want some fields to be hidden, for example the QuestionID, and this is different for the initial step (Creating), note that some fields will be hidden when changing; like Countries and language
  3.  We set the ID to match the pagename This implies that if somebody changes the pagename later, the questionID will stay the same.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#set($className = 'WaihonaCode.ATEPublic.ATEPublicClass' )
#set($class = $doc.getObject($className).xWikiClass)
#if($xcontext.action == 'edit')
 #if(!$xwiki.exists($doc)  )
   {{info}}
      $services.localization.render('atepublic.overview.add.new.question.info')
   {{/info}}
   ##========
   ##Prepare default fields
   ##========
   #set($discard = $doc.getObject($className).set('questionID', $doc.name) )
   #set($hiddenProperties = [])
   #set($discard = $hiddenProperties.add('questionID') )
   #set($discard = $hiddenProperties.add('parentQuestionID') )
   #set($discard = $hiddenProperties.add('country') )
   #set($discard = $hiddenProperties.add('language') )
 #else
   #set($hiddenProperties = [])
   #set($discard = $hiddenProperties.add('questionID') )
   #set($discard = $hiddenProperties.add('parentQuestionID') )
 #end
  ...

2. Tag the page with the disease it is linked with

This is the part where we seriously deviate from a default App-Within-Minutes page.
Resume: A normal App-Within-Minutes app will create records (instances) of ONE class on ONE document (page) having ONE Object of the class on this PAGE.
But now we want to add a instance (object) of another Class to the above Page.
And we want to do this using the normal XWiki VIEW/EDIT modes, as our users will experience that as the normal

In the VIEW state the page should show a overview of the linked diseases (we will only have Zero or 1 link, but in this way the pattern will also work for other use-cases.

When the user clicks ADD a link, or Modify the link we should switch to EDIT-mode to have the normal XWiki buttons: 'Save and View', 'Save and Continue', 'Preview' and 'Cancel' at the bottom of the screen (again to keep the user experience as close as possible as expected by our users.

Important knowledge. For better understanding we advise to check the XWiki guide on Sheets

Class sheet
The page we want to add a link to a disease holds an object of ATEPublicClass. This class has a a sheet defined as it's class sheet. This means we need a hook in this sheet to tell it what to do when the user wants to VIEW or EDT the link. Especially for EDIT it is important to change the behavior of the SAVE buttons. For default these buttons will submit a form holding fields for the ATEPublicClass.
View and present a button for adding a link to a disease

Since this object must be created first before SAVE button is pressed we need to change the default behavior of the Parameter: objectPolicy. Normally when you enter data on a XWiki page the OBJECT is already there as it came from the template. The formfields will just update the values. But when creating NEW object we must tell the SAVE button to also CREATE the object before SAVE.

  1. ^ Current implementation we would allow only one disease per question, but in next implementation we can envision a question that is relevant for multiple diseases

About the website contents

 

All of the information on this WebSite is for education purposes only. The place to get specific medical advice, diagnoses, and treatment is your doctor. Use of this site is strictly at your own risk. If you find something that you think needs correction or clarification, please let us know at: 

Send a email: wiki@waihonapedia.org