Kamil Cierczek
Kamil Cierczek

Reputation: 51

Using yii2\jui widgets on dynamically created fileds

I'm writing a project for my studies in yii2. I've got an issue with manging widgets in view.

I've got a form with inputs thats describe an invoice. One of the inputs is binded with DataPicker from yii2\jui another input is binded with AutoComplete from yii2\jui. So basicly for this the code looks like:

$contractors = app\models\Contractor::find()
->select('contractorId as id, contractorShortName as label, contractorShortName as value')
->asArray()
->all();
/.../

<tr>
    <td>
        <?= DatePicker::widget([
            'name' => 'costBillDate[]',
            'language' => 'pl', 
            'dateFormat' => 'yyyy-MM-dd'
        ]) ?>
    </td>
    <td><?= AutoComplete::widget(
            'clientOptions' =>[
            'source' => $contractors,
            'autofill' => 'true',
            'select' => new JsExpression("function( event, ui ) {
                        $($(this).parent().find('input[name=\"contractorId[]\"]')).val(ui.item.id);
                        }")
        ],]) ?>
        <?= Html::hiddenInput('contractorId[]', "", []) ?>
    </td>
//other inputs
    <td class="text-center delete"><div class="glyphicon glyphicon-trash"></div></td>
</tr>

The code above is simple and basicly works. So under the table I added a button that replicate the row from table to insert more documents info to database. And for each row I add a script to delete this row.

//Dynamically creation of a row
$this->registerJs('$("#add-bill").on("click",function(){'
    . '$("#costs-bills").append(\''
    . '<tr>'
    . Html::tag("td", DatePicker::widget([
        'name' => 'costBillDate[]',
        'language' => 'pl',
        'dateFormat' => 'yyyy-MM-dd'
     ]))
    . '<td>'
    . AutoComplete::widget([
        'clientOptions' =>[
            'source' => $contractors,
            'autofill' => 'true',
            'select' => new JsExpression("function( event, ui ) {
                $($(this).parent().find('input[name=\"contractorId[]\"]')).val(ui.item.id);
                }")
            ],])
            . Html::hiddenInput('contractorId[]', "", [])
            . '</td>'
            . '<td class="text-center delete"><div class="glyphicon glyphicon-trash"></div></td>'
            . '</tr>'
            . '\');'

             //binding function to created span
            . '$(".delete").on("click",function(){
            var $killrow = $(this).parent("tr");
            $killrow.addClass("danger");
            $killrow.fadeOut(2000, function(){
            $(this).remove();
            });})'
            . '})
');

//Binding delete function to span for static row
$this->registerJs('$(".delete").on("click",function(){
        var $killrow = $(this).parent("tr");
        $killrow.addClass("danger");
        $killrow.fadeOut(2000, function(){
        $(this).remove();
        });})
');

#add-bill is id of a button.

#costs-bills is id of table in which I have the form.

The effect of above code: - I can add rows to table; - I can delete chosen rows from table.

THE PROBLEM: If I add the row to table with dynamically created inputs DataPicker and AutoComplete in that (dynamically created) row doesn't work. They behave as normal textInputs.

I don't know what to do.

Upvotes: 4

Views: 1268

Answers (1)

Kamil Cierczek
Kamil Cierczek

Reputation: 51

Problem solved. Correct JS code:

$this->registerJs('
    $("#add-bill").on("click", function(){
        $("#costs-bills").append(\'<tr>'
        . Html::tag("td", Html::textInput("costBillDate[]","", ['class' => 'dp']))
        . '<td>'
        . Html::textInput("", "", ['class' => 'ac'])
        . Html::hiddenInput("contractorId[]")
        . '</td>'
        . Html::tag("td", Html::tag("div", "", ['class' => 'glyphicon glyphicon-trash']) , ['class' => 'text-center delete'])
        . '</tr>\');
        $(".delete").on("click", function(){
            var $killrow = $(this).parent("tr");
            $killrow.addClass("danger");
            $killrow.fadeOut(2000, function(){
                $(this).remove();
            });
        });

        $("#costs-bills .dp").datepicker();
        $("#costs-bills .ac").autocomplete(
        {
            source:'
            . json_encode($contractors) . ',
            select: function(event, ui) {
                $($(this).parent().find(\'input[name="contractorId[]"]\')).val(ui.item.id);
            }
        });
    });

    $(".delete").on("click",function(){
        var $killrow = $(this).parent("tr");
        $killrow.addClass("danger");
        $killrow.fadeOut(2000, function(){
        $(this).remove();
        });
    })'
);

EDIT:
Some exlanation for th code above. I'm guessing that all of yii2\jui widgets can be called ONLY before (document).ready() event. If the widget is called after page being loaded the result is ILLEGAL pointer in JS console. The yii2\jui is a wrapper for standard jQuery widget, basicly.

The solution of my problem was to replece in JS script for #add-bill onClick event lines that ware calling yii2\jui widgets with standard text inputs with some calsses (in the code above dp for DataPicker input, ac for AutoComplete input). When a row of inputs was successfully added to DOM I just needed to bind my textInputs with datatpicker() and autocomplete() methods of jQuery.

I'm not sure if my explanation is correct, but code above works as it should.

Kind regards,
Kamil

Upvotes: 1

Related Questions