Fill textfield based on dropdrown selection (form in bootstrap modal) ajax

Hello guys, it’s been a long time since my last post.
Today I come to ask for help with an ajax function.
This is the full picture:
I got a form in a bootstrap modal and within the form there are 3 dropdowns and 4 textfields. Alumno and Asignatura are dependent dropdowns. That’s working fine. The problem is I need to populate the textfields below. Nota1, Nota2, Nota3 and Nota4 when I select Asignatura.

Here’s some code:

Model class Nota.php

class Nota extends \yii\db\ActiveRecord
{
    /**
     * {@inheritdoc}
     */
    public static function tableName()
    {
        return 'nota';
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [['id_alumno', 'id_asignatura', 'id_curso'], 'required'],
            [['id_alumno', 'id_asignatura'], 'integer'],
            [['nota1', 'nota2', 'nota3', 'nota4', 'promedio'], 'number'],
            [['id_curso'], 'string', 'max' => 45],
            [['id_alumno'], 'exist', 'skipOnError' => true, 'targetClass' => Alumno::className(), 'targetAttribute' => ['id_alumno' => 'id']],
            [['id_asignatura'], 'exist', 'skipOnError' => true, 'targetClass' => Asignatura::className(), 'targetAttribute' => ['id_asignatura' => 'id']],
            [['id_curso'], 'exist', 'skipOnError' => true, 'targetClass' => Curso::className(), 'targetAttribute' => ['id_curso' => 'id']],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'id_alumno' => 'Alumno',
            'id_asignatura' => 'Asignatura',
            'id_curso' => 'Curso',
            'nota1' => 'Nota1',
            'nota2' => 'Nota2',
            'nota3' => 'Nota3',
            'nota4' => 'Nota4',
            'promedio' => 'Promedio',
        ];
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getAlumno()
    {
        return $this->hasOne(Alumno::className(), ['id' => 'id_alumno']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getAsignatura()
    {
        return $this->hasOne(Asignatura::className(), ['id' => 'id_asignatura']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getCurso()
    {
        return $this->hasOne(Curso::className(), ['id' => 'id_curso']);
    }
}

function actionListarNota in NotaController.php

public function actionListarNotas($id_alumno, $id_asignatura)
    {        
        //Almacena todas las notas donde 'id_alumno' = $id_alumno y 'id_asignatura' = $id_asignatura
        $notas = Nota::find()
                ->select(['nota1', 'nota2', 'nota3', 'nota4'])
                ->where(['id_alumno' => $id_alumno])
                ->andWhere(['id_asignatura' => $id_asignatura])
                ->all();
        
        foreach ($notas as $nota){
            echo Json::encode($nota);
        }
    }

_form.php view of Nota

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\helpers\ArrayHelper;

/* @var $this yii\web\View */
/* @var $model app\models\Nota */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="nota-form">

    <?php $form = ActiveForm::begin(); ?>
    
    <?= $form->field($model, 'id_curso')->dropDownList(

ArrayHelper::map(app\models\Curso::find()->all(),'id', 'id'),
            [
                'prompt' => 'Seleccione un curso',
                'onchange' => '$.post("index.php?r=alumno/listar-alumnos&id=' . '"+$(this).val(), function(data){
                    $("#nota-id_alumno").html(data);
                });',    
                
            ]); ?>
    
    <?= $form->field($model, 'id_alumno')->dropDownList(

ArrayHelper::map(app\models\Alumno::find()->all(),'id', 'nombre'), 
            [
                'prompt' => 'Seleccione un alumno',
            ]); ?>

<?= $form->field($model, 'id_asignatura')->dropDownList(

ArrayHelper::map(app\models\Asignatura::find()->all(),'id', 'nombre'),
            [
                'prompt' => 'Seleccione una asignatura',
                'onchange' => '$.get("index.php?r=nota/listar-notas&id_alumno=' . '"+$("#nota-id_alumno").val()' .
                '+"&id_asignatura=' . '"+$(this).val(), function(data){
                    alert(data);
                    $("#nota-nota1").attr("value", data);
                });'
                
            ]); ?>
    
    <?= $form->field($model, 'nota1')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'nota2')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'nota3')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'nota4')->textInput(['maxlength' => true]) ?>

    <div class="form-group">
        <?= Html::submitButton('Guardar', ['class' => 'btn btn-primary']) ?>
    </div>

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

</div>

Here’s a picture of the form and the network response. I need to populate all textfields with data I fetch from actionListarNotas. Im getting all data in the first textfield instead. Im new to ajax. Any suggestions??

Thanks in advance.

@samdark @softark could you give me a little hand my friends?

Hi @jc.reyes.suazo

Maybe this instead:

$("#nota-nota1").attr("value", data.nota1);
$("#nota-nota2").attr("value", data.nota2);
$("#nota-nota3").attr("value", data.nota3);
$("#nota-nota4").attr("value", data.nota4);

One thing I’m concerned about is that you are returning multiple data from actionLstarNotas. Is it OK with you? I mean that if you are sure you have only one Nota for the given Alumno and Ssignatura you should use one instead of all.

Thank you @softark for your quick response.

I corrected actionListarNotas like this

public function actionListarNotas($id_alumno, $id_asignatura)
    {        
        //Almacena todas las notas donde 'id_alumno' = $id_alumno y 'id_asignatura' = $id_asignatura
        $notas = Nota::find()
                ->select(['nota1', 'nota2', 'nota3', 'nota4'])
                ->where(['id_alumno' => $id_alumno])
                ->andWhere(['id_asignatura' => $id_asignatura])
                ->one();
        
        echo Json::encode($notas);
        
    }

and Im getting this

1. {nota1: "7.0", nota2: "5.6", nota3: "", nota4: ""}

  1. nota1: "7.0"
  2. nota2: "5.6"
  3. nota3: ""
  4. nota4: ""

I proved with an alert of data.nota1

<?= $form->field($model, 'id_asignatura')->dropDownList(

ArrayHelper::map(app\models\Asignatura::find()->all(),'id', 'nombre'),
            [
                'prompt' => 'Seleccione una asignatura',
                'onchange' => '$.get("index.php?r=nota/listar-notas&id_alumno=' . '"+$("#nota-id_alumno").val()' .
                '+"&id_asignatura=' . '"+$(this).val(), function(data){
                    alert(data.nota1);
                    $("#nota-nota1").attr("value", data.nota1);
                    $("#nota-nota2").attr("value", data.nota2);
                    $("#nota-nota3").attr("value", data.nota3);
                    $("#nota-nota4").attr("value", data.nota4);
                });'
                
            ]); ?>

and this is what I see

The thing is I cant separate the data, variable data has all data. data.nota1, data.nota2, data.nota3, data.nota4 are undefined.

@jc.reyes.suazo

What about this?

public function actionListarNotas($id_alumno, $id_asignatura)
{
    $notas = Nota::find()
        ->select(['nota1', 'nota2', 'nota3', 'nota4'])
        ->where(['id_alumno' => $id_alumno])
        ->andWhere(['id_asignatura' => $id_asignatura])
        ->one();
    Yii::$app->response->format = Response::FORMAT_JSON;
    return Json::encode($otas);
}

@softark I tested it and I’m getting this

{"nota1":"7.0","nota2":"5.6","nota3":"","nota4":""}null 

Doesn’t work either, plus the alert doesn’t display.
Any thoughts?

public function actionListarNotas($id_alumno, $id_asignatura)
{
    $nota = Nota::find()
        ->select(['nota1', 'nota2', 'nota3', 'nota4'])
        ->where(['id_alumno' => $id_alumno])
        ->andWhere(['id_asignatura' => $id_asignatura])
        ->one();
    Yii::$app->response->format = Response::FORMAT_JSON;
    return $nota;
}

This should work.