How to save values of multiple radios in yii2 activeForm? - php

I have a survey app with many questions. Each question has options that are presented in form of radiolist.
I am using the ActiveForm and RadioList in for loop in order to get all the questions and options from the Database.
Everything is ok with printing the questions and options but
When I try to save the answers to the database, it saves only the last option.
In my save action I tried to put a foreach loop in order to save each answer, but it didn't work for me.
I tried to var_dump the $model->save and $request->post('Questions') there is all the selected options, not only the last one.
Model:
here is only the rules:
public function rules(){
return[
[['id','question_id', 'option_id'], 'required']
];
}
View:
<?php $form = ActiveForm::begin([
'id' => 'my-form-id',
'action' => ['answers/save'],
]
);
?>
<?php $questions = Questions::find()->orderBy('id ASC')->all(); ?>
<?php for ($i=0; $i<count($questions); $i++): ?>
<?= Html::encode("{$questions[$i]->title}") ?>
<?php $options = Options::find()->where (['question_id'=>$questions[$i]->id])->orderBy('id ASC')->all();
$options = ArrayHelper::map($options,'id', 'title');
?>
<label class="container" >
<?= $form->field($model, 'option_title')->radioList(
$options,
['name'=>'Questions['.$questions[$i]->id.']',
'separator' => '<br>',
])->label(false) ?>
</label>
<?php endfor; ?>
<?= Html::submitButton('Save', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end(); ?>
Controller:
public function actionSave(){
$model = new Answers();
$request = \Yii::$app->request;
foreach($request->post('Questions') as $key=>$value) {
$model->load($request->post());
$model->option_id = $value;
$model->question_id = $key;
$model->save();
}
}
Sorry guys if it is obvious question but I really do not understand how to do it. Googling also didn't helped.
If you have any ideas please share

You need to move the $model = new Answers(); inside the loop as you need to save all the checkboxes by looping on the post array you should create a new object every time and then it will save all of them. Just change your code to the below
public function actionSave(){
$request = \Yii::$app->request;
foreach($request->post('Questions') as $key=>$value) {
$model = new Answers();
$model->load($request->post());
$model->option_id = $value;
$model->question_id = $key;
$model->save();
}
}
Also you should use transaction block when working with related or multiple records like in this case you should either save all of them or none in case of any error or exception, currently it isnt the case. If the exception or error occurs on the 4th checkbox you still have the first 3 checkbox values saved. Try wrapping the code like below
public function actionSave(){
$request = \Yii::$app->request;
//start transaction
$transaction=Yii::$app->db->beginTransaction();
try{
foreach ($request->post('Questions') as $key => $value) {
$model = new Answers();
$model->load($request->post());
$model->option_id = $value;
$model->question_id = $key;
$model->save();
}
//commit the transaction to save the records
$transaction->commit();
}catch(\Exception $e){
//rollback the transaction so none of the checkboxes are saved
$transaction->rollBack();
//do your stuff intimate the user by adding the message to a flash and redirecting
}
}

Related

How to post checked values of radiolist to database?

I am trying to create a Quiz app, with many MCQ questions that are stored in Database. I successfully get questions and options from Db and display it.
However, when I try to post the checked values to Db it doesn't work.
I am using ActiveForm and RadioList inside of it.
All data is taken from Db using for loop.
Also, I need to pass the question_id when posting the checked value.
I have Tables:
Questions - questions table.
Answers - table where I want to write the checked values.
Options - Table from where I get the options(a,b,c) for the questions.
Answers Controller:
public function actionSave()
{
$model = new Answers;
$request = \Yii::$app->getRequest();
if ($request->isPost && $model->load($request->post())) {
\Yii::$app->response->format = Response::FORMAT_JSON;
return ['success' => $model->save()];
}
return $this->renderAjax('index', [
'model' => $model,
]);
}
public function actionCreate()
{
$model = new Answers;
$this->save($model);
}
protected function save($model)
{
if (isset($_POST['Answers'])) {
$model->attributes = $_POST['Answers'];
if ($model->save()) {
$this->redirect(array('index'));
}
}
$this->render('_form', compact('model'));
}
Here is the view:
<?php $form = ActiveForm::begin(); ?>
<?php for ($i=0; $i<count($questions); $i++): ?>
<div>
<?= Html::encode("{$questions[$i]->title}") ?>
</div>
<?php $options = Options::find()->where(['question_id'=>$questions[$i]->id])->orderBy('id ASC')->all();
$options = ArrayHelper::map($options,'id', 'title');?>
<label class="container" >
<?= $form->field($model, 'option_id')->radioList($options, ['name'=>'Questions['.$questions[$i]->id.']', 'separator' => '<br>' ])->label(false) ?>
</label>
<?php endfor; ?>
<?= Html::submitButton('Save', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end(); ?>
I expect that when user answers all questions and press the "Save" button, it will save the checked value and question_id to the table in Db. However, now it do nothing, and do not show any errors.
I am working on this first time, so please can you help me to understand how to do it?
We are lacking the code of the model, as it is right now you could do:
Dump the post inside the action with var_dump($request->post());die();
Check if the values are on the post.
Check if the field name are in the rules of the class.
Check if the name of the field in the post is right.

Yii 1.1.19 Join Table Update not working fully

The Problem: If I select the new checkbox, it will update the data, but when I unchecked all the existing checkbox, it is not working. Even when I unchecked multiple checkboxes and leave one, it still works. Just not working when I select all unchecked checkbox to update data. Any suggestion would be greatly appreciated
This is my model that I am using get join table ID:
public function getProfileCampaigns($campaignIds = true) {
$campaignData = array();
$campaignProfiles = Yii::app()->db->createCommand()->select('campaign_id')
->from('campaign_profiles')
->where('profile_id = :profile_id',array(':profile_id' => $this->profile_id))
->queryAll();
// Check if need to send only campaign ids
if ($campaignIds) {
foreach ($campaignProfiles as $campaignProfile) {
$campaignData[] = $campaignProfile['campaign_id'];
}
}
return $campaignData;
}
This my controller for update action:
public function actionUpdate($id)
{
$model = $this->loadModel($id);
$model->setScenario(Profile::SCENARIO_UPDATE);
// Get active campaigns
$campaigns = Campaign::model()->findAll();
// Uncomment the following line if AJAX validation is needed
$this->performAjaxValidation($model);
// Check if profile have any releated profile
$model->campaignIds = $model->getProfileCampaigns();
if(isset($_POST['Profile']))
{
$model->attributes=$_POST['Profile'];
if($model->validate()) {
$model->save();
// Check if any campaign choosed
if ($_POST['Profile']['campaignIds']) {
Yii::app()->db->createCommand()->delete('campaign_profiles', 'profile_id = :profile_id', array(':profile_id' => $model->profile_id));
foreach ($_POST['Profile']['campaignIds'] as $campaignId) {
$campaignProfile = new CampaignProfile();
$campaignProfile->setIsNewRecord(true);
$campaignProfile->campaign_id = $campaignId;
$campaignProfile->profile_id = $model->profile_id;
$campaignProfile->save();
}
Yii::app()->user->setFlash('success', 'The Profile was successfully updated.');
$this->redirect(array('update','id'=>$model->profile_id));
}
}
}
$this->render('update',array(
'model' => $model,
'campaignListData' =>$campaigns,
));
}
This is form for getting checkbox select for update:
<div class="form-group">
<?php echo $form->labelEx($model,'campaignIds'); ?>
<div class="col-sm-9">
<?php echo $form->checkBoxList($model, 'campaignIds', CHtml::listData($campaignListData, 'id', 'name')); ?>
<?php echo $form->error($model,'campaignIds'); ?>
</div>
</div>
That is because only selected checboxes are send as form data. When no checkbox is checked, no data is sent, so probably default/old value from model is used.
You may use uncheckValue setting to define default value which will be send, when no checkbox is checked:
<div class="form-group">
<?php echo $form->labelEx($model,'campaignIds'); ?>
<div class="col-sm-9">
<?php echo $form->checkBoxList(
$model,
'campaignIds',
CHtml::listData($campaignListData, 'id', 'name'),
['uncheckValue' => '']
); ?>
<?php echo $form->error($model,'campaignIds'); ?>
</div>
</div>
Since 1.1.7, a special option named 'uncheckValue' is available. It can be used to set the value that will be returned when the checkbox is not checked. By default, this value is ''. Internally, a hidden field is rendered so when the checkbox is not checked, we can still obtain the value. If 'uncheckValue' is set to NULL, there will be no hidden field rendered.
https://www.yiiframework.com/doc/api/1.1/CHtml#activeCheckBoxList-detail

Yii2 checkboxlist broken down into categories (nested sets)

I seem to be having some trouble creating a form input that allows checkboxlists and nested sets to work together.
What I'd like, is something exactly like what bookbub does:
http://i.imgur.com/PfpgSf5.jpg
Right now in my database I have it structured as follows:
Category table
- id
- name
- parent_id
Basically, my idea is to display everything on the _form that has parent_id as null as a heading (no checkbox) and everything that has a parent_id as a checkbox under the appropriate heading.
However, the only solution that I can get that's close doesn't seem to allow me to have checkboxes already checked if we're updating a user's preferences. It does however display things exactly how I would like. Here's what I have so far:
ProfileReader's (ProfileReader is my model that extends users to hold their preferences) _form:
<?php
$primaryCategories = (new Category)->getPrimaryCategories();
//$selectedCategories = yii\helpers\ArrayHelper::map($model->categories, 'id', 'name');
foreach ($primaryCategories as $pc) {
echo '<p>'.$pc->name.'</p>';
if ($pc->subCategories) {
//the following never fully worked. It doesn't automatically check the boxes for relations that
//are already setup. You need to somehow use $model->categories[#] and 'id' for that to work
//echo $form->field($model->categories[#], 'id')->label(false)
echo $form->field($pc, 'subCategories[' . $pc->id . '][]')->label(false)
->checkboxList(yii\helpers\ArrayHelper::map($pc->subCategories, 'id', 'name'),
['separator' => '<p>']);
}
}
?>
ProfileReaderController:
public function actionUpdate()
{
$model = $this->findModel(\Yii::$app->user->identity->id);
if ($model == null) {
$model = new ProfileReader();
$model->user_id = \Yii::$app->user->identity->id;
}
if ($model->load(Yii::$app->request->post()) && $model->save()) {
//link the categories to the pen name
$categories = Yii::$app->request->post()['Category']['subCategories'];
$model->unlinkAll('categories', true);
foreach ($categories as $category) {
if ($category)
foreach ($category as $c) {
$c = (new Category)->findOne($c);
$model->link('categories', $c);
}
}
return $this->redirect(['update']);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
ProfileReader:
public function getCategories()
{
return $this->hasMany(Category::className(), ['id' => 'category_id'])
->viaTable('user_category', ['user_id' => 'user_id']);
}
Does anyone have any clue how I can make this work? Is it even possible in Yii2 with activeform?
Okay, after many hours I finally figured it out. Posting my resulting code here so that it may help someone else. Don't ask me to explain it as I don't fully get it myself :P
It might also be a good idea to do some testing on it too before throwing it into a live environment, I haven't done any yet.
update action:
/**
* Updates an existing ProfileReader model.
* If update is successful, the browser will be redirected to the 'view' page.
* #param integer $id
* #return mixed
*/
public function actionUpdate()
{
$model = $this->findModel(\Yii::$app->user->identity->id);
if ($model == null) {
$model = new ProfileReader();
$model->user_id = \Yii::$app->user->identity->id;
}
if ($model->load(Yii::$app->request->post()) && $model->save()) {
//unlink the categories first to avoid duplicates
$model->unlinkAll('categories', true);
//link the categories to the pen name
foreach ($model->categoriesArray as $pc) {
if ($pc) {
foreach ($pc as $sc) {
$sc = (new Category)->findOne($sc);
$model->link('categories', $sc);
}
}
}
return $this->redirect(['update']);
} else {
//get the categories and separate them into groups based on parent_id
foreach ($model->categories as $c) {
$model->categoriesArray[$c->parent_id][] = $c;
}
return $this->render('update', [
'model' => $model,
]);
}
}
ProfileReader model (had to add a variable):
public $categoriesArray;
_form:
<label class="control-label">Categories</label>
<?php
$allCategories = (new Category)->getOrderedCategories();
foreach ($allCategories as $pc) {
echo '<p>'.$pc['name'].'</p>';
echo $form->field($model, 'categoriesArray['.$pc['id'].'][]')->label(false)
->checkboxList(yii\helpers\ArrayHelper::map($pc['subCategories'], 'id', 'name'),
['separator' => '<p>']);
}
?>

Basic edit operation in yii

I have used CgridView which list all the data from my table 'Jobs',also have an edit and delete for each row.Which has been implemeted using prebuilt template in yii.I tried few things,but it not working.My first aim is to display that particular row data in edit form.
My codes are as follows:
The model corresponding is,UpdateJob.php.
/*Model*/
public function edit() {
$criteria = new CDbCriteria;
$criteria->compare('id', 'Admin', true);
return new CActiveDataProvider('viewjob', array(
// 'criteria' => $criteria,
'sort'=>array(
'defaultOrder'=>'key_skills ASC',
),
));
}
/*Contoller*/
public function actionUpdateJob()
{
if(isset($_GET['id'])) //Is it the right way //
{
$id=$_GET['id'];
}
$model = new UpdateJob('edit');
$params = array('model' => $model,'id' => $id
);
$this->render('update', $params);
}
/*VIEW*/ Have just tried to show the data as follows.
<div class="row">
<?php echo $form->labelEx($model,'Company Name'); ?>
<?php echo $form->textField($model,'posted_by'); ?>
<?php echo $form->error($model,'posted_by'); ?>
</div>
Thats it..
How to just display the row of a particular id. For the time being I don't want to update it. Please Help
this will be done through js
$(gridID).yiiGridView('getSelection') should be your start
read http://www.yiiframework.com/doc/api/1.1/CGridView

Editing a specific record in yii

I have a view section in my project,and using CGridView to list all the data from table,also have an edit and delete option within the grid to edit and delete specific row.
I am stuck with the edit section.I am working on how to get a specific row data dispalyed in editjob.php,I have done a few things,but no use.My codes are as follows,
In my view job section using CgridView,
'buttons' =>array('update'=>array(
'label'=>'edit',
'url'=>'Yii::app()->controller->createUrl("UpdateJob",array("id"=>$data["id"]))',
))
In Model UpdateJob:
public function edit()
{
$criteria=new CDbCriteria;
$criteria->find('id','Admin',true);
return new CActiveDataProvider('viewjob', array(
'criteria'=>$criteria,
// 'sort'=>array(
// 'defaultOrder'=>'key_skills ASC',
// ),
));
in controller:
public function actionUpdateJob()
{
if(isset($_GET['id']))
{
$id=$_GET['id'];
}
$model = new UpdateJob('edit');
$params = array('model' => $model,'id' => $id //passing the id like this
);
$this->render('update', $params);
}
And finaly in view written something like ,but showing error
<div class="row">
<?php echo $form->labelEx($model,'Company Name'); ?>
<?php echo Chtml::textField('posted_by',UpdateJob::model()->FindByPk($model->id)->posted_by); ?>
<?php echo $form->error($model,'posted_by'); ?>
</div>
am I on right track.
Youre loading a fresh model instead of fetching an existing one. Replace this line:
$model = new UpdateJob('edit');
By this line:
$model = UpdateJob::model()->findByPk($id);
To save the data you do this:
if(isset($_POST['UpdateJob'])) {
$model->scenario='edit';
$model->attributes=$_POST['UpdateJob'];
if($model->save())
$this->redirect(array('admin');
}

Categories