Monday, March 4, 2013

New Ajax/JSON Functionality for BB2.0

From Steven de Klerk, Senior Developer at BlueBox:

New Ajax functionality has been added to BB2 this week, allowing for any PHP function to be easily accessed via JavaScript through the use of Ajax and optional JSON objects, without the need for additional coding. The function to call via Ajax is simply called "ajax" and is available on all BB2 modules. This function accepts a few parameters, listed below:
  • global[ajax_method] - Required. Sets the function to be called within the module
  • global[param] - Optional. The parameters to be passed to the called function, as an indexed array. So, param[0], would be the first parameter. param[1] the second, and so on. e.g. $_class->method(param[0], param[1]);
  • global[json_encode] - Optional. Sets the response to the Ajax call. Default is a basic "success" response, otherwise when this param is set to "1", it will return a JSON encoded object.
The new "ajax" function does a permission check to ensure the user can run the "ajax_method" listed, and then either returns a basic "success" if the function was run without problems, or returns a JSON object, which would be the primary use for this new functionality.
Let's say we wanted to add a new user with the user name of "testuser" and the first name of "Paul". To do this, we'd simply call the following url:
/?class=bb_users&method=ajax&global[ajax_method]=add&global[param][0][this_class]=bb_users&global[param][0][fields][name]=testuser&global[param][0][fields][first_name]=Paul
Breaking that up, you'll see we've called "ajax" on the class "bb_users", and set the PHP function as "add". We then pass through the parameters. Since the "add" function only takes one mixed array, we're going to set global[param][0] with our array of data. In this case, it's just the "this_class" parameter, and then the "name" and "first_name" fields. Since we haven't set it to return a JSON encoded object, it will just print out the text "success" on completing. If you use this method, make sure to check that the response text only contains the word "success" (responseText == 'success'), as an error could also be present, and should be displayed to the user in that case.
This, however, doesn't fully utilize the new functionality. To do this, "global[json_encode]=1" should be passed in the url, telling the ajax function to return a usable JSON object, which provides far more information. For example, running the same url above, but with the included JSON encoding switch, we see the returned data is:
{"response":{"this_class":"bb_users","fields":{"name":"testuser","first_name":"Paul"},"do_not_redirect":"true","_id":"52"},"rows":4,"html":"","status":"success","error":""}
This is a JSON encoded string, and thanks to JavaScript libraries such as Prototype, we can turn this into an easy to use object by calling "evalJSON()" on the reponseText. The JSON object contains a few parameters:
  • response - the response from the function called. This can be anything, depending on what the function returns
  • rows - the number of rows. If there's only 1 result (such as a "get" or "add" call), it will list the number of elements.
  • html - any outputted HTML while running the function. Useful if the function does resp/print calls
  • status - whether the function completed successfully or not
  • error - any errors that may have been caught while running the function
The first thing to do when checking the response, is to make sure that the "status" parameter == 'success', and if it doesn't, then check the "error" parameter to see if any errors were caught. If it was successful, you can now check the function response and use the returned data. So, if we wanted to alert the new _id of the user we added, we can do so like this (assuming that the variable "data" is the evaluated JSON object):
if (data.status == 'success') {
     alert(data.response._id);
} else {
     alert('Error: ' + data.error);
}
Handling and calling the new "ajax" function can all be done fairly easily through Prototype's Ajax.Request functionality, however, to make things even easier, there's a new BB2 ajax function which handles most of the leg work described above.
The new JavaScript function is called "ajax2json", and is a quick and easy gateway to the above functionality.
The new function takes the following parameters:
ajax2json(callback, className, method, param, loaderElm, largeLoader)
  • callback - Required. (function) The callback function when the response has arrived from the request
  • className - Required. (string) The BB2 class/module to call
  • method - Required. (string) The BB2 method to call on the above class
  • param - Optional. (object) An object containing the parameters to be passed to the above class->method
  • loaderElm - Optional. (string) The HTML element to add a loading spinner during the request
  • largeLoader - Optional. (bool) Whether or not to use a large spinner
So, let's do the same user add as above, and then get a list of users with the same name as what we've added. To start off with, we'll create a callback handler and then an "add" function:
 function handleAddResponse(data) {
  if (data.status == 'success') {
   alert('New record added with _id: ' + data.response._id);
  } else {
   alert('Error: ' + data.error);
  }
 }
 function addUser() {
  var param = {
   0: {
    fields: {
     name: 'testuser',
     first_name: 'Paul'
    }
   }
  };

  ajax2json(handleAddResponse, 'bb_users', 'add', param);
 }
Breaking down the above, we call "ajax2json" with the callback function "handleAddResponse", which checks to make sure the response was successful, and if so, it alerts the new _id. We then set the class, method and parameters which is a basic JavaScript object, made up of the fields we want to set.
Once we've added our user, we want to get a list of users with the name "Paul" and then handle that data. This can be done like so:
 function handleListResponse(data) {
  if (data.status == 'success') {
   alert('Found ' + data.rows + ' row(s).');
   data.response.each(function (row) {
    var output = '';
    for (var field in row) {
     output += field + ': ' + row[field] + '\n';
    }
    alert(output);
   });
  } else {
   alert('Error: ' + data.error);
  }
 }
 function listUsers() {
  var param = {
   0: {
    where: 'first_name LIKE \'%paul%\''
   }
  };

  ajax2json(
handleListResponse, 'bb_users', 'getList', param);
 }
This time our callback function is a bit more advanced, as we're going to run through the response data and alert the values. If we do the add before the list, we'll get back at least one row containing all of the data for our new user record. We can now display this data in a table, use it in another add, and more.
With this new functionality, there should no longer be a need to create additional BB2 functions to act as "proxies" between standard and custom BB2 functions and the browser, as we can now pass and receive data between the PHP side of BB2 and the client/browser side seamlessly.

No comments:

Post a Comment