Yii2: Why kartik\select2 widget not filled then I trying update model? - php

Im have ActiveRecord model and view for update form of this model. Also I have getter and setter in model class that looks like this
public function setTopvisorGoogleRegion($value)
{
$this->myvalue = $value;
return(true);
}
public function getTopvisorGoogleRegion()
{
return([1 => '123']); //I return this array for show you essence of the problem
}
Following logic in this code $model->topvisorgoogleregion must return [1 => '123']
In view I have next code
<?php echo($form->field($model, topvisorgoogleregion)->textInput());?>
<?php echo $form->field($model, 'topvisorgoogleregion')->widget(Select2::classname(), [
'data' => [1 => '123', 2 => '456'],
'options' => [
'id'=>'projectCtrl',
'placeholder' => 'Select option',
'multiple' => true
],
'pluginOptions' => [
'allowClear' => true,
'tags' => true,
],
]);
?>
When I open form I want to see option 1 => '123' already selected in Select2. Its logically because when already existing record is updating, ActiveRecord get data that already stored in model (in this case using getter) and fill fields in view with this data (In first field that using textInput I see text 'Array' because getter in model returns array). But Select2 is empty when I open update page. Whats going wrong?
If I delete first field (textInput) nothing changes

I find the solution - in getter I need provide ActiveQuery object, not array. I dont know why and how it works, but it works

Related

Yii2 Load schedule using unclead/yii2-multiple-input

I am using unclead / yii2-multiple-input widget.
I want to generate different number of rows with values from my database.
How can i do this?
I can design my columns in view and edit data manualy after page generated. But miss how to program the number of rows and its values in the view.
My code in view:
<?= $form->field($User, 'User')->widget(MultipleInput::className(), [
'min' => 0,
'max' => 4,
'columns' => [
[
'name' => 'name',
'title' => 'Name',
'type' => 'textInput',
'options' => [
'onchange' => $onchange,
],
],
[
'name' => 'birth',
'type' => \kartik\date\DatePicker::className(),
'title' => 'Birth',
'value' => function($data) {
return $data['day'];
},
'options' => [
'pluginOptions' => [
'format' => 'dd.mm.yyyy',
'todayHighlight' => true
]
]
],
]
])->label(false);
How can I make (for example) 8 rows with different values, and also have the ability to edit/remove/update some of them?
You need to look into the documentation as it says that you need to assign a separate field into the model which will store all the schedule in form of JSON and then provide it back to the field when editing/updating the model.
You have not added the appropriate model to verify how are you creating the field User in your given case above. so, i will try to create a simple example which will help you implement it in your scenario.
For Example.
You have to store a user in the database along with his favorite books.
User
id, name, email
Books
id, name
Create a field/column in you User table with the name schedule of type text, you can write a migration or add manually.
Add it to the rules in the User model as safe.
like below
public function rules() {
return [
....//other rules
[ [ 'schedule'] , 'safe' ]
];
}
Add the widget to the newly created column in ActiveForm
see below code
echo $form->field($model,'schedule')->widget(MultipleInput::class,[
'max' => 4,
'columns' => [
[
'name' => 'book_id',
'type' => 'dropDownList',
'title' => 'Book',
'items' => ArrayHelper::map( Books::find()->asArray()->all (),'id','name'),
],
]
]);
When saving the User model convert the array to JSON string.
like below
if( Yii::$app->request->isPost && $model->load(Yii::$app->request->post()) ){
$model->schedule = \yii\helpers\Json::encode($model->schedule);
$model->save();
}
Override the afterFind() of the User model to covert the json back to the array before loading the form.
like below
public function afterFind() {
parent::afterFind();
$this->schedule = \yii\helpers\Json::decode($this->schedule);
}
Now when saved the schedule field against the current user will have the JSON for the selected rows for the books, as many selected, for example, if I saved three books having ids(1,2,3) then it will have json like below
{
"0": {
"book_id": "1"
},
"2": {
"book_id": "2"
},
"3": {
"book_id": "3"
}
}
The above JSON will be converted to an array in the afterFind() so that the widget loads the saved schedule when you EDIT the record.
Now go to your update page or edit the newly saved model you will see the books loaded automatically.

CakePHP 3 Modeless Form Persistence

I am creating a modeless form based on the example given here. Once the user clicks the submit button, I retrieve some information from the database and display it in a table beneath the form. When I click on the submit button, the form displays the default values for start and end every time which is causing some confusion from my users using the page.
Is there any way to have the FormHelper display the values submitted by the end user rather than the defaults?
src/Form/StartEndForm.php
namespace App\Form;
use Cake\Form\Form;
class StartEndForm extends Form{
protected function _buildSchema(Schema $schema) {
return $schema->addField('start', [
'type' => 'date',
'default' => new Time('-1 month')
])
->addField('end', [
'type' => 'date',
'default' => new Time()
]);
}
protected function _buildValidator(Validator $validator) {
return $validator->add('start', 'date', [
'rule' => ['date'],
'message' => 'Please provide a valid date'
])
->add('end', 'date', [
'rule' => ['date'],
'message' => 'Please provide a valid date'
]);
}
protected function _execute(array $data) {
//do some SQL stuff and return the value
}
}
src/Template/Logs/index.ctp
echo $this->Form->create($form, [
'class' => 'start-end-date',
'type' => 'get'
]);
echo $this->Form->input('start');
echo $this->Form->input('end');
echo $this->Form->submit('Submit');
echo $this->Form->end();
//If values were returned, create a table
foreach(....)....
You are using a GET based form, ie the form values are being sent via the query string, and by default the form helper does not take the query string into account when looking for possible data to populate its controls, hence you'll end up with the forms being populated with the schema defaults.
You can either enable query string lookup (available as of CakePHP 3.4):
echo $this->Form->create($article, [
'class' => 'start-end-date',
'type' => 'get'
'valueSources' => [
'query', // < add this _before_ the default `context` source
'context'
]
]);
which will make the form helper explicitly look up the query data in the current request, or you could switch to using a POST form, which will automatically pick up the data as POST data is by default looked up by all built-in form contexts (Array, Entity, Form, Null), either as fallback, or as the primary source.
See also
Cookbook > Views > Helpers > Form > Getting form values from the query string

Yii2 Kartik EditableColumn Dropdown Relation Returns wrong Value

I have an issue with a Gridview using kartik\grid\EditableColumn, after changing the value I am returned the wrong value for the column when it updates. I am returned the dropdown key/main table integer rather than the string contained in a linked table.
I have two tables
Leads - columns id and status_id
Related fields - model, field, related_value, related_value
The relation is based on in this case
model:"Leads",
field:"status_id",
related_id:status_id
I have the following relation in my model
public function getStatus()
{
return $this->hasOne(RelatedFields::className(), ["related_id" => "status_id"])->andOnCondition(["status.field" => "status_id", "status.model"=>"Leads"])->from(["status" => RelatedFields::tableName()]);
}
I also created the following as a test based on this link
public function getStatusValue()
{
return $this->status->related_value;
}
Here is the column code
[
'class' => 'kartik\grid\EditableColumn',
'attribute' => 'status_id',
'value'=>'status.related_value',
//'value' => function($model){ return $model->status->related_value; },
//'value' => function($model){ return $model->StatusValue; },
//'refreshGrid' => true,//Works but not nice
'vAlign'=>'middle',
'hAlign'=>'center',
'pageSummary' => true,
'readonly' => false,
'width'=>'10%',
'filter'=>Html::activeDropDownList($searchModel, 'status', ArrayHelper::map(RelatedFields::Find()->where(['model' =>"Leads","field"=>"status_id"])->all(), 'related_id', 'related_value'),['class' => 'form-control','prompt' => Yii::t('app', '')]),
'editableOptions'=> [
//'attribute'=>'status_id',
//'value'=>'status.related_value',
//'header' => 'profile',
//'format' => Editable::FORMAT_BUTTON,
'inputType' => Editable::INPUT_DROPDOWN_LIST,
'data'=> ArrayHelper::map(RelatedFields::Find()->where(['model' =>"Leads","field"=>"status_id"])->all(), 'related_id', 'related_value'),
]
],
Commented out are a number of lines in my attempts to fix the issue as well as combinations of them, however all result in the wrong value.
If for example I select the related value "New" which has a related_id 1, after the column has been updated I get the value 1 instead of "New".
When the table is first loaded/reloaded the value does show correctly.
I could reload the grid, but this seems wrong just to fix 1% of the data shown on the page.
I your model take a public variable $status_value
create an assigning value method
public function getStatusValue()(){
return $this->status_value= $this->status->related_value;
}
Now in Gridview use getStatusValueenter code heremethod with assigning value as below
use yii\helpers\Url;
$gridColumns = [
[
'class' => 'kartik\grid\EditableColumn',
'attribute' => 'status_value',
'pageSummary' => true,
'readonly' => false,
'value' => function($model){ return $model->statusValue; }, // assign value from getStatusValue method
'editableOptions' => [
'header' => 'status_value',
'inputType' => kartik\editable\Editable::INPUT_TEXT,
'options' => [
'pluginOptions' => [
]
]
],
],
];
If you follow Kartik guide, he suggest to add EditableColumnAction to better handle the editable column:
The EditableColumnAction offers a quick easy way to setup your
controller action for updating, saving and managing the EditableColumn
output from GridView. This action class extends from yii\rest\Action
and hence all properties available with yii\rest\Action are applicable
here. The basic setup of the column involves setting up the controller
action and the EditableColumn.
So you need to add an EditableColumnAction in your controller to handle the update of the model:
public function actions()
{
return ArrayHelper::merge(parent::actions(), [
'edit-lead' => [
'class' => EditableColumnAction::class,
'modelClass' => Leads::class
]
]);
}
In your GridView editable column configuration, include the above
controller action for processing the Editable within editableOptions.
For example
And in your column code you need to add the action to editableOptions property:
'editableOptions' => [
...
'formOptions' => ['action' => ['/leads/edit-lead']]
]
Now, according to the guide, you can add to your action the outputValue property:
'outputValue' => function (Leads $model) {
return $model->status->related_value;
}

How to add default value selected in dropdownlist with enum?

I am new to yii2 and trying to get around. I have a dropdownlist whose values in the database are enum. So when the crud was created the dropdownlist had the enum values.
But I want to keep one value selected as default in the drop down list.
My form code is below:
<?= $form->field($model, 'priotiy_level')->dropDownList([ 'low' => 'Low', 'medium' => 'Medium', 'high' => 'High', ], ['prompt' => 'Select Priority Level']) ?>
Instead of the prompt, I want to have medium as a selected value. Can someone please help me with this?
Thank you.
After initialization of the $model instance in your controller set the attribute and then pass $model to view.
$model->priority_level = 'medium';
As #Bizley said, you need to set the value of the attribute in your Controller. In Yii2, you can do that with in one line:
public function actionSomething {
$model = new MyClass(['priotiy_level' => 'medium']);
// code
return $this->render('something', [
'model' => $model
]);
}
Additionally to previous answers you can also use default validator:
class SomeActiveRecord extends ActiveRecord {
// ...
function rules(){
return [
['priotiy_level', 'default', 'value' => 'medium']
// set "username" and "email" as null if they are empty
[['username', 'email'], 'default'],
// set "level" to be 1 if it is empty
['level', 'default', 'value' => 1],
];
}
}
More details see here: Handling Empty Inputs.
This code sets default value for the all actions/forms. If you need different default values on different forms, can be used also scenarios of validation.
Give class to your dropdownList :
Ex.
<?= $form->field($model, 'priotiy_level')->dropDownList([ 'low' => 'Low', 'medium' => 'Medium', 'high' => 'High', ], ['class' => 'priority_list','prompt' => 'Select Priority Level']) ?>
Give Default value using Java Script or Jquery
Ex.
<script>
$(".priority_list").val('medium'); // assing value using jquery
</script>
You can also use ID:
Ex.
<script>
var temp=document.getElementById('project-industry_id');
temp.value='medium';
</script>

cakephp 3.0 how to populate a select field with values instead of id

i was looking for a previous answer, but the ones i've found are related to older cakephp versions
i have two tables, 'magazines' and 'issues' where there is a relation 'issues' BelongsTo 'magazines', this is what IssuesTable looks like:
public function initialize(array $config){
$this->belongsTo('Magazines', [
'foreignKey' => 'id'
]);
}
table magazines has two fields, magazines.id and magazines.name
table issues has two fields, issues.id, issues.magazine_id where issues.magazine_id is the foreign key
to populate a select input in the issues view with the magazine.name values and save the issues.magazine_id, i've set the controller like this
$this->set('magazines', $this->Issue->Magazine->find('list'));
then i've added the following code to the issue view add.cpt
<?php
echo $this->Form->input('name', [
'type' => 'select',
'multiple' => false,
'options' => $magazines,
'empty' => true]);
?>
but i get the input select with the issues.magazine_id as values instead of magazines.name
thanks for your help and comments
You want to use find('list') as this will return the primary key and display field:-
$this->set(
'magazines',
$this->Issues->Magazines->find('list')
);
Then in your form you need the input name to be magazine_id if you're wanting to set the foreign key for the association:-
echo $this->Form->input(
'magazine_id',
[
'type' => 'select',
'multiple' => false,
'options' => $magazines,
'empty' => true
]
);
See the docs for more info.
Update
If you're experiencing issues with find('list') it is perhaps because your model's displayField is not getting set correctly. Cake normally determines the displayField for the model on initialisation. If this isn't working, or you want a different field you can set this manually in the model's initialize() method. E.g.:-
class MagazinesTable extends Table
{
public function initialize(array $config)
{
$this->displayField('name');
}
}
Changing 'name' to the appropriate field.
Alternatively, you can choose which field Cake will use for the values returned by find('list') (this is particularly useful when you want to override the default displayField). E.g.:-
$this->Issues->Magazines->find('list', [
'keyField' => 'id',
'valueField' => 'name'
]);
Display selected option in month helper
$this->Form->month('students.month', [
'label' => false,
'value'=>date('m'),
'required'=>true
]);
This actually helped me.
$this->Issues->Magazines->find('list', [
'keyField' => 'id',
'valueField' => 'name'
]);

Categories