This is an old revision of the document!
Yii 2 Using AJAX
Using JQuery AJAX
Create a view. This should include the JavaScript method to call AJAX, and a form control that calls the method somehow (eg. onchange
or click
events).
File /views/issue/create.php
:
<?php // Add Javascript code to perform AJAX call (using JQuery) $jsBlock = " function getCompany() { $.ajax({ // Controller method to call url: '" . Yii::$app->request->baseUrl. '/issue/get-company' . "', // Parameter data to pass in data: { account_number: $('#issue-account_number').val(), }, type: 'POST', cache: false, // Code to run if the request succeeds; // the response is passed to the function success: function(data) { // process data console.log('data: [' + data + ']'); $('#company_search_results').html(data); }, // Code to run if the request fails; // the raw request and status codes are passed to the function error: function( xhr, status, errorThrown ) { alert('Sorry, there was a problem! Error: ' + errorThrown + 'Status: ' + status + xhr); console.log('Error: ' + errorThrown ); console.log('Status: ' + status ); console.dir( xhr ); }, // Code to run regardless of success or failure complete: function( xhr, status ) { //alert('The request is complete!'); } }) .fail (function(){ alert('Error'); }); } "; // NOTE: $position can be: // View::POS_READY (the default) // View::POS_HEAD // View::POS_BEGIN // View::POS_END $position = \yii\web\View::POS_END; $this->registerJs($jsBlock, $position); ?> ... <div class="issue-form"> <?php $form = ActiveForm::begin(); ?> <!-- Field to grab parameter to pass to AJAX query --> <?= $form->field($model, 'account_number')->textInput([ 'maxlength' => true, 'onchange'=>'getCompany()' ]) ?> <p/> <!-- Box to display AJAX results --> <?= Html::tag('div', '...', ['id' => 'company_search_results']); ?> ... </div>
In controller, add action to handle query in OnChange
: File /controllers/IssueController.php
:
use app\models\Issue; use app\models\Customer; ... class IssueController extends Controller { ... public function actionGetCompany() { // Grab AJAX parameter from POST (since that is the method we used) if (Yii::$app->request->isPost){ $account_number = Yii::$app->request->post('account_number'); Yii::info('POST account_number: ' . $account_number, 'actionGetrec'); } // Validate and query the data we need if (empty($account_number)) { $modelCust = new Customer(); $account_number = $modelCust->account_number; $company_name = $modelCust->company_name; $arrCustomer = $modelCust->toArray(); Yii::info('Empty account_number: ' . $account_number . 'company_name: ' . $company_name, 'actionGetrec'); } else { $modelCust = Customer::find()->where(['account_number' => $account_number])->one(); $arrCustomer = Customer::find()->where(['account_number' => $account_number])->asArray()->one(); if(!empty($modelCust)) { $company_name = $modelCust->company_name; Yii::info('Found account_number: ' . $account_number . 'company_name: ' . $company_name, 'actionGetrec'); Yii::info('Customer record: ' . print_r($modelCust, true), 'actionGetrec'); } else { Yii::info('Customer not found: ' . $account_number, 'actionGetrec'); } } // Prepare data to send back $data = array(); if (!empty($arrCustomer['company_name'])) { $data[] = $arrCustomer['company_name']; } if (!empty($arrCustomer['address'])) { $data[] = $arrCustomer['address']; } if (!empty($arrCustomer['city'])) { $data[] = $arrCustomer['city']; } if (!empty($arrCustomer['state_prov'])) { $data[] = $arrCustomer['state_prov']; } if (!empty($arrCustomer['country'])) { $data[] = $arrCustomer['country']; } if (!empty($arrCustomer['phone'])) { $data[] = $arrCustomer['phone']; } if (!empty($arrCustomer['phone'])) { $data[] = $arrCustomer['phone']; } if (!empty($arrCustomer['email'])) { $data[] = $arrCustomer['email']; } // Send AJAX results if (count($data) > 0) { return '<div class="alert alert-success" role="alert">' . implode(', ', $data) . '</div>'; } else { return '<div class="alert alert-danger" role="alert">Customer record not found</div>'; } } }
Using JQuery $.get()
You can also get data without using AJAX by simply using this JQuery $.get()
method attached to an event (such as OnChange
event):
<?= $form->field($model, 'product_name')->dropDownList(ArrayHelper::map(Products::find()->all(), 'id', 'name'), ['prompt'=>'-Choose a Product-', 'onchange'=>' $.get( "index.php?r=suborders/listprice&id="+$(this).val(), function( data ) { $( "#suborders-product_price" ).val( data ); }); ']); ?>
Examples
Request the test.php page, but ignore the return results.
$.get( "test.php" );
Request the test.php page and send some additional data along (while still ignoring the return results).
$.get( "test.php", { name: "John", time: "2pm" } );
Pass arrays of data to the server (while still ignoring the return results).
$.get( "test.php", { "choices[]": ["Jon", "Susan"] } );
Alert the results from requesting test.php (HTML or XML, depending on what was returned).
$.get( "test.php", function( data ) { alert( "Data Loaded: " + data ); });
Alert the results from requesting test.cgi with an additional payload of data (HTML or XML, depending on what was returned).
$.get( "test.cgi", { name: "John", time: "2pm" } ) .done(function( data ) { alert( "Data Loaded: " + data ); });
Get the test.php page contents, which has been returned in json format (<?php echo json_encode( array( “name”⇒“John”,“time”⇒“2pm” ) ); ?>
), and add it to the page.
$.get( "test.php", function( data ) { $( "body" ) .append( "Name: " + data.name ) // John .append( "Time: " + data.time ); // 2pm }, "json" );
See more:
Using AJAX Returning JSON
Add HTML elements that will be updated with AJAX, and attach the AJAX functionality to an event, such as the click
event. Eg: The view index
for the SiteController
(file [app]/views/site/index.php
):
<h2>Quote of the day</h2> <div id="quote-of-the-day"> Click to get random quote </div> <div id="quote-number-2"> Click to get quote ID 2 </div> <div id="quote-error"> Click to get quote that does not exist </div> ... <?php // Javascript code block to handle AJAX requests $jsBlock = <<< JS // get without 'query' = random quote $('#quote-of-the-day').click(function(){ $.ajax({ //url: '?r=professional/quote', // using standard routing url: 'quote', // using PrettyUrl routing dataType: "json", success: function(data) { if(data.error) { alert(data.error); } else if(data.quote) { $("#quote-of-the-day").html(data.quote); } else { $("#quote-of-the-day").html("Response in invalid format!"); alert("Response in invalid format!"); } } }) }); // get with ID 2 $('#quote-number-2').click(function(){ $.ajax({ //url: '?r=professional/quote&query=2', // using standard routing url: 'quote/?query=2', // using PrettyUrl routing dataType: "json", success: function(data) { if(data.error) { alert(data.error); } else if(data.quote) { $("#quote-number-2").html(data.quote); } else { $("#quote-number-2").html("Response in invalid format!"); alert("Response in invalid format!"); } } }) }); // get with ID 5 - does not exist $('#quote-error').click(function(){ $.ajax({ //url: '?r=professional/quote&query=5', // using standard routing url: 'quote/?query=5', // using PrettyUrl routing dataType: "json", success: function(data) { if(data.error) { alert(data.error); } else if(data.quote) { $("#quote-error").html(data.quote); } else { $("#quote-error").html("Response in invalid format!"); alert("Response in invalid format!"); } } }) }); JS; // NOTE: $position can be: // View::POS_READY (the default) // View::POS_HEAD // View::POS_BEGIN // View::POS_END $position = \yii\web\View::POS_END; $this->registerJs($jsBlock, $position); ?>
In the controller, add an action to handle the AJAX request. Eg: In the SiteController
we would add action quote
(file [app]/controllers/SiteController.php
):
<?php ... class SiteController extends Controller { ... // to show random quote open: index.php?r=mycontroller/quote // to show quote with ID 2: index.php?r=mycontroller/quote&query=2 // to show error: index.php?r=mycontroller/quote&query=5 public function actionQuote() { // some parameter from JS // ex. 127.0.0.1/?r=my-controller/quote&query=3 // $queryTerm = 3; $queryTerm = Yii::$app->request->get('query'); Yii::$app->response->format = 'json'; //$quotes = ['one', 'two', 'three']; $quotes = [ ['Walking on water and developing software from a specification are easy if both are frozen.', 'Edward V Berard'], ['It always takes longer than you expect, even when you take into account Hofstadter’s Law.', 'Hofstadter’s Law'], ['Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.', 'Rick Osborne'], ['I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone.', 'Bjarne Stroustrup'], ['Java is to JavaScript what Car is to Carpet.', 'Chris Heilmann'] ]; if($queryTerm !== null) { // some parameter specified if(isset($quotes[$queryTerm])) { // quote exists, show it return ['quote' => $quotes[$queryTerm]]; } else { // quote with specified ID does not exist return ['error' => 'Quote with this ID does not exist.']; } } else { // no parameter - show random if(count($quotes) > 0) { // we got some quotes, we can random return ['quote' => $quotes[rand(0, count($quotes)-1)]]; } else { // we got zero quotes, error return ['error' => 'Zero quotes in database. Cannot show random quote.']; } } } ... } ?>
Source: http://www.yiiframework.com/forum/index.php/topic/54820-yii2-ajax-howto/
References:
Using PJAX (instead of AJAX)
In the view, add a Pjax block where dynamic value is going to display. Eg: For the 'Create Issue' view in [app]/views/issue/create.php
:
use yii\widgets\Pjax; ... <div class="col-sm-12 col-md-6"> <?php Pjax::begin(); ?> <?= Html::a("Generate Random String", ['issue/create'], ['class' => 'btn btn-lg btn-primary']) ?> <h3><?= $randomString ?></h3> <?php Pjax::end(); ?> </div> <div class="col-sm-12 col-md-6"> <?php Pjax::begin(); ?> <?= Html::a("Generate Random Key", ['issue/create'], ['class' => 'btn btn-lg btn-primary']) ?> <h3><?= $randomKey ?><h3> <?php Pjax::end(); ?> </div>
In the controller, create the variables references in the view. Eg: For the 'Create Issue' view, we add this to the actionCreate()
in [app]/controllers/IssueController.php
:
public function actionCreate() { $randomString = strtotime("now"); $randomKey = strtotime("now"); $model = new Issue(); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } else { return $this->render('create', [ 'model' => $model, 'randomString' => $randomString, 'randomKey' => $randomKey, ]); } }
Another example, pointing to different actions. Eg: File views\site\time-date.php
use yii\widgets\Pjax; use yii\helpers\Html; ... <?php Pjax::begin(); ?> <?= Html::a("Show Time", ['site/time'], ['class' => 'btn btn-lg btn-primary']) ?> <?= Html::a("Show Date", ['site/date'], ['class' => 'btn btn-lg btn-success']) ?> <h1>It's: <?= $response ?></h1> <?php Pjax::end(); ?>
File controllers\SiteController.php
public function actionTime() { return $this->render('time-date', ['response' => date('H:i:s')]); } public function actionDate() { return $this->render('time-date', ['response' => date('Y-M-d')]); }