简体   繁体   中英

Update amount and total fields based on values entered in yii2

I am working on an invoice in yii2. The invoice has items added dynamically using the wbraganca\\dynamicform\\DynamicFormWidget . These items each has quantity and price inputs, and an amount updated automatically based on the values of quantity and price . At the bottom of the invoice, is the total which is the sum of the amount of each item of the invoice. The total field is also updated automatically when any of the input fields ie quantity and price changes. I have tried coming up with a Javascript code that I got online but this only updates the first item amount but the rest are not working. Below is my code for the form...

_form.php

<?php

use yii\helpers\Html;
use kartik\widgets\ActiveForm;
use wbraganca\dynamicform\DynamicFormWidget;
use kartik\widgets\DatePicker;
use yii\helpers\Url;
use yii\helpers\ArrayHelper;
use app\models\Tenant;
use app\models\InvoiceItems;
use app\models\FinancialAccounts;

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

<?php
/* start getting the totalamount */
$script = <<<EOD
    var getAmount = function() {

        var qnty = $(".qnty").val();
        var price = $(".price").val();
        var amount = 0;

        amount = parseInt(qnty) * parseInt(price);

        //Assign the sum value to the field
        $(".amount").val(amount);
    };

    $(".price").on("change", function() {
        getAmount();
    });
EOD;
$this->registerJs($script);
/*end getting the totalamount */
?>

<div class="invoices-form">

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

    <fieldset>

        <legend>Invoice Details</legend>

        <div class="form-group kv-fieldset-inline">
            <div class="col-sm-3">
                <?= $form->field($modelInvoice, 'tenant_id')->dropDownList(ArrayHelper::map(Tenant::find()->select(['tenant_id', 'first_name', 'last_name', 'address'])->all(), 'tenant_id', 'displayName'),
                [
                    'prompt'=>'Select Tenant', 'class' => 'form-control inline-block',
                    'onchange'=>'
                        $.post( "'.Yii::$app->urlManager->createUrl('lease/list-lease?tenant_id=').'"+$(this).val(), function( data ) {
                          $( "select#lease" ).html( data );
                        });
                    '
                ]) ?>
            </div>

            <div class="col-sm-3">
                <?php 
                $dataLease=ArrayHelper::map(\app\models\Lease::find()->asArray()->all(), 'lease_id', 'leaseDetails');
                echo $form->field($modelInvoice, 'lease')
                    ->dropDownList(
                        $dataLease,           
                        ['id'=>'lease']
                    );
            ?>
            </div>

            <div class="col-sm-3">
                <?= $form->field($modelInvoice, 'date')->widget(DatePicker::classname(), ['options' => ['placeholder' => 'Enter Invoice date ...'], 'pluginOptions' => ['autoclose'=>true, 'format' => 'yyyy-mm-dd', 'endDate' => '0d']]) ?>
            </div>

            <div class="col-sm-3">
                <?= $form->field($modelInvoice, 'due_date')->widget(DatePicker::classname(), ['options' => ['placeholder' => 'Enter due date ...'], 'pluginOptions' => ['autoclose'=>true, 'format' => 'yyyy-mm-dd', 'startDate' => '0d']]) ?>
            </div>

            <div class="col-sm-3">
                <?= $form->field($modelInvoice, 'invoice_number')->textInput(['maxlength' => true]) ?>
            </div>
        </div>        

    </fieldset>

    <fieldset>

        <legend>Invoice Line Items</legend>

        <?php DynamicFormWidget::begin([
            'widgetContainer' => 'dynamicform_wrapper',
            'widgetBody' => '.container-items',
            'widgetItem' => '.invoice-item',
            'limit' => 10,
            'min' => 1,
            'insertButton' => '.add-item',
            'deleteButton' => '.remove-item',
            'model' => $modelsInvoiceItem[0],
            'formId' => 'dynamic-form',
            'formFields' => [
                'Items',
            ],
        ]); ?>

        <table class="table table-bordered table-striped">
            <thead>
                <tr>
                    <th>Invoice Item</th>
                    <th>Description</th>
                    <th>Quantity</th>
                    <th>Price (Kshs)</th>
                    <th>Account</th>
                    <th>Amount</th>
                    <th class="text-center" style="width: 5%;">
                        <button type="button" class="add-item btn btn-success btn-xs"><span class="fa fa-plus"></span></button>
                    </th>
                </tr>
            </thead>
            <tbody class="container-items">
            <?php foreach ($modelsInvoiceItem as $indexItem => $modelInvoiceItem): ?>
                <tr class="invoice-item">
                    <td class="vcenter">
                        <?php
                            // necessary for update action.
                            if (! $modelInvoiceItem->isNewRecord) {
                                echo Html::activeHiddenInput($modelInvoiceItem, "[{$indexItem}]id");
                            }
                        ?>
                        <?= $form->field($modelInvoiceItem, "[{$indexItem}]item_id")->label(false)->dropDownList(ArrayHelper::map(InvoiceItems::find()->select(['item_id', 'item'])->all(), 'item_id', 'item'),['class' => 'form-control inline-block', 'prompt'=>'Select Invoice Item']) ?>
                    </td>
                    <td class="vcenter">
                        <?= $form->field($modelInvoiceItem, "[{$indexItem}]desc")->label(false)->textInput(['maxlength' => true]) ?>
                    </td>
                    <td class="vcenter">
                        <?= $form->field($modelInvoiceItem, "[{$indexItem}]qnty")->label(false)->textInput(['class' => 'qnty']) ?>
                    </td>
                    <td class="vcenter">
                        <?= $form->field($modelInvoiceItem, "[{$indexItem}]price")->label(false)->textInput(['class' => 'price']) ?>
                    </td>
                    <td class="vcenter">
                        <?= $form->field($modelInvoiceItem, "[{$indexItem}]account_id")->label(false)->dropDownList(ArrayHelper::map(FinancialAccounts::find()->select(['account_id', 'account_name'])->all(), 'account_id', 'account_name'),['class' => 'form-control inline-block', 'prompt'=>'Select Account']) ?>
                    </td>
                    <td class="vcenter">
                        <?= $form->field($modelInvoiceItem, "[{$indexItem}]amount")->label(false)->textInput(['class'=>'amount','readOnly'=> true]) ?>
                    </td>
                    <td class="text-center vcenter" style="width: 5%; verti">
                        <button type="button" class="remove-item btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
                    </td>
                </tr>
             <?php endforeach; ?>
            </tbody>
            <tbody>
                <tr>
                     <td></td>
                     <td></td>
                     <td></td>
                     <td></td>
                     <td>Total</td>
                     <td class="total">
                         <?= $form->field($modelInvoice, "total")->label(false)->textInput(['class'=>'total','readOnly'=> true]) ?>
                     </td>
                     <td></td>
                 </tr>
            </tbody>
        </table>

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

    </fieldset>


    <div class="col-sm-offset-3 col-sm-9">
        <?= Html::submitButton($modelInvoice->isNewRecord ? 'Create' : 'Update', ['class' => $modelInvoice->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
    </div>

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

</div>

Specifically, this is the Javascript code

<?php
/* start getting the totalamount */
$script = <<<EOD
    var getAmount = function() {

        // var items = $(".item");
        // var qnty = $(elem).find(".qnty").val();
        var qnty = $(".qnty").val();
        var price = $(".price").val();
        // var price = $(elem).find(".price").val();
        var amount = 0;

        amount = parseInt(qnty) * parseInt(price);

        // items.each(function (index, elem) {
        //     var priceValue = $(elem).find(".sumPart").val();
        //     //Check if priceValue is numeric or something like that
        //     sum = parseInt(sum) + parseInt(priceValue);
        // });
        //Assign the sum value to the field
        $(".amount").val(amount);
    };

    //Bind new elements to support the function too
    $(".price").on("change", function() {
        getAmount();
    });
EOD;
$this->registerJs($script);
/*end getting the totalamount */
?>

And here is the screenshot of the form that I am working with: 发票截图

I am not good with Javascript hence I don't understand most of the code but I get the idea and flow of information. Please assist me on what I can do here. Thanks.

You use $ sign with class selector (".class"). So you get set in return.

jQuery val method:

Get the current value of the first element in the set of matched elements or set the value of every matched element.

You can use row index to make different elements unique.

Try

$(".price").on("change", function(event) {
    getAmount(event);
});

function getAmount(event) {
    var priceElement = event.target;
    // extract row index from priceElement's id
    // use row index to find elements with id selector ("#elementId")
};

Based on @Sui Dream solution above, and from researching other places on the internet, this is what I was able to do finally. I only updated the script and everything worked fine:

<?php
/* start getting the totalamount */
$script = <<<EOD
    var getAmount = function() {

        var items = $(".invoice-item");
        var amount = 0;
        var total = 0;

        items.each(function (index, elem) {
            var qnty = $(elem).find(".qnty").val();
            var price = $(elem).find(".price").val();
            //Check if qnty and price are numeric or something like that
            amount = parseInt(qnty) * parseInt(price);

            //Assign the amount value to the field
            $(elem).find(".amount").val(amount);

            var amountValue = $(elem).find(".amount").val();

            total = parseInt(total) + parseInt(amountValue);

            $(".total").val(total);
        });
    };

    //Bind new elements to support the function too
    $(".container-items").on("change", function() {
        getAmount();
    });
EOD;

$this->registerJs($script);
?>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM