Update form after ajax save - yii2

I want form data updated after ajax save. Cause if item was new (id - empty), it tries to create new one each time. Also there are back-end generated fields which are appears after save.
<?php $form = ActiveForm::begin([
'method' => 'post',
'action' => ['category/save', 'id' => $category ? $category->id : ''],
'enableClientValidation' => true,
// 'enableAjaxValidation' => false,
'validateOnChange' => false,
'validateOnBlur' => false,
'validateOnSubmit' => true,
'options' => [
'id' => 'customer-update',
'class' => 'ajax-submit',
],
'fieldConfig' => [
'template' => '<div class="row-content-col1">{label}</div><div class="row-content-col2">{input}{error}</div>'
]
]); ?>
.......
<?php echo $form->field($category, 'url')->textInput(['class' => 'ip', 'readonly' => true]); ?>
......
<?php $form->end(); ?>
Form field produce such html:
<div class="row-content-col1"><label class="control-label" for="category-url">Url</label></div><div class="row-content-col2"><input type="text" id="category-url" class="ip" name="Category[url]" readonly><div class="help-block"></div></div>
</div>
And than on controller i return this (tried different variations):
{"error":false,"message":"Category 'asdfzsdf sdf' saved","data":{"name":"asdfzsdf sdf","url":"asdfzsdf-sdf","project_id":1,"id":21}}
What is valid response for ajax form? Or is there other way to handle this all ?

Pjax is really useful for your challenge, Just add your form inside of Pjax widget. add form action to new path(such: site/control-data).
In your action method do what you want, but send response like that :
return $this->renderAjax('form path',$model);
It's the general of what you must do.
But maybe you have problem with jquery or pjax or need some more data, but all questions have an answer,
See Pjax for ActiveForm

Related

How to pass parameter from controller to another view (a form) inside a view

This is my actionIndex() in my controller.
public function actionIndex()
{
$featured= new ActiveDataProvider([
'query'=>News::find()
->where(['not', ['featuredOrder' => null]])
->orderBy('featuredOrder'),
]);
$checkList=Featured::find()
->joinWith('news')
->where(['news.featuredOrder'=>null])
->orderBy('featuredOrder')
->all();
return $this->render('index', [
'dataProvider' => $featured,
'checkList'=>$checkList,
]);
I have a listview in my index view which is rendered by this controller. If an item of the listview is clicked, it will display the detailView of each item, along with the update button to update the item's data which will generate a form to update. I need to pass the $checklist to this form. Later I'll use this $checklist to populate a drop-down list. I wonder how to pass the parameter. I could just move this part to the form view, but I think it's not a good practice to have this inside a view.
$checkList=Featured::find()
->joinWith('news')
->where(['news.featuredOrder'=>null])
->orderBy('featuredOrder')
->all();
This is my index :
<?php echo \yii\widgets\ListView::widget([
'dataProvider' => $featured,
'itemView'=>'_post',
'options'=>['class'=>'row'],
'itemOptions'=>['class'=>'col-md-4'],
'summary'=>'',
'viewParams'=>['cekList'=>'cekList'],
'pager' => [
'options'=>['class'=>'pagination justify-content-center'],
'linkContainerOptions'=>['class'=>'page-item'],
'linkOptions'=>['class'=>'page-link'],
_post view
div class = "panel panel-default">
<div class = "panel-body">
<h2 class="truncate text-center"><?=Html::a($model->title, ['view', 'id' => $model->id] ) ?> </h2>
<hr>
</div>
<!-- another block of code, but unrelated, so I won't include it -->
This is the view.php file,being rendered if an item's title in the _post above is clicked.
<div class="row justify-content-between">
<div class="col-xs-6">
<?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
<?= Html::a('Delete', ['delete', 'id' => $model->id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => 'Do you want to delete this post?',
'method' => 'post',
],
]) ?>
If an update button is clicked, it will render a form. I want to pass the param to this form.
My Answer is Based On this Query :
$checkList=Featured::find()
->joinWith('news')
->where(['news.featuredOrder'=>null])
->orderBy('featuredOrder')
->all();
If you want to use only above query for drop down there is a two way to do that :
1. Create A method in controller and use array helper method for drop down list add select statement in query
public function checklistDropdown(){
$items = Featured::find()
->joinWith('news')
->where(['news.featuredOrder'=>null])
->orderBy('featuredOrder')
->all();
$items = ArrayHelper::map($items, 'id', 'name');
}
In your index action call this method pass just like you passed model and dataprovider
2. second option is more feasible i think
Create a component helper for generic drop down list add above method in that component and use that component to call the method in you view , you can define that method as STATIC . It will be reusable.

Yii2 : I Can't type anything if select2 in modal

I'm using Kartik Select2 Widget ... but the problem is I can't type anything in the search.
I used this code:
`<?= Html::button('حجز موعد ', ['value'=>URL::to('index?r=event/create'), 'class' => 'btn btn-warning btn-block btn-flat','id'=>'creates']) ?>
<?php
Modal::begin([
'options' => [
'id' => 'kartik-modal',
'tabindex' => false
],
]);
modal::end();
?>`
JS Code:
`$(function(){
$(document).on('click','#creates',function(){
var date = new Date().toJSON().slice(0,10);
$.get('?r=event/create',{'date':date},function(data){
$('#modal').modal('show')
.find('#kartik-modal')
.html(data);
});
});
});`
my problem is : the text disabled
If not in modal it works fine !

Getting label with colon for model's field in a form

I need to have Body: (with colon at the end), not Body rendered as label for each field in my form. How can I achieve this the best way?
I tried modifying fieldConfig => template in ActiveForm::begin by adding div class=\"\">{label}:</div> into it:
<?php $form = ActiveForm::begin([
'id' => 'edit-form',
'options' => ['class' => 'form-horizontal'],
'fieldConfig' => [
'template' => "<div class=\"\">{label}:</div>\n<div class=\"\">{input}</div>\n<div class=\"\">{error}</div>",
'labelOptions' => ['class' => 'edit-label'],
]]); ?>
but it is wrong. Colon is rendered as separate DOM element, with incorrect styling and looks ugly.
I tried doing this awfully in CSS:
.edit-label::after {
content: ":";
}
but this is even worse.
I remember, that I made a lot of stupid things in Yii1 to get this. I don't want to repeat these stupid things, when implementing this in Yii2. What is the best way of achieving this?
When using Bootstrap 3 (yii\bootstrap\ActiveField) you can use additional placeholders in the $template and you need to replace {label} with {beginLabel}{labelTitle}:{endLabel}:
<?php $form = ActiveForm::begin([
'id' => 'edit-form',
'options' => [
'class' => 'form-horizontal',
'enctype'=>'multipart/form-data'
],
'fieldConfig' => [
'template' => "<div class=\"\">{beginLabel}{labelTitle}:{endLabel}</div>\n<div class=\"\">{input}</div>\n<div class=\"\">{error}</div>",
'labelOptions' => ['class' => 'edit-label'],
],
]); ?>
I don't know, how to solve this problem, if you're using basic yii\widgets\ActiveField instead.

CakePHP onChange event

I have no idea why this onChange event is not working. Maybe I got so used to the code that I can't see my mistake. I'd appreciate your help:
<td class="cellInput">
<?php
$options = array('200'=>'200', '500'=>'500', '1000'=>'1000', '2000'=>'2000', '5000'=>'5000', 'Outro'=>'Outro');
$attributes = array('legend' => false);
echo $form->select('capacidade', $options, array(
'class' => '',
'label' => '',
'default' => '200',
'onchange' => "javascript:checkForOther(this);",
));
?>
</td>
As others suggested, place the attributes in the correct parameter position. The other thing i would do is remove the javascript and just have the function name in there like:
From: 'onchange' => "javascript:checkForOther(this);"
To: 'onchange' => "checkForOther(this)"
Try
Putting the attributes as the fourth argument instead of the third:
echo $form->select('capacidade', $options, null,
array(
'class'=>''
,'label' => ''
,'default' => '200'
,'onchange' => "javascript:checkForOther(this);"
)
);
Does the source of the generated page have the onChange attribute?
See the documentation
According to CakePHP documentation on select method, the third argument is used to choose which option is selected by default.
You must use the fourth argument to pass HTML attributes to a select element:
<td class="cellInput">
<?php
$options = array('200'=>'200', '500'=>'500', '1000'=>'1000', '2000'=>'2000', '5000'=>'5000', 'Outro'=>'Outro');
$attributes = array('legend'=>false);
echo $form->select('capacidade', $options, '200', array('class'=> '', 'label' => '', 'onchange' => "checkForOther(this);"));
?>
</td>

Zend subform view script render

I would rather not deal with decorators as my form design is not exactly straight forward, but i would like to keep the functionality of validating the forms.
So i have it set up where sub forms are working correctly, but when i try to style it manually in my viewscript i get the name without the parent. I've seen other posts that are similar, but i haven't found a solution.
Example:
This is in my view script
<?php echo $this->form->username->renderViewHelper();?>
I then get
<input type="text" value="" id="username" name="username">
When rendered. It should be
<input type="text" value="" id="form1-username" name="form1[username]">
How do i get that form1 portion?
Thanks!
Edit
Ok, so i found one way.
By using belongTo, it works:
$form1->addElements(array(
new Zend_Form_Element_Text('username', array(
'belongsTo' => 'form1',
'required' => true,
'label' => 'Username:',
'filters' => array('StringTrim', 'StringToLower'),
'validators' => array(
'Alnum',
array('Regex',
false,
array('/^[a-z][a-z0-9]{2,}$/'))
)
))
));
Is there a better way to do this or is this the only way?
Edit2
public function prepareSubForm($spec){
if (is_string($spec)) {
$subForm = $this->{$spec};
} elseif ($spec instanceof Zend_Form_SubForm) {
$subForm = $spec;
} else {
throw new Exception('Invalid argument passed to ' .
__FUNCTION__ . '()');
}
$this->setSubFormDecorators($subForm)
->addSubmitButton($subForm)
->addSubFormActions($subForm);
return $subForm;
}
public function setSubFormDecorators(Zend_Form_SubForm $subForm){
$subForm->setDecorators(array(
'FormElements', \\<--- I tried to change this to PrepareElements before.
array('HtmlTag', array('tag' => 'dl',
'class' => 'zend_form')),
'Form',
));
return $this;
}
I believe you can get your desired output just by using:
<?php echo $this->form->username; ?>
I get the expected output when calling this without renderViewHelper. This is also without any special code for decorators or preparing sub forms. All I had to do was add belongsTo to the form element.
UPDATED:
If you set this to be your default decorator, you can eliminate the dd/dt tags from rendering, instead it will use a div. Then you may be closer to getting the custom output you want. You can change the tag in HtmlTag from div to whatever tag you would like to wrap your elements in. This is what I use mostly:
array(
'ViewHelper',
'Errors',
array('Description', array('tag' => 'p', 'class' => 'description')),
array('HtmlTag', array('tag' => 'div', 'class' => 'form-div')),
array('Label', array('class' => 'form-label', 'requiredSuffix' => '*'))
);
This is the default for Zend Framework:
array(
'ViewHelper',
'Errors',
array('Description', array('tag' => 'p', 'class' => 'description')),
array('HtmlTag', array('tag' => 'dd', 'id' => array('callback' => $getId)))
array('Label', array('tag' => 'dt'))
);
Note that file, and submit/button elements use different decorators.
Also see this answer