This is a pretty technical blog entry today, but I thought I'd post it seeing as how difficult it has been for me to find any reliable information on how all this works.
Dojo is an awesome Javascript framework, and their Grids are world-class examples of how to manage large volumes of data through a consistent, reliable and familiar interface. It supports all sorts of features from row sorting, paging and in-line editing through to custom formatters. Today's blog is about in-line editing, and how to handle errors.
Typically when you're editing a value in a form, your form needs to be able to return an error message should the submitted value be somehow incorrect. Some of this you can do client-side, but many other transactions require you to hit the back-end server and confirm the validity of the submitted value - to check if the users has correct permissions, or that there's enough credits in their account to post, or any number of possiblities.
The editing in Dojo's grid is well documented, except for the error handling. I'll show you how.
First of all, I'm assuming you're using the JsonRestStore as your data store, as that's the one I'm using, but I'm pretty sure the others work on a similar principle.
In order to get Dojo's store to recognize there was an error in its write request, you have to return a http response code other than 200 - something in the 400s or 500s is usually appropriate. For this solution, I've chosen a nice and obscure 409, for reasons that will become obvious soon.
So, your application has to generate a 409 in its response, and send through the appropriate error strings in order to have them parsed out in the Javascript. Here's an example of how I did my PUT controller in a Zend framework application.
<?php
public function putAction() {
Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true);
if ($this->_request->isPut()) {
$formData = Zend_Json::decode($this->_request->getRawBody());
if (false === $this->getModel()->update($formData['id'], $formData)) {
$this->_helper->layout->disableLayout(true);
$errors = $this->getModel()->getErrors();
$this->getResponse() ->setHttpResponseCode(409) ->setBody(json_encode( (isset($errors) ? $errors: '' )));
}
} else {
throw new Exception('Incorrectly called controller action');
}
}
?>
The reason here for using a 409 is that firstly, the error is somewhat appropriate, but secondly, because I've chosen to disable the server-generated HTML error response for 409 errors. This is so that I have a clean JSON error array when our response gets back to the data store. In order to disable the HTML, add a
ErrorDocument 409 " "to your .htaccess file.
Once this is done, your server is ready to generate a response we can deal with back in the Javascript world. In order to grab this response though, we have to write a customized onError handler for our store.save method. Here's how it's done.
In my application, I have a "save grid changes" button. This is fairly straight-forward, it's a Dojo button that users can click once they have finished their edits in the grid. Here's my code:
<button busylabel="Saving data" dojotype="dojox.form.BusyButton" id="gridButtonChargeback" timeout="5000">
Save grid changes</button>
I'm using a BusyButton because it provides a little more feedback to the user, but you can use a regular button if you like. The interesting part is in the store.save method - the onError handler passes its error object through to a my function parseGridError, in which we can pull apart the response and display the error to the user.
function parseGridError(response) {
var errors = JSON.parse(response.responseText);
for ( var i in errors ) {
alert( errors[i] );
}
}
Obviously this is a very simple example of what you can do to display the errors, and indeed I've since gone on to open a dijit.Dialog that displays a lengthy description and the error messages nicely listed out, but the mechanism remains the same - your application is generating a http response code, a list of errors in JSON, it's being handled by the onError handler in the store.save method, and then you print it out to the user. It's probably a good idea to let the user know that their store has reverted to the state it was in before they started their latest batch of edits, too.
I hope this helps someone out there, because it took a lot of time to pull all this information together, this side of things isn't really documented in Dojoland. Feel free to point out any better ways of achieving this solution too, it's probably not the best way of doing things, but it certainly seems to work so far!

Comments
Thanks a lot!
I'm going to try that code right now!
Post new comment