Dynamically add form field to ActiveForm

Hi, in my project i want to create form fields dynamically on an ActiveForm, similar to what the DynamicForm extension does.

I want to create these elements based on a dropdown selection (for example, if the user selects "name" then a form field for the model attribute "name" should be created) and later on submit all the inputs values to apply filters in a grid. Basically i want to create "N" fields of the same model depending on what the user specify. This means that a field for the same model attribute may be created again as well.

How should i approach this? so the form fields get rendered properly and validation rules work on the newly created fields correctly.

Any help is greatly appreciated. Let me know if any more info is needed, thanks in advance.

Your best bet might be to ajax load the view after a dropdown onChange event. the view could use that plugin you linked in your original post.

This would essentially have different model for each option that could all share the same table. This could be beneficial as getting into scenarios can get really messy really quickly if you have a lot of different options.

You could have just one action that dynamically calls a different view based on the value passed in the ajax call that is based off of the selection.

That sounds like a good option, although i’m not entirely sure how to implement it. I’ll have to test a bit and see if i can implement it in this way. I don’t know how i’ll apply the filters based on these inputs later on but i’ll have to do it one step at a time.

Thanks for your help.

I don’t know if there are bugs in this since i fully typed it in the commet box but it should get your going in the right direction if this is the path you want to go.




//view


<-- your select list here -->

<div id="ajaxContent"></div>


<script>

jQuery('#dropdown_id').on('change',function(){

 jQuery.post('<?= Url::to(['/yourController/create-type']);?>?type=' + jQuery(this).val(), function(data){

  jQuery('#ajaxContent').html(data);

 })

});

</script>


//controller

public function actionCreateType($type){

//your model

//if you dynamically do it you need to fully namespace it in your use statements.

 $model =  new $type;

//other stuff

 return $this->renderAjax("_form_{$type}",[

   'model'=>$model

 ]);

}



I’m doing something similar to what you suggested me but i’m unsure about some things. The main problem right now is how can i send all the data from the created inputs with one button (a submit button).

I’m rendering the view with the model that will be used in the input, something like this:




<?php 


use yii\bootstrap\ActiveForm;

use yii\helpers\Html;


?>




<?php $form = ActiveForm::begin(['id' => 'campo-adicional', 

                                 'action' => ['index'],

                                 'method' => 'get',

                                 ]) ?>


<div class="row">

<div class="col-xs-4 col-xs-offset-2">

    <?= 

        $form->field($model, 'cargo_empresa')->textInput(['placeholder' => 'Name'])->label(false) ?>

</div>

</div>


<div class="row">

    <div class="col-xs-6 col-xs-offset-5">

        <?= Html::submitButton('Buscar', ['class' => 'btn btn-primary']) ?>

    </div>

</div>


<?php ActiveForm::end() ?>



In my ajax call i append this content to a div.




$('#ajaxContent').append(data);



The input gets generated correctly. I can submit the value of this input with the submit button associated, but I want to submit this and other input values (if the user has created and filled more inputs) with one button at the end of the "form". How can i achieve this?

Thanks for your help skworden.

This should help you in the tabular data portion

http://www.yiiframework.com/doc-2.0/guide-input-tabular-input.html

I still can’t find a way to implement this with just a single form. In order to create the inputs properly i’m rendering a view with just the input to be generated, to do this i wrap the input inside an ActiveForm and generate the input in the “standard” way.




<?= $form->field($model, 'model_attribute')->textInput(['placeholder' => 'Name']) ?>



Problem is, in my search view (_search.php) I can’t submit the values from these inputs, i think this is because these belong to a different form so my “outer” ActiveForm can’t send them (I shouldn’t be nesting forms, i know). How can i generate the inputs in the same form dynamically? pure jQuery (using clone() and appendTo()) doesn’t seem to work either.

I’ll take another look at tabular data input, it’ll be useful later on.

What you’re trying to do is called tabular input. Read the link and do some google searches on yii2 and tabular input or just use that plugin you referenced in the og post. You will use jquery and a default like yii2 input. I think you almost have it but you seem to be overthinking it.

[size=“5”][u][b]It’s Work Perfact for Dynamic add Form fields Store into DB and Also Update Form

[/b][/u][/size]

[size="3"][b]//controller CandidateController.php

[/b][/size]

[size="4"]CandidateControlller.php - [/size]




    public function actionAddCandidate(){

        $model = new CandidateForm();


         if (Yii::$app->request->post() && $model->load(Yii::$app->request->post())) {

             if(isset($_POST['CandidateForm']['contact'])) {

                                foreach ($_POST['CandidateForm']['contact'] as $key => $value) {

                                    $contact = new ContactInfo();

                                    $contact->user_id = $user->id;

                                    $contact->name = $value['name'];

                                    $contact->relation = $value['relation'];

                                    $contact->phone_no = $value['phone_no'];

                                    $contact->email = $value['email'];

                                    $contact->city = $value['city'];


                                    if ($contact->validate()) {

                                        $contact->save();

                                        $flag = 1;

                                    } else {

                                        print_r($contact->getErrors());

                                        $transaction->rollBack();

                                        die;

                                    }

                                }

                            }

          }

    }






    public function actionAddAdditionalRow(){


        if(\Yii::$app->getRequest()->getIsAjax()) {

            echo $this->renderAjax('_form-batch/additional',array("i" =>$_GET['i']));

            exit;

        } else {

            throw new HttpException(404, 'Unable to resolve the request: candidate/add-additional-row');

        }

    }



[b]//view File _form.php

[/b]





<header class="panel-heading">

        Contact Info.

    </header>

    <br>

    <div class="form-group">

        <button type="button" id="button-add-another" class="btn btn-primary">Add Another</button>

    </div>

    <div class="row col-md-12" id="div-address-form">

        <?php

            if(isset($model->contact)){

                foreach ($model->contact as $key => $value){

        ?>

            <div class="col-md-12 well" id="<?= "div".$i ?>" style="padding: 10px;">

                <div class="row">

                    <div class="col-lg-12 text-right"><a href="javascript:void(0)" id="<?= $i ?>"><i class="fa fa-times" aria-hidden="true"></i></a></div>

                </div>

                <div class="row">

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

                        <div class="form-group">

                            <label class="control-label">Name</label>

                            <input type="text" id="candidateform-<?php echo $i?>-name" class="form-control" name="CandidateForm[contact][<?php echo $i?>][name]" value="<?= $value->name ?>" required>

                        </div>

                    </div>

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

                        <div class="form-group">

                            <label class="control-label">Relation</label>

                            <input type="text" id="candidateform-<?php echo $i?>-relation" class="form-control" name="CandidateForm[contact][<?php echo $i?>][relation]" value="<?= $value->relation ?>">

                        </div>

                    </div>

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

                        <div class="form-group">

                            <label class="control-label">Phone No</label>

                            <input type="text" id="candidateform-<?php echo $i?>-phone_no" class="form-control" name="CandidateForm[contact][<?php echo $i?>][phone_no]" value="<?= $value->phone_no ?>">

                        </div>

                    </div>

                </div>

                <div class="row">

                    <div class="col-lg-6">

                        <div class="form-group">

                            <label class="control-label">Email</label>

                            <input type="text" id="candidateform-<?php echo $i?>-email" class="form-control" name="CandidateForm[contact][<?php echo $i?>][email]" value="<?= $value->email ?>">

                        </div>

                    </div>

                    <div class="col-lg-6">

                        <div class="form-group">

                            <label class="control-label">City</label>

                            <input type="text" id="candidateform-<?php echo $i?>-city" class="form-control" name="CandidateForm[contact][<?php echo $i?>][city]" value="<?= $value->city ?>">

                        </div>

                    </div>

                </div>

            </div>


             <?php

                $this->registerJs("

                    $(document).on('click', '#".$i."', function(){

                    $('#div".$i."').remove();

                });");

             ?>


        <?php $i = $i + 1;

                }

            }else{

        ?>

            <div class="col-md-12 well" id="<?= "div".$i ?>" style="padding: 10px;">

                <div class="row">

                    <div class="col-lg-12 text-right"><a href="javascript:void(0)" id="<?= $i ?>"><i class="fa fa-times" aria-hidden="true"></i></a></div>

                </div>

                <div class="row">

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

                        <div class="form-group">

                            <label class="control-label">Name</label>

                            <input type="text" id="candidateform-<?php echo $i?>-name" class="form-control" name="CandidateForm[contact][0][name]" required>

                        </div>

                    </div>

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

                        <div class="form-group">

                            <label class="control-label">Relation</label>

                            <input type="text" id="candidateform-<?php echo $i?>-relation" class="form-control" name="CandidateForm[contact][0][relation]">

                        </div>

                    </div>

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

                        <div class="form-group">

                            <label class="control-label">Phone No</label>

                            <input type="text" id="candidateform-<?php echo $i?>-phone_no" class="form-control" name="CandidateForm[contact][0][phone_no]">

                        </div>

                    </div>

                </div>

                <div class="row">

                    <div class="col-lg-6">

                        <div class="form-group">

                            <label class="control-label">Email</label>

                            <input type="text" id="candidateform-<?php echo $i?>-email" class="form-control" name="CandidateForm[contact][0][email]">

                        </div>

                    </div>

                    <div class="col-lg-6">

                        <div class="form-group">

                            <label class="control-label">City</label>

                            <input type="text" id="candidateform-<?php echo $i?>-city" class="form-control" name="CandidateForm[contact][0][city]">

                        </div>

                    </div>

                </div>

            </div>


         <?php } ?>

    </div>


<?php

$this->registerJs("

    var i  = ".$i."+1;

     $(document).on('click', '#button-add-another', function(){

        $.ajax({

            url: '".\Yii::$app->urlManager->createUrl(['candidates/add-additional-row'])."?i='+i,

            type: 'post',

            data: $('#".$form->id. "').serialize(),

            dataType: 'html',

            success: function(data) {

                i++;

                $('#div-address-form').append(data);

            },

        });

    });


    $(document).on('click', '#".$i."', function(){

        $('#div".$i."').remove();

    });

");

?>




[size="3"][b]//another form _form-batch/additional.php

[/b][/size]





<div class="col-md-12 well" id="<?= "div".$i ?>" style="padding: 10px;">

        <div class="row">

            <div class="col-lg-12 text-right"><a href="javascript:void(0)" id="<?= $i ?>"><i class="fa fa-times" aria-hidden="true"></i></a></div>

        </div>

        <div class="row">

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

                <div class="form-group">

                    <label class="control-label">Name</label>

                    <input type="text" id="candidateform-<?php echo $i?>-name" class="form-control" name="CandidateForm[contact][<?php echo $i?>][name]" required>

                </div>

            </div>

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

                <div class="form-group">

                    <label class="control-label">Relation</label>

                    <input type="text" id="candidateform-<?php echo $i?>-relation" class="form-control" name="CandidateForm[contact][<?php echo $i?>][relation]">

                </div>

            </div>

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

                <div class="form-group">

                    <label class="control-label">Phone No</label>

                    <input type="text" id="candidateform-<?php echo $i?>-phone_no" class="form-control" name="CandidateForm[contact][<?php echo $i?>][phone_no]">

                </div>

            </div>

        </div>

        <div class="row">

            <div class="col-lg-6">

                <div class="form-group">

                    <label class="control-label">Email</label>

                    <input type="text" id="candidateform-<?php echo $i?>-email" class="form-control" name="CandidateForm[contact][<?php echo $i?>][email]">

                </div>

            </div>

            <div class="col-lg-6">

                <div class="form-group">

                    <label class="control-label">City</label>

                    <input type="text" id="candidateform-<?php echo $i?>-city" class="form-control" name="CandidateForm[contact][<?php echo $i?>][city]">

                </div>

            </div>

        </div>

    </div>


<?php

$this->registerJs("

    $(document).on('click', '#".$i."', function(){

        $('#div".$i."').remove();

    });

");

?>




Thanks for all the help to both, i was overthinking some stuff but i’ve finally been able to do what i wanted (at least a part of it). I was a bit confused because i was generating the inputs using ActiveForm inside a new view and appending them to the “original” view, but that didn’t seem right to me. What i didn’t realize (forgot about it) was that i could just generate active html inputs (Html::activeTextInput() and others), and widgets without ActiveForm, so i’m doing that right now and the values get submitted properly.

I still don’t know how to do the query and apply filters with all the criteria from each input, but i’ll think about it a bit. Will post my implementation later on today in case it’s useful for anyone else.