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.