Yii framework: dropDownList onchange not working - yii2

I have resource regarding dropDownList onchange event, but when I select my dropdownlist that is nothing happen and dint show any error message.
This is my dropdownlist in view:
<?= $form->field($model, 'pro_id')
->dropDownList($pro_option, // options
['prompt'=>'...'] , // options
['onchange' => '$.post("'.Yii::$app->urlManager->createUrl(["transaction/price"]).'"+$(this).val(), function( data ) {
$("#transactionform-r_price").html( data );
})']);?>
<?= $form->field($model, 'r_price')->textInput(['readonly' => true]) ?>
This is my controller(TransactionController.php) actionPrice:
public function actionPrice($id)
{
$price = 123;
return $price;
}

Please correct your syntax like this.
<?= $form->field($model, 'pro_id')->dropDownList($pro_option, [
'prompt' => '---Select Value---',
'onchange'=>'$.get( "'.Url::toRoute(['transaction/price']).'", { id : $(this).val() })
.done(function(data) {
$( "#'.Html::getInputId($model, 'r_price').'").html(data);
});'
]) ?>

Related

yii2: js calulation in server side

This is a page for calculate the product order.
My mentor told me that:
"The code put the code calculation logic inside JavaScript which means, user can simply inject and modified the content and get discount to make it safe, may either do a recalculation on submit at server side before display, or make the js function to call API, and return the result instead of put calculation logic inside JS"
But I really can't get it, how can I make it in server side?
views:
<?php $form = ActiveForm::begin([
'action'=>['summary'],
'id'=>'order-form',
]); ?>
<?= Html::dropDownList('country', null,['malaysia'=>'Malaysia','singapore'=>'Singapore', 'brunei'=>'Brunei'],['id'=>'country']) ?>
<?= Html::textInput('code','',['class'=>'form-control','placeholder'=>'promotion code','id'=>'code', 'style'=>'text-transform:uppercase'])?>
<?= Html::button('Apply', ['class' => 'btn btn-primary', 'id'=>'apply']) ?>
<?= Html::hiddenInput('id', $model->id) ?>
<?= Html::hiddenInput('discount', '', ['id'=>'discount']) ?>
<?= Html::hiddenInput('ship','',['id'=>'ship']) ?>
<?= Html::hiddenInput('qty', $qty, ['id'=>'qty']) ?>
<?= Html::hiddenInput('subtotal', $subtotal, ['id'=>'subtotal']) ?>
<?= Html::submitButton('Checkout', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end(); ?>
js:
$(document).ready(function() {
var qty=$('#qty').val();
var subtotal=$('#subtotal').val();
$('#discount').val(0);
$("#apply").click(function() {
var code=$('#code').val().toUpperCase();
var off5=(subtotal*0.05).toFixed(2);
var off15=15;
if(code=='OFF5PC'){
if (qty>=2)
$('#discount').val(off5);
else{
$('#discount').val(0);
alert('At least 2 quantities');
}
}
else if(code=='GIVEME15'){
if(subtotal>=100)
$('#discount').val(off15);
else{
$('#discount').val(0);
alert('Minumum puchase of RM100');
}
}
else{
$('#discount').val(0);
alert('Invalid promotion code');
}
if ($('#discount').val()=='0'){
$('#code').val('');
}
});
if(qty>=2||subtotal>=150){
$('#ship').val(0);
$('#shipping').html('0');
}
else{
$('#ship').val(10);
$('#shipping').html('10');
}
$("#country").change(function() {
var country=$('#country').val();
if(country=='malaysia'){
if(qty>=2||subtotal>=150){
$('#ship').val(0);
$('#shipping').html('0');
}
else{
$('#ship').val(10);
$('#shipping').html('10');
}
}
else if(country=='singapore'){
if(subtotal>=300){
$('#ship').val(0);
$('#shipping').html('0');
}
else{
$('#ship').val(20);
$('#shipping').html('20');
}
}
else if(country=='brunei') {
if(subtotal>=300){
$('#ship').val(0);
$('#shipping').html('0');
}
else{
$('#ship').val(25);
$('#shipping').html('25');
}
}
});
});
controllers:
public function actionSummary()
{
$id=Yii::$app->request->post('id');
$qty=Yii::$app->request->post('qty');
$discount=Yii::$app->request->post('discount');
$shipping=Yii::$app->request->post('ship');
$subtotal=Yii::$app->request->post('subtotal');
$area=Yii::$app->request->post('country');
$code=Yii::$app->request->post('code');
$summary=Products::findOne($id);
return $this->render('summary', [
'model' => $summary,
'quantity'=>$qty,
'discount'=>$discount,
'shipping'=>$shipping,
'subtotal'=>$subtotal,
'area'=>$area,
'code'=>$code,
]);
}
use browser tools inspect to determine your id of each fields. Usually the default id in Yii2 begins with view_name combine with "-" and field name.
For validating the form onsubmit, you can enable ajaxvalidation in your form like below.
View:
<?php $form = ActiveForm::begin([
'action'=>['summary'],
'enableAjaxValidation' => true,
'id'=>'order-form',
]); ?>
<?= $form->field($model, 'country')->dropDownList(['malaysia'=>'Malaysia','singapore'=>'Singapore', 'brunei'=>'Brunei']) ?>
<?= $form->field($model, 'code', ['options' => ['class' => 'form-control', 'id'=>'code']])->textInput(['placeholder'=>'promotion code'])?>
<?= Html::button('Apply', ['class' => 'btn btn-primary', 'id'=>'apply']) ?>
<?= Html::hiddenInput('id', $model->id) ?>
<?= Html::hiddenInput('discount', '', ['id'=>'discount']) ?>
<?= Html::hiddenInput('ship','',['id'=>'ship']) ?>
<?= Html::hiddenInput('qty', $qty, ['id'=>'qty']) ?>
<?= Html::hiddenInput('subtotal', $subtotal, ['id'=>'subtotal']) ?>
<?= Html::submitButton('Checkout', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end(); ?>
In your controller file, please add the ajax validation code in your controller before inserting into database. Below is the example ajax validation code for validating from server side.
Controller:
public function actionYourActionName(){
$model = new YourModelClass();
if ($model->load(Yii::$app->request->post())) {
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = yii\web\Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
if($model->save())){
//after successful save if you want to do any thing those codes will goes here.
}
}
return $this->render('your-view-file-name', ['model' => $model]);
}
Model:
<?php
namespace app\models;
use yii;
use yii\db\ActiveRecord;
class YourModelClass extends ActiveRecord
{
...
public function rules(){
return [
[['id', 'discount', 'ship', 'qty', 'subtotal'], 'safe'],
[['country', 'code'], 'required']
];
...
}
?>

check a specific submit button value in controller (Yii2)

how to check a submit button value in controller (Yii2). I am working with multiple submit button.
I tried simple php code. but it is not working.
if(isset($_POST['next']) && $_POST['next']=='gotocartfive')
code in view is :
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'status')->checkbox(); ?>
</div>
<div class="form-group">
<?php echo Html::submitButton('NEXT',array('value'=>'gotocartfive','name' => 'next','id'=>'next_summary','class'=>'btn btn-primary pull-right')); ?>
<?php echo Html::submitButton('PREVIOUS',array('value'=>'previous_four','name' => 'cartfour','class'=>'btn btn-primary pull-left')); ?>
</div>
<?php ActiveForm::end(); ?>
<?= Html::submitButton('Submit 1', ['name' => 'action', 'value' => 'submit_1']) ?>
<?= Html::submitButton('Submit 2', ['name' => 'action', 'value' => 'submit_2']) ?>
PHP
If (\Yii::$app->request->isPost) {
switch (\Yii::$app->request->post('action')) {
case 'submit_1':
case 'submit_2':
}
}
When you submit form by pressing enter (without click any submit button), submit_1 will be default value.
You can try following code.
Code in view file.
<?= Html::submitButton(Yii::t('app', '<i class="fa fa-times"></i> Remove'), ['class' => 'btn red', 'name' => 'submit', 'value' => '0']) ?>
<?= Html::submitButton(Yii::t('app', '<i class="fa fa-check"></i> Save'), ['class' => 'btn blue', 'name' => 'submit', 'value' => '1']) ?>
Code in controller action
if (Yii::$app->request->post()) {
if (Yii::$app->request->post('submit') == 0) {
//Code for value 0
}
if (Yii::$app->request->post('submit') == 1) {
//Code for value 1
}
}
Please let me know if you've any questions.
Try This :
View File
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'status')->checkbox(); ?>
<div class="form-group">
<?= Html::submitButton('NEXT',[ 'name'=>'submit', 'value' => 'next', 'class' => 'btn btn-primary pull-right']) ?>
<?= Html::submitButton('PREVIOUS',[ 'name'=>'submit', 'value' => 'previous', 'class' => 'btn btn-primary pull-right') ?>
</div>
<?php ActiveForm::end(); ?>
Controller File
public function actionYourControllerName()
{
if(isset($_POST['submit') && $_POST['submit']=='next')
{
// your code
}
else if(isset($_POST['submit']) && $_POST['submit']=='previous')
{
// your code
}
}
Also you can add this little js snippet to your project and bind it to beforeSubmit event in yii.activeForm.js like this:
(function ($) {
var formId = !!yiiconfig.viewPolicyParams && yiiconfig.viewPolicyParams.formId && yiiconfig.viewPolicyParams.formId,
$form = formId && $("#" + formId);
/**
* Updates hidden field that represents clicked submit button.
* #param event event object triggered
*/
function updateHiddenButton (event) {
var $buttons = $form.find(':submit');
$buttons.length && $buttons.each(function (i,b) {
var $hiddenButton = $('input[type="hidden"][name="' + $(b).attr('name') + '"]', $form);
$hiddenButton.length && $hiddenButton.remove();
});
};
$form && $form.bind('beforeSubmit.' + formId, updateHiddenButton);
} (jQuery));
This code removes all hidden inputs which are being created by yii.activeForm before submitting.
Then after this inputs will be recreated by yii.activeForm.
hope this helps

Yii2 Pjax not working

I want to refresh the gridview using Pjax but somehow it is not working. Here is the code:
_search.php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\widgets\Pjax;
$this->registerJs("
$('#btnAjaxSearch').click(function(){
$.ajax({
type: 'get',
data: $('.bank-search form').serializeArray(),
success: function (data) {
$.pjax.reload({container:\"#bank\"});
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('error');
}
});
return false;
});
", \yii\web\View::POS_END, 'bank-search');
?>
<div class="bank-search">
<?php Pjax::begin(['id' => 'bank-form']); ?>
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'bank_name') ?>
<?= $form->field($model, 'state') ?>
<?= $form->field($model, 'district') ?>
<?= $form->field($model, 'city') ?>
<div class="form-group">
<?= Html::Button('Search', ['class' => 'btn btn-primary','id' => 'btnAjaxSearch']) ?>
</div>
<?php ActiveForm::end(); ?>
<?php Pjax::end(); ?>
</div>
index.php
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use yii\widgets\Pjax;
$this->title = 'Banks';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="bank-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php echo $this->render('_search', ['model' => $searchModel]); ?>
<p>
<?= Html::a('Create Bank', ['create'], ['class' => 'btn btn-success']) ?>
</p>
<?php Pjax::begin(['id' => 'bank']); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'bank_name',
'state',
'district',
'city',
// 'branch',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
<?php Pjax::end(); ?>
</div>
Controller
/**
* Lists all Bank models.
* #return mixed
*/
public function actionIndex()
{
$searchModel = new BankSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
Simple search is working but Pjax is not. I am new to Yii2 so any help would be appreciated. Thank you.
Thanks Edin. It helped me to solved the problem. Here is what I did. It might help someone facing the same problem.
As Edin mentioned you need to pass the url along with the search parameters to the Pjax in order to refresh the gridview.
Here's my edited code :
$js = <<<JS
// get the form id and set the event
$('#bank-form-id').on('beforeSubmit', function(e) {
var form = $(this);
if(form.find('.has-error').length) {
return false;
}
$.ajax({
url: form.attr('action'),
type: 'post',
data: form.serialize(),
success: function(response) {
var csrf = yii.getCsrfToken();
var bank_name = $('#banksearch-bank_name').val();
var state = $('#banksearch-state').val();
var district = $('#banksearch-district').val();
var city = $('#banksearch-city').val();
var url = form.attr('action')+ '&_csrf='+csrf+'&BankSearch[bank_name]='+bank_name+'&BankSearch[state]='+state+'&BankSearch[district]='+district+'&BankSearch[city]='+city;
$.pjax.reload({url: url, container:'#bank'});
}
});
}).on('submit', function(e){
e.preventDefault();
});
JS;
$this->registerJs($js);
The way Pjax is working is by sending another request with special headers. When pjax request is detected only html required to update container is returned from server. Line
$.pjax.reload({container:\"#bank\"});
will send another request, and inside actionIndex queryParams will be empty.
You can solve this by storing search parameters to session or by specifing pjax url with parameters in query string.
Try following:
var url = urlWithFilters();
$.pjax({url: url, container: '#bank'});
In this case you don't need to create own ajax call, just create url with with filters.

Yii2 Gridview data not changing in Pjax

Hello i am performing search using pjax in yii2 . I am following this link.
Above link in given for submit which is working fine, but i want to perform on change of slider.
Here is screenshort of my form .
index.php
<div class="bank-index">
<?php echo $this->render('_search', ['model' => $searchModel]); ?>
<?php \yii\widgets\Pjax::begin(); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'bank_name',
'state',
'district',
'city',
'branch',
'time',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
_search.php
<div class="bank-search">
<?php Pjax::begin(['id' => 'Pjax_bank_id']); ?>
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'id') ?>
<?= $form->field($model, 'bank_name') ?>
<?= $form->field($model, 'state') ?>
<?= $form->field($model, 'district') ?>
<?= $form->field($model, 'city') ?>
<?=
$form->field($model, 'time')->widget(Slider::classname(), [
'pluginOptions'=>[
'min'=>0,
'max'=>20,
'step'=>1
]
]);
?>
<?php // echo $form->field($model, 'branch') ?>
<div class="form-group">
<?= Html::submitButton(Yii::t('app', 'Search'), ['class' => 'btn btn-primary']) ?>
<?= Html::resetButton(Yii::t('app', 'Reset'), ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
**How i have registered js file**
registerJs($this->render('searchJs.php')); ?>
searchJs.php
$('#banksearch-time').on('slideStop', function(){
alert('hello');
var form = $(this);
if(form.find('.has-error').length) {
return false;
}
$.ajax({
url: form.attr('action'),
type: 'post',
data: form.serialize(),
success: function(response) {
var csrf = yii.getCsrfToken();
var bank_name = $('#banksearch-bank_name').val();
var state = $('#banksearch-state').val();
var district = $('#banksearch-district').val();
var city = $('#banksearch-city').val();
var time = $('#banksearch-time').val();
var url = 'index'+ '&_csrf='+csrf+'&BankSearch[bank_name]='+bank_name+'&BankSearch[state]='+state+'&BankSearch[district]='+district
+'&BankSearch[city]='+city +'&BankSearch[time]='+time;
$.pjax.reload({url: url, container:'#Pjax_bank_id'});
}
});
}).on('submit', function(e){
e.preventDefault();
});
Solved The problem was I have not assigned the id to Pjax in gridview.<?php yii\widgets\Pjax::begin(['id' => 'gridresult']) ?>
I have assigned Pjax id of _search .php.
I changed From: $.pjax.reload({url: url, container:'#gridresult'});
TO: $.pjax.reload({url: url, container:'#gridresult'});
Good you solved the problem. Here is the another approach. Someone might find this helpful:
$url = \Yii::$app->getUrlManager()->createUrl('bank/index');
<?= $form->field($model, 'time')->widget(Slider::classname(), [
'pluginOptions'=>[
'min'=>0,
'max'=>20,
'step'=>1
],
'pluginEvents' => [
"slideStop" => "function() { refreshGridview($(this).val())}",
]
]); ?>
$js1 = <<<JS
function refreshGridview(value)
{
$.ajax({
url: "$url",
type: 'post',
data: { "BankSearch[id]": value, },
success: function(response) {
var csrf = yii.getCsrfToken();
var bank_id = value;
$.pjax.reload({
url: "$url",
method: 'POST',
data: {
_csrf: csrf,
"BankSearch[id]": value,
},
container:'#bank'
});
}
});
}
JS;
$this->registerJs($js1);
On slidestop plugin event call the custom function with the current value of slider and then through Pjax update the gridview.

dependent dropdown yii2. How to do?

can I create a dependent dropdown in yii2?
I have two tables:
'id','name_country"
'id','name_city','country_id'
and have two methods in my model:
public function getCountryList()
{
$models = NetCountry::find()->asArray()->all();
return ArrayHelper::map($models, 'id', 'country_name');
}
and
public function getCityList($parent_id) {
$models = \common\models\City::find()->where(['parent_id' => $country_id])->asArray()->all();
return ArrayHelper::map($models, 'id', 'name_city','country_id');
}
I have the first field:
<?= $form->field($model, 'country')->dropDownList($model->countryList),['id'=>'parent_id'];
and the second
<?= $form->field($model, 'city')->dropDownList($model->cityList);
I need to 'transmit' parent_id to controller and return city_list by AJAX (with JSON).
How can I do this? I saw an example in Yii1, but what about Yii2?
use the krajee extension for dependent drop down
Details is here Krejee dependent dropdown for yii2
or follow following instructions:
Install the extension via composer:
$ php composer.phar require kartik-v/dependent-dropdown "dev-master"
In your view :
use kartik\widgets\DepDrop;
// Normal parent select
echo $form->field($model, 'cat')->dropDownList($catList, ['id' => 'cat-id']);
// Dependent Dropdown
echo $form->field($model, 'subcat')->widget(DepDrop::classname(), [
'options' => ['id' => 'subcat-id'],
'pluginOptions' => [
'depends' => ['cat-id'],
'placeholder' => 'Select...',
'url' => Url::to(['/site/subcat'])
]
]);
// THE CONTROLLER
public function actionSubcat() {
$out = [];
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if ($parents != null) {
$cat_id = $parents[0];
$out = self::getSubCatList($cat_id);
// the getSubCatList function will query the database based on the
// cat_id and return an array like below:
// [
// ['id'=>'<sub-cat-id-1>', 'name'=>'<sub-cat-name1>'],
// ['id'=>'<sub-cat_id_2>', 'name'=>'<sub-cat-name2>']
// ]
echo Json::encode(['output'=>$out, 'selected'=>'']);
return;
}
}
echo Json::encode(['output'=>'', 'selected'=>'']);
}
creating dependent dropdown in yii2 without using any third party libraries is
quite as simple as yii1. you have to try following code written below as per your requirements.
use gii to create models,views, controller for respective tables.
suppose there r two table like country, city as u written.
then write the following code into views file for one controller(like country):
<?php
use yii\helpers\ArrayHelper;
use yii\widgets\ActiveForm;
?>
<div>
<?php
$dataCountry=ArrayHelper::map(\app\models\Country::find()->
asArray()->all(),'id', 'name');
$form = ActiveForm::begin();
echo $form->field($model, 'id')->dropDownList($dataCountry,
['prompt'=>'-Choose a Name-',
'class'=>'adjust',
'onchange'=>'
$.post("'.Yii::$app->urlManager->createUrl('city/lists?id=').
'"+$(this).val(),function( data )
{
$( "select#city" ).html( data );
});
']);
$dataPost=ArrayHelper::map(\app\models\City::find()->
asArray()->all(), 'id', 'city');
echo $form->field($model, 'id')
->dropDownList(
$dataPost,
['id'=>'city',
'class'=>'adjust'
]
);
ActiveForm::end();
?>
</div>
and after this in another controller for city write following code as:
<?php
namespace app\controllers;
class CityController extends \yii\web\Controller
{
public function actionLists($id)
{
//echo "<pre>";print_r($id);die;
$countPosts = \app\models\City::find()
->where(['country_id' => $id])
->count();
$posts = \app\models\City::find()
->where(['country_id' => $id])
->orderBy('id DESC')
->all();
if($countPosts>0){
foreach($posts as $post){
echo "<option value='".$post->id."'>".$post->city."</option>";
}
}
else{
echo "<option>-</option>";
}
}
}
then run into url it works!
edit: fixed url construction. http requests will now work.
You can do it without any widget manually:
make your activeform as follows:
<?= $form->field($model, 'nameofyourmodel')->dropDownList(
ArrayHelper::map(\app\models\nameofyourmodel::find()->all(), 'id', 'name'),
[
'prompt'=>'smth',
'onchange' => '
$.post(
"' . Url::toRoute('getoperations') . '",
{id: $(this).val()},
function(res){
$("#requester").html(res);
}
);
',
]
); ?>
and here the second form which receives the id from the first model:
<?= $form->field($model,'nameofyourmodel')->dropDownList(
[],
[
'prompt' => 'smth',
'id' => 'requester'
]
); ?>
and the last action is to make a functionality in controller to match 2 ids and send them to your model:
public function actionGetoperations()
{
if ($id = Yii::$app->request->post('id')) {
$operationPosts = \app\models\firstmodel::find()
->where(['id' => $id])
->count();
if ($operationPosts > 0) {
$operations = \app\models\secondmodel::find()
->where(['firstmodelid' => $id])
->all();
foreach ($operations as $operation)
echo "<option value='" . $operation->firstmodelid. "'>" . $operation->name . "</option>";
} else
echo "<option>-</option>";
}
}
The above code is not working properly. There is an error in the line
$.post("'.Yii::$app->urlManager->createUrl('city/lists&id=').'"+$(this).val(),function( data )
console shows the error :
Not Found (#404): Unable to resolve the request: subcategory/lists&id=54
is there any solution for this
my controller looks like below
public function actionLists($id)
{
$posts = SubCategory::find()
->where(['category_id' => $id])
->orderBy('id DESC')
->all();
if($posts){
foreach($posts as $post){
echo "<option value='".$post->id."'>".$post->name."</option>";
}
}
else{
echo "<option>-</option>";
}
}
when i remove the id from the url and hard coded it in to controller it works properly.
I have find a solution for this
please change your view as follows
<?= $form->field($model, 'category_id')->dropDownList($data,['prompt'=>'-Choose a Category-',
'onchange'=>'
$.get( "'.Url::toRoute('product/catlists').'", { id: $(this).val() } )
.done(function( data )
{
$( "select#product-sub_categoryid" ).html( data );
});
']); ?>
and controller like this
public function actionCatlists($id)
{
$mymodel = new Product ();
$size = $mymodel->modelGetCategory ( 'product_sub_category',$id );
if($size){
echo '<option value="">Choose Sub category</option>';
foreach($size as $post){
echo "<option value='".$post['id']."'>".$post['name']."</option>";
}
}
else{
echo '<option value="0">Not Specified</option>';
}
}
don't forget to include this on your view
use yii\helpers\Url;