| 128 | | if (type == 'error') |
| 129 | | alert('Error when retrieving data from the server!'); |
| 130 | | else |
| 131 | | // de code the simpleJson answer from django ''details'' method. |
| 132 | | // it populates a Js array ! straigth so cool ! |
| 133 | | arrayData = dojo.json.evalJson(data); |
| 134 | | // now we update the html using the css id as a pointer to the part |
| 135 | | // we want to update |
| 136 | | dojo.byId("mark_total").innerHTML = arrayData[1]; |
| 137 | | dojo.byId("mark_message").innerHTML = arrayData[2]; |
| 138 | | dojo.byId("mark_status").innerHTML = arrayData[3]; |
| 139 | | // and the fancy fading effect |
| 140 | | dojo.lfx.html.highlight("mark_status", [255, 151, 58], 700).play(300); |
| 141 | | } |
| 142 | | |
| 143 | | function init() |
| 144 | | { |
| 145 | | var sendFormButton = dojo.byId('sendFormButton'); |
| 146 | | dojo.event.connect(sendFormButton, 'onclick', 'sendForm') |
| 147 | | } |
| 148 | | |
| 149 | | dojo.addOnLoad(init); |
| 150 | | |
| 151 | | </script> |
| 152 | | }}} |
| 153 | | |
| 154 | | the following ''HTML code'' just comes after the upper code snipset. |
| 155 | | |
| 156 | | {{{ |
| 157 | | [... total mark get updated, lets put css id="mark_total" ...] |
| 158 | | {% if r.total_mark %}<li><b>Score</b>: <span id="mark_total">{{ r.total_mark }}</span>/5</li>{% endif %} |
| 159 | | [....] |
| 160 | | {% if not user.is_anonymous %} |
| 161 | | {% ifnotequal user.id r.owner_id %} |
| 162 | | <form enctype="multipart/form-data" id="myForm" method="post"> |
| 163 | | <span id="mark_message">{{mark_message}}</span> |
| 164 | | <select name="select_mark"> |
| 165 | | <option value ="1" {% ifequal my_mark 1 %} selected {% endifequal %}>1</option> |
| 166 | | <option value ="2" {% ifequal my_mark 2 %} selected {% endifequal %}>2</option> |
| 167 | | <option value ="3" {% ifequal my_mark 3 %} selected {% endifequal %}>3</option> |
| 168 | | <option value ="4" {% ifequal my_mark 4 %} selected {% endifequal %}>4</option> |
| 169 | | <option value ="5" {% ifequal my_mark 5 %} selected {% endifequal %}>5</option> |
| 170 | | </select> |
| 171 | | </form> |
| 172 | | <button id="sendFormButton">Notez</button> |
| 173 | | <br/> |
| 174 | | <span id="mark_status">{{ mark_status }}</span> |
| 175 | | {% endifnotequal %} |
| 176 | | {% endif %} |
| 177 | | }}} |
| 178 | | |
| 179 | | And, voila. |
| 180 | | |
| 181 | | To have a demo use guest as login, guest as password here [http://ozserver.no-ip.com:345] or if not working here [http://www.cefinban.net]. |
| 182 | | Go to index and pick a recipe, update the rating. |
| 183 | | |
| 184 | | You can also have a look at the screenshot here : [http://ozserver.no-ip.com/~greg/images/ajaxdjango.png] |
| 185 | | |
| 186 | | == Dreamhost and Simplejson == |
| 187 | | |
| 188 | | If you are using dreamhost for hosting please be aware that simplejson is not installed. |
| 189 | | Instead you will have to install the source of simplejson in a folder in your home directory eg /proz/json/simple_json |
| 190 | | The simple_json directory contains the required __init__.py for it to be loaded as a python module. |
| 191 | | |
| 192 | | Then in your ~/.bash_profile add the directory to your python path like below. |
| 193 | | |
| 194 | | {{{ |
| 195 | | export PYTHONPATH=$PYTHONPATH:$HOME/django/django_src:$HOME/django/django_projects:$HOME/progz/json |
| 196 | | }}} |
| 197 | | |
| 198 | | That will allow yout to use simpl_json in python shell. |
| 199 | | But '''dont forget''' to change django.fcgi ! |
| 200 | | Add |
| 201 | | {{{ |
| 202 | | sys.path +=['/home/coulix/progz/json'] |
| 203 | | }}} |
| 204 | | log out/in and try import simple_json (or simplejson depends on what source you picked) |
| 205 | | |
| 206 | | {{{ |
| 207 | | #!html |
| 208 | | <a name="P2"><h1>Handling the form when JavaScript is deactivated.</h1></a> |
| 209 | | }}} |
| 210 | | If a user has deactivated his browser's javascript support, or is using a text mode browser, we need a way of making the previous rating button submit the rating to the server which should this time return an html template instead of data to the Ajax call. |
| 211 | | |
| 212 | | == Updating the form HTML (details.html template) == |
| 213 | | This time we put a submit type input inside the form instead of the button type in part 1. |
| 214 | | type="submit" as indicates its name, submits the form to the server, we will need a way of stopping this behavior using javaScript. |
| 215 | | |
| 216 | | {{{ |
| 217 | | <form enctype="multipart/form-data" id="myForm" method="post"> |
| 218 | | <span id="mark_message">{{mark_message}}</span> |
| 219 | | <select name="select_mark"> |
| 220 | | [...] |
| 221 | | </select> |
| 222 | | <input id="sendFormButton" type="submit" value="Notez" /> |
| 223 | | </form> |
| 224 | | }}} |
| 225 | | |
| 226 | | Now, how can we tell our details method in view.py to know if it comes from a normal submit request or an Ajax request ? |
| 227 | | Two solutions, |
| 228 | | |
| 229 | | The '''first''' uses a hidden variable in form.html and an added content element in the JS part. |
| 230 | | |
| 231 | | {{{ |
| 232 | | function sendForm() |
| 233 | | { |
| 234 | | dojo.byId("mark_status").innerHTML = "Loading ..."; |
| 235 | | dojo.io.bind({ |
| 236 | | url: '.', |
| 237 | | handler: sendFormCallback, |
| 238 | | content: {"js", "true"}, |
| 239 | | formNode: dojo.byId('myForm') |
| 240 | | }); |
| 241 | | } |
| 242 | | |
| 243 | | |
| 244 | | [...] |
| 245 | | <form enctype="multipart/form-data" id="myForm" method="post"> |
| 246 | | [...] |
| 247 | | <input type="hidden" name="js" value="false"> |
| 248 | | </form> |
| 249 | | }}} |
| 250 | | |
| 251 | | With this, in our django method in view.py we can test for request["js"]=="true" it would means that Js is activatd and we return the appropriate answer to the Ajax request. |
| 252 | | |
| 253 | | The '''second''' uses the url to pass a new variable ajax_or_not to the detail method. |
| 254 | | |
| 255 | | {{{ |
| 256 | | #!python |
| 257 | | def details(request, r_slug, r_cat, ajax_or_not=None): |
| 258 | | [...] |
| 259 | | }}} |
| 260 | | |
| 261 | | We modify the url.py to accept this new parameter. |
| 262 | | {{{ |
| 263 | | #!python |
| 264 | | (r'^recettes/(?P<r_cat>[-\w]+)/(?P<r_slug>[-\w]+)/(?P<ajax_or_not>.*)$', 'cefinban.recettes.views.details'), |
| 265 | | }}} |
| 266 | | |
| 267 | | The dojo binding needs to append a variable to the original document url, to make ajax_or_not not None. |
| 268 | | |
| 269 | | {{{ |
| 270 | | function sendForm() |
| 271 | | { |
| 272 | | dojo.byId("mark_status").innerHTML = "Loading ..."; |
| 273 | | dojo.io.bind({ |
| 274 | | url: './ajax/', |
| 275 | | handler: sendFormCallback, |
| 276 | | formNode: dojo.byId('myForm') |
| 277 | | }); |
| 278 | | } |
| 279 | | }}} |
| 280 | | |
| 281 | | == New details method in view.py == |
| 282 | | |
| 283 | | We just need to test for the existence of ajax_or_not |
| 284 | | |
| 285 | | {{{ |
| 286 | | #!python |
| 287 | | def details(request, r_slug, r_cat, ajax_or_not=None): |
| 288 | | [...] |
| 289 | | if request.POST: |
| 290 | | [...] same as part 1 |
| 291 | | # except here we check ajax_or_not |
| 292 | | if ajax_or_not: |
| 293 | | # use json for python js exchange |
| 294 | | # it was a french string, if we dont't use unicode |
| 295 | | # the result at the output of json in Dojo is wrong. |
| 296 | | message = unicode( message, "utf-8" ) |
| 297 | | jsonList = simple_json.dumps((my_mark, total, form_message ,message)) |
| 298 | | return HttpResponse(jsonList) |
| 299 | | |
| 300 | | return render_to_response('recettes/details.html', {'r': r, 'section':'index', |
| 301 | | 'mark_status':message , 'mark_message':form_message, 'my_mark': my_mark}, |
| 302 | | context_instance=RequestContext(request),) |
| 303 | | }}} |
| 304 | | |
| 305 | | {{{ |
| 306 | | #!html |
| 307 | | <a name="P3"><h1>Fixing the frozen fading when user resend the form without waiting for the first fading to end.</h1></a> |
| 308 | | }}} |
| 309 | | If you haven't realised yet, if two or more calls are sent to the javascript function sendForm in a short time, the fading effect of the current sendForm Callback method might get stuck / froze / bugged. |
| 310 | | We need a way of avoiding this by desactivating the connection between the submit button and the sendForm method while the fading '''animation''' is active. |
| 311 | | Thanks Dojo there is such things ! in two lines of code its done. |
| 312 | | |
| 313 | | |
| 314 | | {{{ |
| 315 | | function sendFormCallback(type, data, evt) |
| 316 | | { |
| 317 | | [...as before ...] |
| 318 | | // and the fancy fading effect |
| 319 | | |
| 320 | | // first disconnect the listener ! |
| 321 | | dojo.event.disconnect(sendFormButton, 'onclick', 'sendForm'); |
| 322 | | // assign our fading effect to an anim variable. |
| 323 | | var anim = dojo.lfx.html.highlight("mark_status", [255, 151, 58], 700).play(300); |
| 324 | | // When this anim is finish, reconnect |
| 325 | | dojo.event.connect(anim, "onEnd", function() { dojo.event.connect(sendFormButton, 'onclick', 'sendForm'); }); |
| 326 | | } |
| 327 | | }}} |
| 328 | | |
| 329 | | how nice is this ! |
| 330 | | Careful, while talking about how to fix the problem using onEnd in Dojo IRC chanel, they realised play() method didnt behave properly and updated it to react to onEnd and such. |
| 331 | | su you need at least revision '''4286'''. |
| 332 | | Update your dojo source |
| 333 | | |
| 334 | | {{{ |
| 335 | | svn co http://svn.dojotoolkit.org/dojo/trunk dojo |
| 336 | | }}} |
| 337 | | |
| 338 | | |
| 339 | | |
| 340 | | |
| 341 | | '''Note''' It might be completely wrong. |
| 342 | | More questions / complaints: coulix@gmail.com |
| 343 | | |