Changes for page Best Practices

Last modified by Vincent Massol on 2017/09/05

<
From version < 3.2 >
edited by Silvia Macovei
on 2010/02/26
To version < 4.1 >
edited by Eduard Moraru
on 2012/05/23
>
Change comment: Added a best practice for "Handling errors when using xredirect for non-Javascript UIs"

Summary

Details

Page properties
Author
... ... @@ -1,1 +1,1 @@
1 -XWiki.SilviaRusu
1 +XWiki.enygma
Content
... ... @@ -8,7 +8,7 @@
8 8  
9 9  Class sheet documents should be written using the following construct (this is an example for displaying documents containing XWiki.XWikiUsers objects):
10 10  
11 -{{code}}
11 +{{code language='velocity'}}
12 12  #set($obj = $doc.getObject("XWiki.XWikiUsers"))
13 13  #if(!$obj)
14 14   1 User Sheet
... ... @@ -20,3 +20,69 @@
20 20  {{/code}}
21 21  
22 22  {{info}}The 'if' tests first for the non existence. This is so that XWiki extract the title from the //1 User Sheet//, which is a proper title to display when viewsing the sheet page, instead of the computed name which will usually display something wrong.{{/info}}
23 +
24 += Handling errors when using xredirect for non-Javascript UIs =
25 +
26 +When writing an UI with JavaScript, AJAX takes care of forwarding your action to a background service replying with success or with an error that is then displayed to the user in the same page.
27 +
28 +Without JavaScript, we usually use the xredirect query parameter to specify the current page (and state) to which we want to come back after performing an action (by pressing a button, link, submitting a form, etc.).
29 +
30 +One common problem when writing UIs without JavaScript in this way is error handling. In other words, how do you handle the situation when the service that you use to perform your action throws an error?
31 +
32 +A simplified code for this in the background service that produces the error is:
33 +
34 +{{code language='velocity'}}
35 +#handleRequest($success)
36 +#if ($success)
37 + #if ($request.action == 'get' || $request.xpage== 'plain')
38 + ## JavaScript call here.
39 + Action was successful.
40 + #elseif ("$!request.xredirect" != '')
41 + ## No-JavaScript here. Redirect.
42 + $response.sendRedirect($request.xredirect)
43 + #end
44 +#else
45 + #if ($request.action == 'get' || $request.xpage== 'plain')
46 + ## JavaScript call here.
47 + Action was NOT successful.
48 + $response.setStatus(403)
49 + #elseif ("$!request.xredirect" != '')
50 + ## No-JavaScript here. What now!? Redirect?
51 + #handleErrorHere($request.xredirect)
52 + #end
53 +#else
54 +{{/code}}
55 +
56 +The idea is that you want to pass the error message to the UI but you don`t have a clear way of doing it, like you have for AJAX calls (response code and response text). A solution is to use the Session in order to pass your error message. You set the error in the service and, in the UI, you read and remove it so that it is only displayed once.
57 +
58 +For the background service, it translates to:
59 +
60 +{{code language='velocity'}}
61 +...
62 + #elseif ("$!request.xredirect" != '')
63 + ## No-JavaScript here. Redirect and forward error message.
64 + $request.session.setAttribute("${errorMessageKeyPrefix}${request.xredirect}", 'Action was NOT successful')
65 + $response.sendRedirect($request.xredirect)
66 + #end
67 +...
68 +{{/code}}
69 +
70 +On the UI side:
71 +
72 +{{code language='velocity'}}
73 +...
74 + #set ($xredirect = $doc.getURL($context.action, $!{request.queryString}))
75 + #set ($errorMessage = $request.session.getAttribute("${errorMessageKeyPrefix}${xredirect}"))
76 + #if ("$!errorMessage" != '')
77 + ## Clean the error and display the message.
78 + #set ($discard = $request.session.removeAttribute("${errorMessageKeyPrefix}${xredirect}"))
79 + {{error}}$errorMessage{{/error}}
80 + #end
81 +...
82 +{{/code}}
83 +
84 +Note that using xredirect's value as session key (prefixed or not) is a good idea because:
85 +1.it's already there in both the UI (for sending it as parameter) and the background service (received as parameter)
86 +2.it acts like a namespace, ensuring that the error will only be displayed for the current page/request.
87 +
88 +This method works together with the whole purpose for which we are doing the redirect in the first place (so that the user can refresh the page without re-sending the action or re-posting a form), ensuring that after the first display, on a refresh, the error goes away.

Get Connected