Using AJAX

Yii2 provides appropriate attributes for some widgets to make AJAX calls; sometimes, however, writing a JavaScript code in these attributes will make code hard to read, especially if we are dealing with complex codes.

Consequently, to make an AJAX call, we will use external JavaScript code executed by registerJs().

This is a template of the AJAX class using the GET or POST method:

<?php
$this->registerJs( <<< EOT_JS
     
     // using GET method
$.get({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});

     // using POST method
$.post({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});

EOT_JS
);
?>

An AJAX call is usually the effect of a user interface event (such as a click on a button, a link, and so on). So, most of the time an AJAX call is directly connected to the .on() event of jQuery on the HTML elements (anchors, buttons, and so on). For this reason, it is important to remember how Yii2 renders the name and id attributes of input fields.

When we call Html::activeTextInput($model, $attribute) or in the same way use <?= $form->field($model, $attribute)->textInput() ?>.

The name and id attributes of the input text field will be rendered as follows:

  • id : The model class name separated with a dash by the attribute name in lowercase; for example, if the model class name is Room and the attribute is floor, the id attribute will be room-floor
  • name: The model class name that encloses the attribute name, for example, if the model class name is Reservation and the attribute is price_per_day, the name attribute will be Reservation[price_per_day]; so every field owned by the Reservation model will be enclosed all in a single array

Example – reservation details loaded from the customers' drop-down lists

In this example, there are two drop-down lists and a detail box. The two drop-down lists refer to customers and reservations; when user clicks on a customer list item, the second drop-down list of reservations will be filled out according to their choice.

Finally, when a user clicks on a reservation list item, a details box will be filled out with data about the selected reservation.

Create a new action in basic/controllers/ReservationsController.php named actionDetailDependentDropdown():

    public function actionDetailDependentDropdown()
    {
        $showDetail = false;
        
        $model = new Reservation();
        
        if(isset($_POST['Reservation']))
        {
          $model->load( Yii::$app->request->post() );
        
          if(isset($_POST['Reservation']['id'])&&($_POST['Reservation']['id']!=null))
            {
               $model = Reservation::findOne($_POST['Reservation']['id']);
               $showDetail = true;
            }
        }
        
        
        return $this->render('detailDependentDropdown', [ 'model' => $model, 'showDetail' => $showDetail ]);
    }

In this action, we will get the customer_id and id parameters from a form based on the Reservation model data and if it are filled out, the data will be used to search for the correct reservation model to be passed to the view.

There is a flag called $showDetail that displays the reservation details content if the id attribute of the model is received.

In ReservationsController, there is also an action that will be called using AJAX when the user changes the customer selection in the drop-down list:

    public function actionAjaxDropDownListByCustomerId($customer_id)
    {
        $output = '';
        
        $items = Reservation::findAll(['customer_id' => $customer_id]);
        foreach($items as $item)
        {
            $content = sprintf('reservation #%s at %s', $item->id, date('Y-m-d H:i:s', strtotime($item->reservation_date)));
            $output .= yiihelpersHtml::tag('option', $content, ['value' => $item->id]);
        }
        
        return $output;
    }

This action will return the <option> HTML tags filled out with reservations data filtered by the customer ID passed as a parameter.

Now let's look at the view in basic/views/reservations/detailDependentDropdown.php:

<?php
use yiihelpersHtml;
use yiiwidgetsActiveForm;
use yiihelpersArrayHelper;
use yiihelpersUrl;
use appmodelsCustomer;
use appmodelsReservation;

$urlReservationsByCustomer = Url::to(['reservations/ajax-drop-down-list-by-customer-id']);
$this->registerJs( <<< EOT_JS

    $(document).on('change', '#reservation-customer_id', function(ev) {

        $('#detail').hide(); 
                
        var customerId = $(this).val();    
        
        $.get(
            '{$urlReservationsByCustomer}',
            { 'customer_id' : customerId },
            function(data) {
                data = '<option value="">--- choose</option>'+data;
                $('#reservation-id').html(data);
            }
        )
        ev.preventDefault();
    });

    $(document).on('change', '#reservation-id', function(ev) {
        $(this).parents('form').submit();
        ev.preventDefault();
    });

EOT_JS
);

?>

<div class="customer-form">
    <?php $form = ActiveForm::begin(['enableAjaxValidation' => false, 'enableClientValidation' => false, 'options' => ['data-pjax' => '']]); ?>

    <?php $customers = Customer::find()->all(); ?>
    <?= $form->field($model, 'customer_id')->dropDownList(ArrayHelper::map( $customers, 'id', 'nameAndSurname'), [ 'prompt' => '--- choose' ]) ?>

    <?php $reservations = Reservation::findAll(['customer_id' => $model->customer_id]); ?>
    <?= $form->field($model, 'id')->label('Reservation ID')->dropDownList(ArrayHelper::map( $reservations, 'id', function($temp, $defaultValue) {
      $content = sprintf('reservation #%s at %s', $temp->id, date('Y-m-d H:i:s', strtotime($temp->reservation_date)));
        return $content;
    }), [ 'prompt' => '--- choose' ]); ?>

    <div id="detail">
    <?php if($showDetail) { ?>
        <hr />
        <h2>Reservation Detail:</h2>
        <table>
            <tr>
                <td>Price per day</td>
                <td><?php echo $model->price_per_day ?></td>
            </tr>
        </table>
    <?php } ?>
    </div>
    
    <?php ActiveForm::end(); ?>

</div>

At the top of the view, there are handlers for changes in the customers and reservations drop-down list.

If the customer drop-down list is changed, the detail div will be hidden, an AJAX call will get all the reservations filtered by customer_id, and the result will be passed as content to the reservations drop-down list. If the reservations drop-down list is changed, a form will be submitted.

Next in the form declaration, we can find first of all the customer drop-down list and then the reservations list, which uses a closure to get the value from the ArrayHelper::map() methods. We could add a new property in the Reservation model by creating a function starting with the prefix get, such as getDescription(), and put in it the content of the closure, or rather:

public function getDescription()
{
$content = sprintf('reservation #%s at %s', $this>id, date('Y-m-d H:i:s', strtotime($this>reservation_date)));
            return $content;
}

Or we could use a short syntax to get data from ArrayHelper::map() in this way:

    <?= $form->field($model, 'id')->dropDownList(ArrayHelper::map( $reservations, 'id', 'description'), [ 'prompt' => '--- choose' ]); ?>

Finally, if $showDetail is flagged, a simple details box with only the price per day of the reservation will be displayed.

Point your browser to http://hostname/basic/web/reservations/detail-dependent-dropdown:

Example – reservation details loaded from the customers' drop-down lists

Dynamic reservation details being loaded from the customer drop-down list

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.111.92