This is the documentation for LemonStand V1, which has been discontinued. You can learn more and upgrade your store here.

LemonStand Version 1 Has Been Discontinued

This documentation is for LemonStand Version 1. LemonStand is now offered as a cloud-based eCommerce platform.
You can try the new LemonStand and learn about upgrading here.

Using AJAX

LemonStand Administration Area has a built-in AJAX implementation, which allows you to send AJAX requests from your pages and process them in a page controller. PHP Road AJAX framework is built upon the MooTools JavaScript framework. PHP Road is a PHP framework LemonStand is based on.

Sending and processing AJAX requests

To send an AJAX request, you need to write a few lines of JavaScript code. Each AJAX request should be bound to a specific FORM element. To create an opening FORM element use the Phpr_Form::openTag() construction. Example:

<?= Phpr_Form::openTag() ?>
  <!-- Form content is here -->
</form>

We also want to mention that LemonStand can build forms automatically and you almost never will need to write the HTML code for creating form elements like text fields. The process of building forms will be described in the Lists and forms in the Administration Area article. However, you need to declare the FORM element manually, using the syntax described above.

To send an AJAX request, you first need to obtain a JavaScript object corresponding the form element. It is easy to find a form object, if have a reference to any object inside the form. Each HTML element in the LemonStand Administration Area has the getForm() method, which finds a form the element belongs to. For example, if you are need to send an AJAX request when user clicks a link inside a form, you can use the following code:

<?= Phpr_Form::openTag() ?>
  <a href="#" onclick="$(this).getForm().sendPhpr('index_onSomeEvent'); return false;">Send request</a>
</form>

The code creates a form and a link inside it. The link click handler contains JavaScript code which finds a FORM element which wraps the link. After that the form sendPhpr() method is called. This method is added by the LemonStand framework. The method accepts two parameters, and only the first parameter is required. This parameter is a name of the controller method which should handle the request. To prevent the browser redirection, the click handler JavaScript code returns FALSE value.

Another way to access a form element from JavaScript is to specify the form identifier in the Phpr_Form::openTag() function call. This function can accept a single array-typed parameter. Each element of the array becomes a FORM tag attribute in the result HTML code. For example, if you use the following code 

<?= Phpr_Form::openTag(array('id'=>'my_form', 'class'=>'some_class')) ?>
  <!-- Form content is here -->
</form>

the function will return the following HTML markup:

<form action="/your/page/url" method="post" id="my_form" class="some_class" onsubmit="return false;">
  <!-- Form content is here -->
</form>

The onsubmit, action and method attributes are added by function automatically. Also, if you do not define the id parameter, LemonStand will use the "FormElement" default value. 

Now, if you know a form identifier, you can access it from JavaScript code directly, in the following way:

<?= Phpr_Form::openTag(array('id'=>'my_form')) ?>
  <a href="#" onclick="$('my_form').sendPhpr('index_onSomeEvent'); return false;">Send request</a>
</form>

Processing a request

To process the request on the server side, you need to declare an event handler in the controller class. In the example above we invoke the index_onSomeEvent handler. This handler should be declared in the controller class in the following way:

protected function index_onSomeEvent()
{
}

There are 2 limitations applied to the event handlers:

  • Handlers should be declared as protected class methods
  • Event handler names should start with an action name and the _on letters. In the example above, we imply that the link is situated on the index controller page and we used the index_on prefix. If you are coding a page corresponding the 'edit' action, your event handlers should have the edit_on prefix.

In some rare cases you may need to have a handler callable from different pages. It is possible by adding the $globalHandlers field to the controller class declaration. For example, in LemonStand Orders controller we have defined some global event handlers, which we can call both from the Create Order and Edit Order pages:

public $globalHandlers = array(
  'onCopyBillingAddress', 
  'onBillingCountryChange'
);

Of course you will need to define the event handler methods, with names matching the handler names defined in the $globalHandlers array.

The important feature of event handler class methods is that LemonStand passes to them function parameters in a similar way as it does it with actions. In the Adding a back-end user interface article in the Page parameters section we described how LemonStand converts URL sections to action method parameter values. If you have the /abcblog/posts/edit/4, you can get the parameter value in the action method (the edit action in this case):

public function edit($id)
{
  // $id value is 4
}

All AJAX event handlers called from the edit page will receive the same parameter. For example:

public function edit_onSave($id)
{
  // $id value is 4
}

Accessing form field values in the event handler

When you send an AJAX request, you can access all values of posted form fields through the PHP $_POST variable. LemonStand API has a jmore useful replacement of the $_POST array - the post() function. This function has 2 parameters - the POST field name and the field default value (the second parameter is optional). Thus, if a form contains a text input element with name "first_name", you can access the field value in the handler with the following code:

$name = post('first_name', 'John'); 

Request options

You can configure a behavior of the sendPhpr() function by passing configuration parameters to the second method parameter. The second parameter should be a JavaScript hash variable, which you can define using the curly brackets:

$(this).getForm().sendPhpr('index_onSomeEvent', {
  // Define parameters here
});

You can find descriptions of all possible request parameters below.

  • extraFields - allows to add extra form field values in addition to values of field contained by the form. The value should be a JavaScript hash object. Example:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      extraFields: {'last_name': 'Doe'}
    });
    
    If you execute this request, you can access the last_name POST value in the event handler, as it was described earlier.
  • loadIndicator - configures the loading indicator behavior. Please see a detailed description of the parameter in the Managing loading indicators section below.
  • confirm - allows to ask a user to confirm the action before sending the request. Example:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      confirm: 'Do you really want to delete this record?'
    });
    
  • alert - allows to display a message instead of sending the request:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      alert: 'You cannot delete this record'
    });
  • preCheckFunction - allows to execute some code before sending the request. The function must return TRUE if the request is allowed. This function is called before displaying messages specified in the confirm and alert parameters. Example:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      preCheckFunction: function(){ 
        if (!some_condition)
        {
          alert('You cannot perform this operation');
          return false;
        }
        return true;
      }
    });
  • postCheckFunction - works in the same way as the preCheckFunction, but is the function executed after displaying messages specified in the confirm and alert parameters.
  • prepareFunction - allows to execute some preparation code before sending the request.
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      prepareFunction: function(){ 
        // Do some preparation work
      }
    });
  • update - allows to specify a page element identifier to be updated in case of the request success. Please read the Updating page content section below for details.
  • onSuccess - function to execute in case of the request success.
  • onComplete - function to execute when the request completes, the both cases - success or failure.
  • onFailure - function to execute in case if the server returned an error. Please read the Processing server errors section below for details.
  • onAfterError - function to execute if the server returned an error, after executing any JavaScript code sent by server.
  • onAfterUpdate - function to execute when the framework finishes updating page content in case of the successful request.

Managing loading indicators

By default, when you initiate an AJAX request, LemonStand displays a loading indicator on a gray rectangle overlapping the form. And by default LemonStand does not hides the loading indicator when the request completes.

The loadIndicator request parameter mentioned above is a JavaScript hash object which can have the following fields:

  • show - a Boolean-type parameter, which indicates whether the indicator should be displayed. The default value is true. You can disable the loading indicator using the following code:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      loadIndicator: {show: false}
    });
    
  • hideOnSuccess - indicates whether the indicator should be hidden in case of the request success. The default value is false. You can use the following code to turn automatic indicator on:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      loadIndicator: {hideOnSuccess: true}
    });
    
  • injectInElement - indicates whether the loading indicator DIV element should be injected inside the FORM element. By default LemonStand creates a DIV element with absolute position and coordinates matching the form element. However in some circumstances, when the form can change it size or position during the request, you may need to inject the indicator into the form:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      loadIndicator: {injectInElement: true}
    });
    
    To use this approach you also should wrap the form element into a DIV element with the relative CSS class:
    <div class="relative">
      <?= Phpr_Form::openTag() ?>
        <!-- Form content is here -->
      </form>
    </div>
    
  • element - allows to specify an HTML element other than the form, to display the loading indicator above it. We sometimes use this approach in LemonStand to display a loading indicator above some form area, instead of the whole form. For example, on the Create/Edit Product page we display a loading indicator above the option list, instead of the whole form:

    Code example:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      loadIndicator: {element: 'some_element_id'}
    });
    
  • src - allows to specify an image URL to display instead of the default loading indicator image. LemonStand includes a number of loading indicators of different size: 30, 40, 50, 70 and 100 pixels. You can use a specific image:
    $(this).getForm().sendPhpr('index_onSomeEvent', {
      loadIndicator: {src: 'phproad/resources/images/form_load_30x30.gif'}
    });
    
    Please note that the image URL should not have the slash character in the beginning.

Displaying a floating loading indicator

In some cases you may want to display a floating loading indicator, which looks like a yellow bar on the top of the screen:

The benefit of the floating loading indicator is that it allows a user to continue working without waiting while the request complete. In order to implement a floating indicator you need to disable the standard loading indicator, and use the request events to display a floating indicator:

$(this).getForm().sendPhpr('index_onSomeEvent', {
  loadIndicator: {show: false},
  onBeforePost: LightLoadingIndicator.show.pass('Loading...'), 
  onComplete: LightLoadingIndicator.hide
});

Updating page content

You can update the page content using the AJAX requests. LemonStand AJAX implementation allows to update a single element or multiple elements at at time.

Updating a single element

If you need to update a single element on a page, for example a DIV element with known identifier, you can use the following request:

$(this).getForm().sendPhpr('index_onSomeEvent', {
  update: 'some_element_id'
});

A value of the update parameter should be an identifier (the ID attribute) of a page element which you are going to update. On the server side you need to output HTML content you want to be displayed in the updatable element:

protected function index_onSomeEvent()
{
  echo "Hello!";
}

This request will output the "Hello!" text in the DIV element with "some_element_id" identifier. With partials you can output HTML content in more convenient way:

protected function index_onSomeEvent()
{
  $this->renderPartial('some_partial');
}

In this case all content of the 'some_partial' partial will be displayed on the page.

Updating multiple elements

It is possible to update multiple page elements with a single AJAX request. In this case you don't need to use the update parameter in the request initialization.

$(this).getForm().sendPhpr('index_onSomeEvent', {
});

Imagine that you have 3 DIV (or SPAN - it does not matter) elements with identifiers "tax", "subtotal" and "total". Then you can write the following code in the even handler:

protected function index_onSomeEvent()
{
  $this->renderMultiple(array(
    'tax'=>'10',
    'subtotal'=>'12',
    'total'=>'22'
  ));
}

You can also use partials instead of fixed values. In this case partial names should be prefixed with the @_ symbols:

protected function index_onSomeEvent()
{
  $this->renderMultiple(array(
    'tax'=>'@_my_tax_partial',
    'subtotal'=>'@_my_subtotal_partial',
    'total'=>'@_my_total_partial'
  ));
}

Sometimes it is more handy to output content separately, especially if you want to pass specific parameters to each partial. You can achieve the same result as in the previous example using the following code:

protected function index_onSomeEvent()
{
  $this->preparePartialRender('tax');
  $this->renderPartial('my_tax_partial');

  $this->preparePartialRender('subtotal');
  $this->renderPartial('my_subtotal_partial');

  $this->preparePartialRender('total');
  $this->renderPartial('my_total_partial');
}

Processing server errors

LemonStand AJAX implementation requires exceptions to be handled correctly in the server-side AJAX event handlers. Each AJAX event handler code, which could generate an exception, should be wrapped into the try..catch block. The catch block should contain the Phpr::$response->ajaxReportException() method call. Example:

protected function index_onSomeEvent()
{
  try
  {
    // Some code which could trigger an exception
    throw new Phpr_ApplicationException('Oops!');
  }
  catch (Exception $ex)
  {
    Phpr::$response->ajaxReportException($ex, true, true);
  }
}

By default errors occurred on the server are displayed above automatically generated forms. If there are no an automatically generated form on the page, the error will not be displayed. You can display errors by handling the onError request event:

$(this).getForm().sendPhpr('index_onSomeEvent', {
  onFailure: popupAjaxError
});

The popupAjaxError() function is declared in the LemonStand JavaScript framework. It loads the error message received from server and displays a standard alert popup window.

You can also perform extra actions, after displaying an error message, using the onAfterError event handler:

$(this).getForm().sendPhpr('index_onSomeEvent', {
  onFailure: popupAjaxError,
  onAfterError: function() {
    //
    // Do something here
    // 
  }
});

AJAX buttons

Besides the link buttons described in the Standard page elements article you can create buttons which trigger an AJAX request when user clicks them. To create an AJAX button use the following code:

<?= backend_ajax_button('Delete', 'index_onSomeAction') ?>

The backend_ajax_button() function can accept 4 parameters:

  • Button title text
  • An AJAX event handler name
  • A list of HTML attributes to apply to the button element. The most common usage is setting the right CSS class for moving a button to the right side of a form:
    <?= backend_ajax_button('Delete', 'index_onSomeAction', array('class'=>"right")) ?>
  • A list of AJAX request configuration parameters, as a single string. If you need to use quote marks inside the parameter value, use apostrophes. For example:
    <?= backend_ajax_button('Delete', 'edit_onDelete', array('class'=>"right"), 
      "confirm: 'Do you really want to delete this order?'") ?>

Next: Lists and Forms in the Administration Area
Previous: Extending the Administration Area menu
Return to Adding a Back-End User Interface