Jump to content

How to populate nested dynamic form inputs with data from server


PrashantS

Recommended Posts

I have a form which allows the user to select ASC center and add students data for each time. The scenario is a user selects ASC center from the drop down list. Upon selecting the ASC center, a function called StudentList returns the students for the selected ASC center. Now these students should be populated for each row. 

I have assigned a class for the Student input field and used each function of the jquery to populate all the students field with the data returned by the StudentList function. But the problem is the data gets populated for the very first row correctly. But as soon as the user clicks on Add Student to add more student for a particular time or clicks on Add Time to add new time then the previously populated data gets cleared. 

The expected is that the once the ASC center is selected from the drop down by the user, then no matter how many new students or new time is added by the user on the form by clicking Add Student or Add Time button then the previously populated data should not be cleared.

The below image shows the students populated for the first student row on selecting the ASC center

https://pasteboard.co/PDm9UwYMK4CI.png

Below is the image which shows the Students input field gets cleared when a user adds new student or adds new time

 

https://pasteboard.co/fzUipa4ZYtCO.png

 

Below is the function StudentList which returns the list of students for specific ASC center.

public function actionStudentLists($id)
    {
        $countstudents = Student::find()->where(['ASCId' => $id])->count();//Counts number of students

        $Students = Student::find()->where(['ASCId' => $id])->all(); // Execute students for ASCId

        if ($countstudents > 0) {

        echo "<option value>Select Students</option>";  

            foreach ($Students as $Student) {
        ob_start();

             echo "<option value='" . $Student->StudentId . "'>" . $Student->StudentName . "</option>";
            }
        } else {
            echo "<option> - </option>";
        }
    }

Below is the form

<?php
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\jui\DatePicker;
use wbraganca\dynamicform\DynamicFormWidget;
use app\models\Ascassignment;
use app\models\Asccenter;
use kartik\time\TimePicker;
use yii\helpers\ArrayHelper;
use app\models\Student;
?>

<script>
// When user clicks on Add Student button
$(function () {
 $(".dynamicform_student").on("beforeInsert", function(e, item) {
  $.post("index.php?r=student/student-lists&id=' . '"+$("select#ascteacherreport-ascid").val(),function(data){
	 $(".i").html(data);

   });
 });
});

//When user clicks on Add Time button
$(function () {
	$(".dynamicform_wrapper").on("beforeInsert", function(e, item) {
	   $.post("index.php?r=student/student-lists&id=' . '"+$("select#ascteacherreport-ascid").val(),function(data){
		$(".i").html(data);

	});
	});
});
</script>

<div class="ascteacherreport-form">

   <?php $form = ActiveForm::begin(['id' => 'dynamic-form',  'options' => ['class' => 'disable-submit-buttons'],
   ]);?>

   <div class="panel panel-primary " >
<div class="panel panel-heading"><font size="3"><b>Teacher Report</b></font></div>
<div class="row">
<div class="col-sm-4">

	<?= $form->field($model, 'ASCId')->dropDownList(ArrayHelper::map(Asccenter::find()->leftJoin('ascassignment','`ascassignment`.`ASCId`=`asccenter`.`ASCId`')->where(['ascassignment.UserId' => \Yii::$app->user->identity->getonlyid()])->all(),'ASCId','ASCName'), ['prompt' => 'Select ASC Center','class'=>'form-control ascid','onChange' => '

	$.post("index.php?r=student/student-lists&id=' . '"+$(this).val(),function(data){
					 $(".i").each(function(k,v)
					{
						 $(".i").html(data);  // Populates the Student control having class .i with the data from the StudentList function
					}
					);
					});
					'
	]) ?>
	</div>

<div class="col-sm-4">

	<?= $form->field($model, 'DateofReport')->widget(DatePicker::classname(), [
											//'language' => 'ru',
											'dateFormat' => 'yyyy-MM-dd',
											'options' => ['class' => 'form-control picker','readOnly'=>'readOnly'],
											'clientOptions'=>['changeMonth'=>true,
											'changeYear'=>true,
											'readOnly'=>true]
]) ?>
</div>
	</div>
	</div>



<div class="panel panel-primary">
		<div class="panel-heading"><font size="3"><b>Time and Student Details</b></font></div>
<?php DynamicFormWidget::begin([
		'widgetContainer' => 'dynamicform_wrapper',
		'widgetBody' => '.container-items',
		'widgetItem' => '.time-item',
		'limit' =>10,
		'min' => 1,
		'insertButton' => '.add-time',
		'deleteButton' => '.remove-time',
		'model' => $modelsTime[0],
		'formId' => 'dynamic-form',
		'formFields' => [
			'FromTime',
			'ToTime'
		],
	]); ?>
	<table class="table table-bordered">
		<thead>
			<tr bgcolor='#B8B8B8'>
			<th style='border: 1px solid black;'></th>
			   <th class ="text-center" style='border: 1px solid black;'>Time</th>
				<th class ="text-center" style='border: 1px solid black;'>Student Details</th>
				<th class="text-center" style='border: 1px solid black;'>
					<button type="button" class="add-time btn btn-success btn-xs"><span class="fa fa-plus"></span> Add Time</button>
				</th>
			</tr>
		</thead>
		<tbody class="container-items">
		<?php foreach ($modelsTime as $indexTime => $modelTime): ?>
			<tr class="time-item">
				<td class="vcenter" style='border: 1px solid black;'>
					<?php
						// necessary for update action.
						if (! $modelTime->isNewRecord) {
							echo Html::activeHiddenInput($modelTime, "[{$indexTime}]ASCReportDetailsId");
						}
					?>
					</td>
					<td style='border: 1px solid black;width:15%'>


					<?=  $form->field($modelTime, "[{$indexTime}]FromTime")->label(true)->widget(TimePicker::classname(),[ 
                                'pluginOptions' => [
                                'readOnly' => true,
                                'minuteStep' => 1,
                            ],])?>
                      <br>

				<?=$form->field($modelTime, "[{$indexTime}]ToTime")->label(true)->widget(TimePicker::classname(),[
                            'pluginOptions' => [
                                'readOnly' => true,
                                'minuteStep' => 1,
                           ],
							])?>
				</td>

				<td style='border: 1px solid black;'>
					<?= $this->render('_form-studentdata', [
						'form' => $form,
						'indexTime' => $indexTime,
						'modelsStudentdata' => $modelsStudentdata[$indexTime],
					]) ?>
				</td>
				<td class="text-center vcenter" style='border: 1px solid black;'>
					<button type="button" class="remove-time btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
				</td>
			</tr>
		 <?php endforeach; ?>
		</tbody>
	</table>
	<?php DynamicFormWidget::end(); ?>
</div>
	<div class="form-group">
		 <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

	</div>

	<?php ActiveForm::end(); ?>

</div>

 

Below is the nested inner form Student form

<?php
use yii\helpers\Html;
use yii\helpers\ArrayHelper;
use yii\bootstrap\ActiveForm;
//use nex\datepicker\DatePicker;
use yii\web\UploadedFile;
use wbraganca\dynamicform\DynamicFormWidget;
use app\models\Student;
?>
<?php DynamicFormWidget::begin([
    'widgetContainer' => 'dynamicform_student',
    'widgetBody' => '.container-student',
    'widgetItem' => '.student-item',
    'limit' => 50,
    'min' => 1,
    'insertButton' => '.add-student',
    'deleteButton' => '.remove-student',
    'model' => $modelsStudentdata[0],
    'formId' => 'dynamic-form',
    'formFields' => [
        'StudentId',
		'Subject',

		'Topic',
		'Confidence',
    ],
]); ?>
<table class="table table-bordered">
    <thead>
        <tr bgcolor='#B8B8B8'>
            <th style='border: 1px solid black;'></th>
                <th class ="text-center" style='border: 1px solid black;'>Student</th>
                <th class ="text-center" style='border: 1px solid black;'>Subject</th>
				<th class ="text-center" style='border: 1px solid black;'>Topic</th>
								<th class ="text-center" style='border: 1px solid black;'>Confidence</th>


            <th class="text-center" style='border: 1px solid black;'>
                <button type="button" class="add-student btn btn-success btn-xs"><span class="glyphicon glyphicon-plus"></span> Add Student</button>
            </th>
        </tr>
    </thead>
    <tbody class="container-student">
    <?php foreach ($modelsStudentdata as $indexStudent => $modelStudentdata): ?>
        <tr class="student-item">
            <td class="vcenter" style='border: 1px solid black;'>
                <?php
                    // necessary for update action.
                    if (! $modelStudentdata->isNewRecord) {
                        echo Html::activeHiddenInput($modelStudentdata, "[{$indexTime}][{$indexStudent}]ASCTeacherReportTimeDetailsId");
                    }
                ?>
				</td>
				<td style='border: 1px solid black; width:30%'><?= $form->field($modelStudentdata, "[{$indexTime}][{$indexStudent}]StudentId")->label(false)->dropDownList(ArrayHelper::map(Student::find()->all(),'StudentId','StudentName'), ['prompt' => 'Select Student','class'=>'form-control i']) ?> //class .i assigned to the Student
            </td>
			<td style='border: 1px solid black; width:30%'>
                <?= $form->field($modelStudentdata, "[{$indexTime}][{$indexStudent}]Subject")->label(false)->textInput(['maxlength' => true]) ?>
            </td>
			<td style='border: 1px solid black; width:30%'>
                <?= $form->field($modelStudentdata, "[{$indexTime}][{$indexStudent}]Topic")->label(false)->textInput(['maxlength' => true]) ?>
            </td>

			<td style='border: 1px solid black; width:30%'>
                <?= $form->field($modelStudentdata, "[{$indexTime}][{$indexStudent}]Confidence")->label(false)->textInput(['maxlength' => true]) ?>
            </td>
            <td class="text-center vcenter" style=" border: 1px solid black;width: 90px;">
                <button type="button" class="remove-student btn btn-danger btn-xs"><span class="glyphicon glyphicon-minus"></span></button>
            </td>
        </tr>
     <?php endforeach; ?>
    </tbody>
</table>

<?php DynamicFormWidget::end(); ?>

 

Edited by PrashantS
Link to comment
Share on other sites

I can't tell for sure, but it seems like maybe you're using JavaScript to populate the select list after a new student/time is added.  The problem I think is that you're re-populating all the select lists with your code.

You have:

$('.i').html(data);

Which will find ALL elements with class i and replace their content.  What you want to do instead is find only the newly added .i element and replace it's content, not any others.  Something like this probably:

$(".dynamicform_student").on("beforeInsert", function(e, item) {
  const $i = $(this).find('.i');
  $.post("index.php?r=student/student-lists&id=' . '"+$("select#ascteacherreport-ascid").val(),function(data){
    $i.html(data);
  });
});

In the beforeInsert callback, this should be the .dynamicform_student element that triggered the event, so use that to create a new jQuery instance and then find a child of it with class i.

Link to comment
Share on other sites

Yes it works, but there is an issue where a user selects an ASC center from the drop down then all the students belonging to that ASC center gets populated on the first row correctly but when the user clicks on Add Student button to add students or clicks on Add Time button to add time then all students are displayed (All ASC centers students are displayed). Only selected ASC centers students should be populated every time the user clicks on Add Student or Add Time button.

Link to comment
Share on other sites

Your URL is probably wrong.

On 3/22/2023 at 9:32 AM, PrashantS said:
"index.php?r=student/student-lists&id=' . '"+$("select#ascteacherreport-ascid").val()

Seems like you tried to mix PHP style and JS style concatenation there.  As such, you're PHP script probably isn't getting the correct ID and just loading everything.

Link to comment
Share on other sites

The URL is getting the correct ASC Id. Following is the code where I am alerting the ASC Id

$(function(){
 $(".dynamicform_student").on("afterInsert", function(e, item) {
	 const $i = $(this).find('.i');
     $.post("index.php?r=student/student-lists&id=' . '"+$("select#ascteacherreport-ascid").val(),function(data){
						   alert($("select#ascteacherreport-ascid").val());
					});

	});

});

If I remove $(function(){ }); block then alert is not working

Link to comment
Share on other sites

kicken's point is that you need to remove the ' . ' from the URL. take this line:

$.post("index.php?r=student/student-lists&id=' . '"+$("select#ascteacherreport-ascid").val(),function(data){

and change it to this:

$.post("index.php?r=student/student-lists&id="+$("select#ascteacherreport-ascid").val(),function(data){

 

Link to comment
Share on other sites

Use the browser's dev tools (networking tab) to inspect the URL and response of your ajax request.  If the URL has the correct ID, but it's response includes all students then there is a problem in your PHP code somewhere.  You'll have to start debugging that to determine why the ID filter is not being applied.

Link to comment
Share on other sites

I change the code to below, but it has issue like previously selected students are getting cleared.

$(document).ready(function(){
 $(".dynamicform_student").on("afterInsert", function(e, item) {
	 const $i = $(this).find('.i');
    $.post("index.php?r=student/student-lists&id="+$("select#ascteacherreport-ascid").val(),function(data){
						   $i.html(data);
					});

	});
});

When I inspect using Network tab, then first time when the user selects the ASC center, the URL gets the correct Id and response is also correct.(Only those students are getting displayed in response as well as in the field belonging to that ASC center)

Image 1 : URL getting correct ID and response is also correct (ASC Center of Id 6 is getting correctly to the URL)

image1.png.26179942309b887b645298b7a9d81955.png

 

Image 2: When user clicks on Add Student button to add new students, then also URL is getting correct ID as well as the response is also correct as shown in below image, but the previously selected students are getting cleared from the form.

image2.png.c6da6645667c25fd4590ea6c3c89e3a9.png

Link to comment
Share on other sites

If the selects are getting cleared, then

const $i = $(this).find('.i');

probably is selecting too many items.  You can check how many inputs it's selecting by logging it.

console.log($i.length, $i);

If it's selecting too much, you'll need to either find a way to narrow the selection or save and restore the selected item when changing the option list.

Link to comment
Share on other sites

$(document).ready(function(){
 $(".dynamicform_student").on("afterInsert", function(e, item) {
	 const $i = $(this).find('.i');
    $.post("index.php?r=student/student-lists&id="+$("select#ascteacherreport-ascid").val(),function(data){
						   console.log(e,item);
					});

	});
});

Doesn't logs anything on the console

Link to comment
Share on other sites

Yes it works correctly for the first time row. But when the user clicks on Add Time button to add students then the first student row of second time gets cleared and second student row of second time shows all the students.

image5.thumb.png.0cef6b2a2fda4fd9fee73c9832cf4bd2.png

 

// When the user clicks on Add Student button
$(document).ready(function(){
 $(".dynamicform_student").on("afterInsert", function(e, item) {
	const $i = $(item).find('.i');
    $.post("index.php?r=student/student-lists&id="+$("select#ascteacherreport-ascid").val(),function(data){
 $i.html(data);
					});

	});
});

//When the user clicks on Add Time button
$(document).ready(function(){
	$(".dynamicform_wrapper").on("afterInsert", function(e, item) {
		const $i = $(item).find('.i');
	   $.post("index.php?r=student/student-lists&id=' . '"+$("select#ascteacherreport-ascid").val(),function(data){
						   $i.html(data);

					});
	});
});

 

Link to comment
Share on other sites

I made changes to the code and now it is working correctly. But on the update page it causes issue like all students are displayed for loaded fields. As shown in the image, it is the update page and student data is loaded but when the user clicks on the drop down of loaded student data then all students are displayed.

// When the user clicks on Add Student button
$(document).ready(function(){
 $(".dynamicform_student").on("afterInsert", function(e, item) {
	const $i = $(item).find('.i');
    $.post("index.php?r=student/student-lists&id="+$("select#ascteacherreport-ascid").val(),function(data){
 $i.html(data);
					});

	});
});

//When the user clicks on Add Time button
$(document).ready(function(){
	$(".dynamicform_wrapper").on("afterInsert", function(e, item) {
		const $i = $(item).find('.i');

	   $.post("index.php?r=student/student-lists&id="+$("select#ascteacherreport-ascid").val(),function(data){
						   $i.html(data);

					});
					// When the user clicks on Add Student button
					$(".dynamicform_student").on("afterInsert", function(e, item) {
	const $i = $(item).find('.i');
    $.post("index.php?r=student/student-lists&id="+$("select#ascteacherreport-ascid").val(),function(data){
 $i.html(data);
					});

	});
	});
});

 

update.thumb.png.0f48b6c71c52af561cc712762c3ea72c.png

 

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.