Coder Social home page Coder Social logo

wbraganca / yii2-dynamicform Goto Github PK

View Code? Open in Web Editor NEW
430.0 53.0 432.0 87 KB

It is widget to yii2 framework to clone form elements in a nested manner, maintaining accessibility.

License: Other

PHP 34.88% JavaScript 65.12%
yii2-dynamicform yii2-framework yii2-extension

yii2-dynamicform's Introduction

yii2-dynamicform

Latest Version Software License Total Downloads

It is widget to yii2 framework to clone form elements in a nested manner, maintaining accessibility. yii2-dynamicform

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist wbraganca/yii2-dynamicform "*"

or add

"wbraganca/yii2-dynamicform": "*"

to the require section of your composer.json file.

Demos

Usage

Hypothetical Scenario

Database

The View

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use wbraganca\dynamicform\DynamicFormWidget;
?>

<div class="customer-form">

    <?php $form = ActiveForm::begin(['id' => 'dynamic-form']); ?>
    <div class="row">
        <div class="col-sm-6">
            <?= $form->field($modelCustomer, 'first_name')->textInput(['maxlength' => true]) ?>
        </div>
        <div class="col-sm-6">
            <?= $form->field($modelCustomer, 'last_name')->textInput(['maxlength' => true]) ?>
        </div>
    </div>

    <div class="panel panel-default">
        <div class="panel-heading"><h4><i class="glyphicon glyphicon-envelope"></i> Addresses</h4></div>
        <div class="panel-body">
             <?php DynamicFormWidget::begin([
                'widgetContainer' => 'dynamicform_wrapper', // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
                'widgetBody' => '.container-items', // required: css class selector
                'widgetItem' => '.item', // required: css class
                'limit' => 4, // the maximum times, an element can be cloned (default 999)
                'min' => 1, // 0 or 1 (default 1)
                'insertButton' => '.add-item', // css class
                'deleteButton' => '.remove-item', // css class
                'model' => $modelsAddress[0],
                'formId' => 'dynamic-form',
                'formFields' => [
                    'full_name',
                    'address_line1',
                    'address_line2',
                    'city',
                    'state',
                    'postal_code',
                ],
            ]); ?>

            <div class="container-items"><!-- widgetContainer -->
            <?php foreach ($modelsAddress as $i => $modelAddress): ?>
                <div class="item panel panel-default"><!-- widgetBody -->
                    <div class="panel-heading">
                        <h3 class="panel-title pull-left">Address</h3>
                        <div class="pull-right">
                            <button type="button" class="add-item btn btn-success btn-xs"><i class="glyphicon glyphicon-plus"></i></button>
                            <button type="button" class="remove-item btn btn-danger btn-xs"><i class="glyphicon glyphicon-minus"></i></button>
                        </div>
                        <div class="clearfix"></div>
                    </div>
                    <div class="panel-body">
                        <?php
                            // necessary for update action.
                            if (! $modelAddress->isNewRecord) {
                                echo Html::activeHiddenInput($modelAddress, "[{$i}]id");
                            }
                        ?>
                        <?= $form->field($modelAddress, "[{$i}]full_name")->textInput(['maxlength' => true]) ?>
                        <div class="row">
                            <div class="col-sm-6">
                                <?= $form->field($modelAddress, "[{$i}]address_line1")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-6">
                                <?= $form->field($modelAddress, "[{$i}]address_line2")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                        <div class="row">
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]city")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]state")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]postal_code")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                    </div>
                </div>
            <?php endforeach; ?>
            </div>
            <?php DynamicFormWidget::end(); ?>
        </div>
    </div>

    <div class="form-group">
        <?= Html::submitButton($modelAddress->isNewRecord ? 'Create' : 'Update', ['class' => 'btn btn-primary']) ?>
    </div>

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

</div>

Javascript Events

$(".dynamicform_wrapper").on("beforeInsert", function(e, item) {
    console.log("beforeInsert");
});

$(".dynamicform_wrapper").on("afterInsert", function(e, item) {
    console.log("afterInsert");
});

$(".dynamicform_wrapper").on("beforeDelete", function(e, item) {
    if (! confirm("Are you sure you want to delete this item?")) {
        return false;
    }
    return true;
});

$(".dynamicform_wrapper").on("afterDelete", function(e) {
    console.log("Deleted item!");
});

$(".dynamicform_wrapper").on("limitReached", function(e, item) {
    alert("Limit reached");
});

The Controller (sample code)

<?php

namespace app\controllers;

use Yii;
use app\models\Customer;
use app\models\CustomerSearch;
use app\models\Address;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use app\base\Model;
use yii\web\Response;
use yii\widgets\ActiveForm;
use yii\helpers\ArrayHelper;

/**
 * CustomerController implements the CRUD actions for Customer model.
 */
class CustomerController extends Controller
{
    ...

    /**
     * Creates a new Customer model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $modelCustomer = new Customer;
        $modelsAddress = [new Address];
        if ($modelCustomer->load(Yii::$app->request->post())) {

            $modelsAddress = Model::createMultiple(Address::classname());
            Model::loadMultiple($modelsAddress, Yii::$app->request->post());

            // ajax validation
            if (Yii::$app->request->isAjax) {
                Yii::$app->response->format = Response::FORMAT_JSON;
                return ArrayHelper::merge(
                    ActiveForm::validateMultiple($modelsAddress),
                    ActiveForm::validate($modelCustomer)
                );
            }

            // validate all models
            $valid = $modelCustomer->validate();
            $valid = Model::validateMultiple($modelsAddress) && $valid;
            
            if ($valid) {
                $transaction = \Yii::$app->db->beginTransaction();
                try {
                    if ($flag = $modelCustomer->save(false)) {
                        foreach ($modelsAddress as $modelAddress) {
                            $modelAddress->customer_id = $modelCustomer->id;
                            if (! ($flag = $modelAddress->save(false))) {
                                $transaction->rollBack();
                                break;
                            }
                        }
                    }
                    if ($flag) {
                        $transaction->commit();
                        return $this->redirect(['view', 'id' => $modelCustomer->id]);
                    }
                } catch (Exception $e) {
                    $transaction->rollBack();
                }
            }
        }

        return $this->render('create', [
            'modelCustomer' => $modelCustomer,
            'modelsAddress' => (empty($modelsAddress)) ? [new Address] : $modelsAddress
        ]);
    }

    /**
     * Updates an existing Customer model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     */
    public function actionUpdate($id)
    {
        $modelCustomer = $this->findModel($id);
        $modelsAddress = $modelCustomer->addresses;

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

            $oldIDs = ArrayHelper::map($modelsAddress, 'id', 'id');
            $modelsAddress = Model::createMultiple(Address::classname(), $modelsAddress);
            Model::loadMultiple($modelsAddress, Yii::$app->request->post());
            $deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsAddress, 'id', 'id')));

            // ajax validation
            if (Yii::$app->request->isAjax) {
                Yii::$app->response->format = Response::FORMAT_JSON;
                return ArrayHelper::merge(
                    ActiveForm::validateMultiple($modelsAddress),
                    ActiveForm::validate($modelCustomer)
                );
            }

            // validate all models
            $valid = $modelCustomer->validate();
            $valid = Model::validateMultiple($modelsAddress) && $valid;

            if ($valid) {
                $transaction = \Yii::$app->db->beginTransaction();
                try {
                    if ($flag = $modelCustomer->save(false)) {
                        if (! empty($deletedIDs)) {
                            Address::deleteAll(['id' => $deletedIDs]);
                        }
                        foreach ($modelsAddress as $modelAddress) {
                            $modelAddress->customer_id = $modelCustomer->id;
                            if (! ($flag = $modelAddress->save(false))) {
                                $transaction->rollBack();
                                break;
                            }
                        }
                    }
                    if ($flag) {
                        $transaction->commit();
                        return $this->redirect(['view', 'id' => $modelCustomer->id]);
                    }
                } catch (Exception $e) {
                    $transaction->rollBack();
                }
            }
        }

        return $this->render('update', [
            'modelCustomer' => $modelCustomer,
            'modelsAddress' => (empty($modelsAddress)) ? [new Address] : $modelsAddress
        ]);
    }

    ...
}

Model Class

<?php

namespace app\base;

use Yii;
use yii\helpers\ArrayHelper;

class Model extends \yii\base\Model
{
    /**
     * Creates and populates a set of models.
     *
     * @param string $modelClass
     * @param array $multipleModels
     * @return array
     */
    public static function createMultiple($modelClass, $multipleModels = [])
    {
        $model    = new $modelClass;
        $formName = $model->formName();
        $post     = Yii::$app->request->post($formName);
        $models   = [];

        if (! empty($multipleModels)) {
            $keys = array_keys(ArrayHelper::map($multipleModels, 'id', 'id'));
            $multipleModels = array_combine($keys, $multipleModels);
        }

        if ($post && is_array($post)) {
            foreach ($post as $i => $item) {
                if (isset($item['id']) && !empty($item['id']) && isset($multipleModels[$item['id']])) {
                    $models[] = $multipleModels[$item['id']];
                } else {
                    $models[] = new $modelClass;
                }
            }
        }

        unset($model, $formName, $post);

        return $models;
    }
}

To zero or more elements (use the following code in your view file)

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use wbraganca\dynamicform\DynamicFormWidget;
?>

<div class="customer-form">

    <?php $form = ActiveForm::begin(['id' => 'dynamic-form']); ?>
    <div class="row">
        <div class="col-sm-6">
            <?= $form->field($modelCustomer, 'first_name')->textInput(['maxlength' => true]) ?>
        </div>
        <div class="col-sm-6">
            <?= $form->field($modelCustomer, 'last_name')->textInput(['maxlength' => true]) ?>
        </div>
    </div>

    <?php DynamicFormWidget::begin([
        'widgetContainer' => 'dynamicform_wrapper', // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
        'widgetBody' => '.container-items', // required: css class selector
        'widgetItem' => '.item', // required: css class
        'limit' => 4, // the maximum times, an element can be added (default 999)
        'min' => 0, // 0 or 1 (default 1)
        'insertButton' => '.add-item', // css class
        'deleteButton' => '.remove-item', // css class
        'model' => $modelsAddress[0],
        'formId' => 'dynamic-form',
        'formFields' => [
            'full_name',
            'address_line1',
            'address_line2',
            'city',
            'state',
            'postal_code',
        ],
    ]); ?>

    <div class="panel panel-default">
        <div class="panel-heading">
            <h4>
                <i class="glyphicon glyphicon-envelope"></i> Addresses
                <button type="button" class="add-item btn btn-success btn-sm pull-right"><i class="glyphicon glyphicon-plus"></i> Add</button>
            </h4>
        </div>
        <div class="panel-body">
            <div class="container-items"><!-- widgetBody -->
            <?php foreach ($modelsAddress as $i => $modelAddress): ?>
                <div class="item panel panel-default"><!-- widgetItem -->
                    <div class="panel-heading">
                        <h3 class="panel-title pull-left">Address</h3>
                        <div class="pull-right">
                            <button type="button" class="remove-item btn btn-danger btn-xs"><i class="glyphicon glyphicon-minus"></i></button>
                        </div>
                        <div class="clearfix"></div>
                    </div>
                    <div class="panel-body">
                        <?php
                            // necessary for update action.
                            if (! $modelAddress->isNewRecord) {
                                echo Html::activeHiddenInput($modelAddress, "[{$i}]id");
                            }
                        ?>
                        <?= $form->field($modelAddress, "[{$i}]full_name")->textInput(['maxlength' => true]) ?>
                        <div class="row">
                            <div class="col-sm-6">
                                <?= $form->field($modelAddress, "[{$i}]address_line1")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-6">
                                <?= $form->field($modelAddress, "[{$i}]address_line2")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                        <div class="row">
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]city")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]state")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]postal_code")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                    </div>
                </div>
            <?php endforeach; ?>
            </div>
        </div>
    </div><!-- .panel -->
    <?php DynamicFormWidget::end(); ?>

    <div class="form-group">
        <?= Html::submitButton($modelAddress->isNewRecord ? 'Create' : 'Update', ['class' => 'btn btn-primary']) ?>
    </div>

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

</div>

yii2-dynamicform's People

Contributors

torvaldz avatar wbraganca avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yii2-dynamicform's Issues

Dropdown reset on clone

Hi -

When you clone elements, in the cloned form the text input fields are empty but the dropdown boxes are pre-selected with the value of the source form. I think it should be reset as well.

--Matt

fail validation

I follow your Demo 1 (address Book) and having a hard time to figure out why my code fails the validation as the customer_id is required.

My use case is create a customer first, save, edit customer , add new address which fail the validation as customer_id field is required for new address. How do I fix the issue ?

Updated: It turns out I must remove the 'customer_id' as required from Address model. Is there another solution ? I prefer to keep customer_id as 'required'

Doesn't work with Kartik Checkbox-X

The following code fixed this issue for me.

       // "kartik-v/yii2-checkbox-x"
        var $hasCheckboxX = $(this).find('[data-krajee-checkboxx]');
        if ($hasCheckboxX.length > 0) {
            $hasCheckboxX.each(function() {
                if ($(this).attr('class') == 'cbx-loading') {
                    var ckxOptions = eval($(this).attr('data-krajee-checkboxx'));
                    $(this).checkboxX(ckxOptions);
                }
            });
        }

Nested widgets

Could you update the "Hypothetical Scenario", "View" and "Controller" to show how to use the nested widget functionality properly?

I'm having trouble figuring out how to save/update nested widget values properly reflecting their relations.

Cant save to DB

Hi, Iam trying this extension. Everything works, but if I want to create new one and save to database, nothing happens. If I add record to DB in sql, I can see it in yii with your extension, but cant update... whats wrong? I mean your example. thanx.

jquery client validation is only invoked in first panel elements

in view

field($modelEducation, "[{$i}]academic_score")->textInput(['maxlength' => true,'class'=>'score']) ?>

in script
$("#acerpeducationdetails-0-academic_score")
$("#acerpeducationdetails-1-academic_score")
$("#acerpeducationdetails-2-academic_score")
and so on in jquery part

$(".score").change(function()
{
$(".score").each(function( index )
{
alert( $( this ).val() );
});
});

here in the first panel when i change the value of acerpeducationdetails-0-academic_score the event gets invoked but for the rest the .change event does not fire

Bug with checkboxes on cloned items

I have found a bug with checkboxes in current version on cloning items.
As you know for each checkbox yii creates hidden input with default {value="0"} and the checkbox itself has default {value="1"}. So we have:

<input type="hidden" name="Tickets[0][class]" value="0">
<input type="checkbox" id="tickets-0-class" class="selectbox" name="Tickets[0][class]" value="1">

But after cloning all cloned items have both input values as {value}, they lose their default value and after that data aren't sent correctly to controller:

<input type="hidden" name="Tickets[0][class]" value>
<input type="checkbox" id="tickets-0-class" class="selectbox" name="Tickets[0][class]" value>

I managed to fix it in 'afterClone' event in this way:

$('#dynamic-widget').on('afterClone' ,function(e, clonedItem) {
  $(this).find('input:hidden').val(0);
  $(this).find('nput:checkbox').val(1);
});

it works for me, but it is not the best solution I guess.
In fact it is not the widget bug but the jquery bug:
http://bugs.jquery.com/ticket/10550
There is described that bug has place in IE but I faced it in Chrome too.

Multiple nested widget example

It's possible to send me any example of deeper scenario with mutiple nested widget?

"Here's could be hypothetical scenario:
A PERSON can have many HOUSES,
each house, can have multiple ROOMS."

Thank you.

how to add form when min limit is 0 in Dynamically Form

@wbraganca Thank you for such a good extension.

I stick at one place when min limit is 0 in dynamic form. I am not getting any option to add form dynamic form when limit is 0.

For example, I have an articles and attachments tables. It is possible that article may have attachments or may not be. As per your development, I must have at least one dynamic form available. so that It can clone. It is good. But I don't want to add any attachment, in that case dynamic form not working. The reason is whenever I click on submit button, it fires validations as I have validation rules for attachments. It means I must have to fill that form. And If I set min limit 0 then No add/delete button or dynamic form displayed.

So What should I do to avoid these cases. I don't know you consider these cases. Please provide your inputs

Validating additional fields

Hello,

Very good extension!
I've implemented dynamicform in my project, but looks like it doesn't validate the additional fields created (for example if I click on [+] then try to submit form, only the initial form validates.)

Please advice! Thank you!

Datepicker problem

Hi!

You suggested me to switch from yii datepicker to kartik datepicker, and for some reason the datepicker for cloned form fields is not working.

I'm definetely using latest versions of everything, I just re-run the composer update..


<?php
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\helpers\URL;

use frontend\models\TitlesList;
use frontend\models\Yesorno;
use frontend\models\Countries;
use frontend\models\EmployeeEmployment;

use kartik\widgets\ActiveForm;
use kartik\widgets\DatePicker;
use kartik\widgets\Select2;
use wbraganca\dynamicform\DynamicFormWidget;
?>
<?php
$form = ActiveForm::begin(['id'=>'registration-step-1','options'=>['class'=>'form-block']]);
?>
<?php
$titleslist = ArrayHelper::map(TitlesList::find()->orderBy('title_order')->all(), 'title_id', 'title_name');
$yesornolist = ArrayHelper::map(Yesorno::find()->orderBy('yesorno_order')->all(), 'yesorno_id', 'yesorno_name');
$countrylist = ArrayHelper::map(Countries::find()->orderBy('country_id')->all(), 'country_id', 'country_name');
?>
<?= Html::activeDropDownList($modelEmployee, 'employee_title', $titleslist, array('class'=>'form-control','prompt'=>'Please Select Title')) ?>
<?= $form -> field ($modelEmployee,'employee_firstname')  ?>  
<?= $form -> field ($modelEmployee,'employee_lastname') ?>
<?= $form -> field ($modelEmployee,'employee_workpermit')->radiolist($yesornolist,['itemOptions' => ['class' =>'radio-inline']]) ?>

<p>Contact Information</p>
<?= $form -> field ($modelEmployee,'employee_email') ?>
<?= $form -> field ($modelEmployee,'employee_phone') ?>
<?= $form -> field ($modelEmployee,'employee_mobile') ?>
<?= $form -> field ($modelEmployee,'employee_address') ?>
<?= $form -> field ($modelEmployee,'employee_town') ?>
<?= $form -> field ($modelEmployee,'employee_country') ?>
<?= $form -> field ($modelEmployee,'employee_postcode') ?>
<p>Education</p>
<?  
//echo $form -> field ($modelEmployee,'employeeQualifications') 
?>
<?php DynamicFormWidget::begin([
                'dynamicItems' => '#form-qualifications',
                'dynamicItem' => '.form-qualifications-item',
                'model' => $modelsQualifications[0],
                'formId' => 'registration-step-1',
                'formFields' => [
                    'employee_employment_position',
                    'employee_employment_start_date',
                    'employee_employment_end_date',
                    'employee_employment_reason',
                    'employee_employment_organisation',
                    'employee_employment_town',
                    'employee_employment_country',
                ],
                'options' => [
                    'limit' => 5,
                ]
            ]); ?>
<div id="form-qualifications">
            <?php foreach ($modelsQualifications as $i => $modelQualifications): ?>
                <div class="form-qualifications-item panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title pull-left">Qualifications</h3>
                        <div class="pull-right">
                            <button type="button" class="clone btn btn-success btn-xs"><i class="glyphicon glyphicon-plus"></i></button>
                            <button type="button" class="delete btn btn-danger btn-xs"><i class="glyphicon glyphicon-minus"></i></button>
                        </div>
                        <div class="clearfix"></div>
                    </div>
                    <div class="panel-body">
                        <?php
                            // necessary for update action.
                            if (!$modelQualifications->isNewRecord) {
                                echo Html::activeHiddenInput($modelQualifications, "[{$i}]id");
                            }
                        ?>
                        <?= $form->field($modelQualifications, "[{$i}]employee_employment_position")->textInput(['maxlength' => 64]) ?>
                        <div class="row">
                            <div class="col-sm-6">
                                <?php
                                    echo $form->field($modelQualifications, "[{$i}]employee_employment_start_date")->widget(DatePicker::classname(), [
                                    'options' => ['placeholder' => 'Please enter employment start date'],
                                    'pluginOptions' => [
                                    'autoclose'=>true,
                                    'format' => 'dd/mm/yyyy'
                                    ]
                                    ]);

                                ?>
                            </div>
                            <div class="col-sm-6">
                                <?php
                                    echo $form->field($modelQualifications, "[{$i}]employee_employment_end_date")->widget(DatePicker::classname(), [
                                    'options' => ['placeholder' => 'Please enter employment end date'],
                                    'pluginOptions' => [
                                    'autoclose'=>true,
                                    'format' => 'dd/mm/yyyy'
                                    ]
                                    ]);

                                ?>
                            </div>
                        </div><!-- .row -->
                        <div class="row">
                            <div class="col-sm-4">
                                <?= $form->field($modelQualifications, "[{$i}]employee_employment_reason")->textInput(['maxlength' => 64]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelQualifications, "[{$i}]employee_employment_organisation")->textInput(['maxlength' => 32]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelQualifications, "[{$i}]employee_employment_town")->textInput(['maxlength' => 15]) ?>
                            </div>
                            <div class="col-sm-4">

                            </div>
                        </div><!-- .row -->
                    </div>
                </div>
            <?php endforeach; ?>
            </div>          
<?php DynamicFormWidget::end(); ?>
<p>Employment in the last two years</p>

<p>Languages</p>

<p>Additional information</p>
<div class="form-group">
        <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
    </div>
<?php
ActiveForm::end();
?>


Please advice
Thanks, D.

Textarea takes default value of first panel when click add new item

I came across one issue, When I click on [+] Add Item button, It is cloning first panel and It is working correctly. But If I have textarea as form element, It takes value of textarea from first panel. It should be blank after Add Item but it is not.

I am attaching screenshot of before and after.

screenshot from 2015-06-02 16 17 08

screenshot from 2015-06-02 16 17 37

Please correct me if wrong anywhere. I am using similar code to address example.

Bootstrap Switch Input renders as raw checkbox on adding lines

Hi, I just found that the switch input keeps on rendering as a raw checkbox on added lines.... I am rendering the form initially with two models and the switchbox is displayed properly for the first two. On clicking the add button a new line is displayed with the form fields all looking ok except for switch input, its displayed as a raw check box.
Do you have an idea why this is happening and how to fix this?
Thanks

Select 2 and DepDrop widgets not working

Hello wbraganca,

First of all thank you for your wonderful widget.

I am using both select 2 and DepDrop in my active form whenever I clicked on add button i was getting the same regex issue which is already raised in the issues list [ no:37].

In that you have added fix to that ticket.I have updated the fix in my end where my regex issue is not coming but still the depdrop is not working .

  1. select2 plugin events are not adding to dynamically added select 2 fields.
  2. Depdrop is not working and it is having weird issue in the new fix that the dependency drop down ajax call is keep on hitting from the moment when i change the parent dropdown value.

Kindly help me on this.

Any help is highly appreciated.

Regards,

Class 'Symfony\Component\DomCrawler\Crawler' not found

this issue was appeared at the first running .
the process stopped at this line: $crawler = new Crawler();
public function run()
{
$content = ob_get_clean();
$crawler = new Crawler();
how can i fix this issue . please.

Doesn't work with IE (9 -> 11)

Works in every other browser.

Cloned template is not rendered properly and jquery events for delete button not wired up.
IE does not support template, tried a couple of polyfills and they did not work.
http://stackoverflow.com/questions/16055275/html-templates-javascript-polyfills

It might be the table.

    <?php $form = ActiveForm::begin(['id' => 'state-form']); ?>

    <?= $form->field($model, 'code')->textInput(['maxlength' => 4]) ?>
    <?= $form->field($model, 'name')->textInput(['maxlength' => 100]) ?>
        <?php DynamicFormWidget::begin([
            'dynamicItems' => '#form-courses',
            'dynamicItem' => '.form-course-item',
            'model' => $modelsStateCourse[0],
            'formId' => 'state-form',
            'formFields' => [
                'course_id'
            ],
            'options' => [
                'min' => 0,
                // 'limit' => 4, // the maximum times, an element can be cloned (default 999)
            ]
        ]); ?>

    <div class="panel panel-default panel-condensed">

        <div class="panel-heading"><h4 class="pull-left">Default Courses for Students</h4>

            <div class="clearfix"></div>
        </div>
        <div class="panel-body">

            <table id="form-courses" class="table table-striped table-bordered table-condensed">
            <thead>
                <tr>
                    <th>Course</th>
                    <th><button type="button" class="clone btn btn-info btn-xs"><i class="glyphicon glyphicon-plus"></i> Add</button>
                </tr>
            </thead>
            <tbody>
            <?php foreach ($modelsStateCourse as $i => $modelStateCourse): ?>
                <tr class="form-course-item">
                    <td>
                        <?= $form->field($modelStateCourse, "[{$i}]course_id")->label(false)->widget(Select2::classname(), [
                              'data' => $courses,
                              'options' => ['placeholder' => 'Select a course ...'],
                              'pluginOptions' => [
                                  'allowClear' => true
                              ],
                          ]) ?>

                    </td>
                    <td class="table-actions">
                            <button type="button" class="delete btn btn-danger btn-xs"><i class="fa fa-remove"></i></button>
                            <?php
                                // necessary for update action.
                                if (! $modelStateCourse->isNewRecord) {
                                    echo Html::activeHiddenInput($modelStateCourse, "[{$i}]id");
                                }
                            ?>
                    </td>
                </tr>
            <?php endforeach; ?>
            </tbody>
            </table>

        </div>

    </div>
    <?php DynamicFormWidget::end(); ?>
    <div class="form-group">
        <?= Html::submitButton($model->isNewRecord ? Yii::t('backend', 'Create') : Yii::t('backend', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
        <?= Html::a('Cancel', ['index'], ['class' => 'btn btn-cancel']) ?>
    </div>

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

Form didn't send information and not corrected work with timepicker widget

Hello, i am trying to use your wudget, and i have two problems^

  1. form didn't send information from first fields group ( $modelsMultipleItem[0]), var dump data example:
    'WorkTime' =>
    array (size=2)
    0 =>
    array (size=3)
    'workDays' => string '' (length=0)
    'workTimeFrom' => string '' (length=0)
    'workTimeTo' => string '' (length=0)
    1 =>
    array (size=3)
    'workDays' => string 'asdasdasd' (length=9)
    'workTimeFrom' => string '22:35' (length=5)
    'workTimeTo' => string '13:48' (length=5)
    image

Second group fields have data.

  1. Timepicker didn't work correct with following group of fields.
    image

It'is have popup picker, second group of fields have not it, on image below.
image

Question - having trouble with actionUpdate

Hi - I'm having trouble getting the actionUpdate to work. In this part of the code from your example:

        $oldIDs = ArrayHelper::map($modelsAddress, 'id', 'id');
        $modelsAddress = Model::createMultiple(Address::classname(), $modelsAddress);
        Model::loadMultiple($modelsAddress, Yii::$app->request->post());
        $deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsAddress, 'id', 'id')));

Could you please tell me what the 'id' parameters in each of the map() represents? For example, if I have a table 'trial' (primary key TRIAL_ID) that has multiple 'stakes' (primary key STAKE_ID with foreign key TRIAL_ID), what would the parameters be for the map functions in the above example?

        $oldIDs = ArrayHelper::map($modelsStake,?, ?);
        $modelsStake = Model::createMultiple(Stake::classname(), $modelsStake);
        Model::loadMultiple($modelsStake, Yii::$app->request->post());
        $deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsStake, ?, ? )));

Multiple nested widgets

Is it possible to create a DynamicFormWidget within a DynamicFormWidget ? I can add the widget within the widget but add and distract buttons all work the same - they remove the outer widgets instances.

This is what I want(example):
1 Parent can have many kids
Many Kids, can have many toys.

I would like to be able to dynamically add kids and then dynamically add toys to each kid. Is this kind of structure/functionality possible with this widget?

DepDrop with type DepDrop::TYPE_SELECT2 is not working dynamically

<?= $form->field($geo_record, "[{$i}]city_id")->widget(DepDrop::className(),
    [
        'data' => ArrayHelper::map(Country::findOne($geo_record->country_id)->geoCities,'id','caption_en'),

        /* this property break DepDrop on dynamic fields. If i remove this string all works fine */
        'type' => DepDrop::TYPE_SELECT2, 

        'select2Options' => ['pluginOptions'=>['allowClear'=>true]],
        'pluginOptions'=>[
            'depends'=>['geo-'.$i.'-country_id'],
            'placeholder' => 'Выберите город...',
            'loadingText' => 'Загрузка списка...',
            'url' => Url::to(['/action/city'])
        ],
    ]
)?>

Error in model?

Thank you for this component. Exactly what was needed. But there is an error:
in the model (app \ base) we return "return $models;"
A check in the controller:
  $ valid = Model :: validateMultiple ($ modelsAddress) && $ valid
but the Model :: validateMultiple () does not return the same boolean ???
This method is somehow returns false.

value attribute not applied for widgetItem children of <input type="text">

Children < input type="text" value="xxx" > elements of widgetItem template attribute do not have their value set in 'value' DOM/property.

If the widgetItem is directly an input, the value property is set

Happens in FF and Chrome so thinking it's expected behaviour though I don't know why.

Possibly related to #19

The default model value (via init() ) of ordinal = 3, rendered html:

<input type="text" id="eventactionstep-0-ordinal" class="form-control" name="EventActionStep[0][ordinal]" value="3">

Example code (and this one works where input is not a child:

            <?php DynamicFormWidget::begin([
                'widgetContainer' => 'steps_container',
                'widgetBody' => '#steps',
                'widgetItem' => '.step',
                'model' => $modelsEventActionStep[0],
                'formId' => 'event-action-form',
                'insertButton' => '.clone',
                'deleteButton' => '.delete',
                'formFields' => [
                    'ordinal',
                    'event_action_id',
                    'action_type',
                    'email_template_id',
                    'script_id',
                    'enabled',
                    'id'
                ],
                'min' => 0,
            ]); ?>

            <div class="panel panel-condensed steps_container">
                <div class="panel-heading">
                    <h3 class="pull-left">Action Steps</h3>

                    <div class="clearfix"></div>
                </div>
                <div class="panel-body">
                    <div id="steps">
                        <?php foreach ($modelsEventActionStep as $i => $modelEventActionStep): ?>
                            <?= Html::activeTextInput($modelEventActionStep, "[{$i}]ordinal",['class' => 'step']) ?>
                        <?php endforeach ?>
                    </div>
                </div>
                <button type="button" class="clone btn btn-info btn-sm"><i
                        class="glyphicon glyphicon-plus"></i> Add Step
                </button>
            </div>
            <?php DynamicFormWidget::end(); ?>

Replace Html::activeTextInput with $form->field, value is not set in DOM value property for input node, as it is rendered within a more complex template, with input as a child

<?= $form->field($modelEventActionStep, "[{$i}]ordinal",['options' => ['class' => 'step']]) ?>

This doesn't work either, input is empty, 'value' DOM property of input node = ""

<div class="step">
<?= Html::activeTextInput($modelEventActionStep, "[{$i}]ordinal") ?>
</div>

yii.jui.AutoComplete

Probably has been asked for before, but I would like to request support for adding multiple AutoComplete widgets from the official developers.
I tried to code this:

<?= $form->field($modelProducto, "[{$i}]concepto")->widget(yii\jui\AutoComplete::classname(), [
    'clientOptions' => [
       'source' => ['USA', 'RUS'],
    ],
    'options' => [
        'class' => 'form-control',
    ],
]) ?>

and the first autocomplete field works, but all the others that you try to add don't...
Seems like the javascript that attaches the autocomplete functionality to the other fields doesn't update itself or something, as well as, probably, the CSS classes...

The models desappear when "enableClientValidation" to false

In the ActiveForm config, if I put enableClientValidation to false, and then there are errors in the models, the models don't appear in the form.

I have the same problem in the create scenario : if before I declare some models with attributes, they don't appear in the form.

How to make it work like in the update scenario ?


More informations : it's the javascript of the widget which delete the items. If I don't use the widget it appears.


Thank you

Is this extenstion working nw ??

I'm getting this error

Argument 1 passed to DOMDocument::importNode() must be an instance of DOMNode, null given, called in C:\xampp\htdocs\iso2\vendor\yiisoft\yii2\base\Widget.php on line 73 and defined

Any help,thanks alot

Controller code example

Really great ext! Thank you. Works fine.
But may be you can show example code for controller?

For example, I think, that simple solution is

public function actionCreate()
{
    $model = new Offer(['scenario' => Offer::SCENARIO_CREATE]);
    $urls = [new OfferUrl()]; // <= this var is $modelsMultipleItem from your example

    if (Yii::$app->request->isPost) {
        // may be better?
        $urls = [];
        $urlsCount = count(Yii::$app->request->post('OfferUrl',[]));
        if ($urlsCount == 0) $urlsCount = 1;
        for ($i = 1; $i <= $count; $i++) $urls[] = new OfferUrl();
        // may be better? END
        $dataLoaded = $model->load(Yii::$app->request->post()) && Model::loadMultiple($urls, Yii::$app->request->post());
        $dataValidated = $model->validate() && Model::validateMultiple($urls);
    } else {
        $dataLoaded = false;
        $dataValidated = false;
    }
    if ($dataLoaded && $dataValidated) {
        foreach ($urls as $url) $model->addUrl($url);
        $model->save(false);
        return $this->redirect(['view', 'id' => $model->id]);
    } else {
        return $this->render('create', [
            'model' => $model,
            'urls' => $urls
        ]);
    }
}

Now I am extend \yii\base\Model and add createMultiple method which extract count of models from $_POST automatically by class name and create same amout of models. Now I use

public function actionCreate()
{
    $model = new Offer(['scenario' => Offer::SCENARIO_CREATE]);
    $urls = [new OfferUrl()]; // <= this var is $modelsMultipleItem from your example

    if (Yii::$app->request->isPost) {
        // may be better?
        $urls = Model::createMultiple(new OfferUrl());
        // may be better? END
        $dataLoaded = $model->load(Yii::$app->request->post()) && Model::loadMultiple($urls, Yii::$app->request->post());
        $dataValidated = $model->validate() && Model::validateMultiple($urls);
    } else {
        $dataLoaded = false;
        $dataValidated = false;
    }
    if ($dataLoaded && $dataValidated) {
        foreach ($urls as $url) $model->addUrl($url);
        $model->save(false);
        return $this->redirect(['view', 'id' => $model->id]);
    } else {
        return $this->render('create', [
            'model' => $model,
            'urls' => $urls
        ]);
    }
}

May be you have better solution?

P.S. Sorry for my english

Issue with kartik-v Select2 widget

After adding one more item to dynamic form - the Select2 widget appears with style="display:none".
Also returns error in console: The select2('destroy') method was called on an element that is not using Select2.
image

Add 'beforeRemove' event

It would be great if I can check whether any input was filled before remove item.
I will be able to notify user with confirmation window then.
So I suggest to add 'beforeRemove' event.

Init function not called when loading form via ajax

I want to use this form in a modal - where the form is loaded via ajax. When doing so, the init function does not get called which results in an error when I try to Insert New Uncaught TypeError: $toclone.clone is not a function. My form works perfectly ok on a normal page load, just not in this scenario. Is there at least a way to call the init function manually for the ajax scenario?

Grouped Select2 WIDGET

Dears,

I tried to add Grouped Select2 WIDGET but no data display, if i remove grouping it;s worked,

Any Helps?

Thanks

Kartik Select2 issue

I have a dynamic form with a Kartik select 2 widget reading data from an ajax page like this:

$initScriptLine = <<< SCRIPT
function (element, callback) {
    var id=\$(element).val();
    if (id !== "") {
        \$.ajax("{$urlLine}?id=" + id, {
            dataType: "json"
        }).done(function(data) {  callback(data.results);});
    }
}
SCRIPT;

$form->field($modelOrderLines, "[{$i}]product_id")->widget(Select2::classname(), [
     'size'=>'sm',
     'pluginOptions' => [
          'ajax' => [
               'url' => \yii\helpers\Url::to(['productlist']),
               'dataType' => 'json',
               'data' => new JsExpression('function(term,page) { return {search:term}; }'),
               'results' => new JsExpression('function(data,page) { return {results:data.results}; }'),
          ],
          'initSelection' => new JsExpression($initScriptLine),
          'allowClear' => true,
          'minimumInputLength' => 3,
          'placeholder'=>'Seleziona un prodotto...'
     ],
     'pluginEvents' => [
          'change' => 'function(data) { productdetails(data); }',
     ]
]);

And a Kartik MaskMoney widget like this:

$form->field($modelOrderLines, "[{$i}]price")->widget(MaskMoney::classname(), [
     'options'=>['onchange'=>'updatetotals()'],
     'pluginOptions' => [
          'prefix' => yii::$app->session['currency_sign'] . " ",
          'thousands' => yii::$app->session['thousand_sep'],
          'decimal' => yii::$app->session['decimal_sep'],
          'precision' => yii::$app->session['decimals'],
          'allowNegative' => true,
     ],
]);

After adding a new form line the previous select widget change the displayed text and the MaskMoney input reset to 0,00.

Tnx

Call to undefined method app\models\Model::loadMultiple()

in C:\xampp\htdocs***\models\Model.php at line 26
public static function createMultiple($modelClass, $multipleModels = [])
{
$model = new $modelClass;
$formName = $model->formName();
$post = Yii::$app->request->post($formName);
$models = [];

    if (! empty($multipleModels)) {
        $keys = array_keys(ArrayHelper::map($multipleModels, 'acctid', 'acctid'));
        $multipleModels = array_combine($keys, $multipleModels);
    }

    if ($post && is_array($post)) {
        foreach ($post as $i => $item) {
            if (isset($item['id']) && !empty($item['id']) && isset($multipleModels[$item['id']])) {
                $models[] = $multipleModels[$item['id']];
            } else {
                $models[] = new $modelClass;
            }
  1. yii\base\ErrorHandler::handleError(2, 'array_combine(): Both parameters...', 'C:\xampp\htdocs\ituml\models\Mod...', 26, ...)

I can't find a solution to this problem, this is on actionUpdate(). Please help. Thanks.

Can't create a hidden field with value

It is impossible to add a hidden field for each cloned element.

It only works for the initial element, for all others the value is removed. I even tried to write it in plain html, even then it would remove the value. This is really weird.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.