Calling Javascript from dynamic form button in yii

2019-08-22 08:52发布

问题:

In Yii2 Dynamic form, I have add-item and remove-item button to add a new row or remove a particular row. What I want is to call a javascript function on click of the remove item button.

Dynamic Form Code -

<?= $form->field($modelsProductsales, "[{$i}]productname")->widget(Select2::classname(), [
'data' => ArrayHelper::map(Productbatch::find()->orderBy('productname')->all(),'productname','productname'),
'language' => 'en',
'options' => ['placeholder' => 'Select Product', 'onchange' => 'getHsndetails($(this))'],
'pluginOptions' => [
    'allowClear' => true
],
])->label(false);
?>

<?= $form->field($modelsProductsales, "[{$i}]batchno")->widget(DepDrop::classname(), [
'options' => ['onload' => 'getProdValues($(this))','onchange' => 'getItemID($(this))'],
'pluginOptions'=>[
    'depends'=> [Html::getInputID($modelsProductsales, "[{$i}]productname")],
    'placeholder'=>'Batch',
    'url'=>Url::to(['/invoice/bills/subcat'])
]
])->label(false); ?>

<?= $form->field($modelsProductsales, "[{$i}]expdate")->label(false)->textInput(['maxlength' => true,'placeholder' => 'ExpDate','readOnly'=>true]) ?>

<?= $form->field($modelsProductsales, "[{$i}]mrp")->label(false)->textInput(['maxlength' => true,'class' => 'mrp','placeholder' => 'MRP']) ?>

<?= $form->field($modelsProductsales, "[{$i}]rate")->label(false)->textInput(['maxlength' => true,'class' => 'rate','placeholder' => 'Rate']) ?>

<?= $form->field($modelsProductsales, "[{$i}]qty")->label(false)->textInput(['maxlength' => true,'class' => 'qty','placeholder' => 'Qty']) ?>

<?= $form->field($modelsProductsales, "[{$i}]free")->label(false)->textInput(['maxlength' => true,'class' => 'free','placeholder' => 'Free']) ?>


<?= $form->field($modelsProductsales, "[{$i}]discount")->label(false)->textInput(['maxlength' => true,'class' => 'disc','placeholder' => 'Discount']) ?>


<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>

Javascript function

<?php
/* start getting the total amount */
$this->registerJs('
    function getSum() {
        var retailPrice = 0;
        var stockistPrice = 0;
        var sum = 0;
        var totalDiscount = 0;
        var totalMrp = 0;
        var totalCst = 0;
        var totalWbst = 0;
        var totalCstonamount = 0;
        var totalWbstonamount = 0;
        var totalCstonmrp = 0;
        var totalWbstonmrp = 0;
        var totalTaxonmrp = 0;
        var totalTaxonamount = 0;
        var totalAmountonmrp = 0;
        var totalAmountonrate = 0;
        var totalBillamountonmrp = 0;
        var totalBillamountonrate = 0;
        var igstAmount = 0;
        var cgstAmount = 0;
        var sgstAmount = 0;

        var cstperValue = $(".cstPercent").val();
        var wbstperValue = $(".wbstPercent").val();
        var selectedValue = $("input[name=taxon]:checked").val();
        //alert(selectedValue);

        var items = $(".item");

        items.each(function (index, elem) {
        var qtyValue = $(elem).find(".qty").val();
        var rateValue = $(elem).find(".rate").val();
        var discValue = $(elem).find(".disc").val();
        var mrpValue = $(elem).find(".mrp").val();
        var freeValue = $(elem).find(".free").val();
        var igstPercent = $(elem).find(".igstrate").val();
        var cgstPercent = $(elem).find(".cgstrate").val();
        var sgstPercent = $(elem).find(".sgstrate").val();



        cgstAmount = (parseFloat(cgstAmount) + ((parseFloat(qtyValue)*parseFloat(rateValue) - (parseFloat(qtyValue)*parseFloat(rateValue)*parseFloat(discValue))/100)*parseFloat(cgstPercent))/100).toFixed(2);

        sgstAmount = (parseFloat(sgstAmount) + ((parseFloat(qtyValue)*parseFloat(rateValue) - (parseFloat(qtyValue)*parseFloat(rateValue)*parseFloat(discValue))/100)*parseFloat(sgstPercent))/100).toFixed(2);

        igstAmount = (parseFloat(igstAmount) + ((parseFloat(qtyValue)*parseFloat(rateValue) - (parseFloat(qtyValue)*parseFloat(rateValue)*parseFloat(discValue))/100)*parseFloat(igstPercent))/100).toFixed(2);

        stockistPrice = (parseFloat(stockistPrice) + (parseFloat(rateValue)*parseFloat(qtyValue) - (parseFloat(rateValue)*parseFloat(qtyValue)*parseFloat(discValue))/100)).toFixed(2);

        sum = Math.round(parseFloat(stockistPrice) + parseFloat(cgstAmount) + parseFloat(sgstAmount) + parseFloat(igstAmount));

    });

   if(isNaN(sum) || sum.length == 0) {
       sum = 0;
   }
   if(isNaN(cgstAmount) || cgstAmount.length == 0) {
       cgstAmount = 0;
   }
   if(isNaN(sgstAmount) || sgstAmount.length == 0) {
       sgstAmount = 0;
   }
   if(isNaN(igstAmount) || igstAmount.length == 0) {
       igstAmount = 0;
   }
   if(isNaN(stockistPrice) || stockistPrice.length == 0) {
       stockistPrice = 0;
   }


   $(".sum").val(sum);
   $(".cgstAmount").val(cgstAmount);
   $(".sgstAmount").val(sgstAmount);
   $(".igstAmount").val(igstAmount);
   $(".totalAmount").val(stockistPrice);

   $(".billAmount").val(sum);
   $(".overdueAmount").val(sum);


    }


    $(".container-items").on("change", function() {
        getSum();
    });
    $(".remove-item").on("click", function() {
        getSum();
        alert("This Onclick is working");
    });

');
/*end getting the total amount */
?>

On Change of the items, the javascript is being called and I'm getting the value. But on Click of the remove-item button, the javascript is not getting called. Please let me know what to do to call the javascript onclick of the remove-item button.

There's no error in the console.

回答1:

If the adding and removing the fields are the only functions that are only manipulating the form then you can use the new MutationObserver to track if any new elements were added or removed from the target container.

This new DOM Api is available in Firefox and Webkit nightly builds, as well as Chrome 18.

The key advantage to this new specification over the deprecated DOM Mutation Events spec is one of efficiency. If you are observing a node for changes, your callback will not be fired until the DOM has finished changing. When the callback is triggered, it is supplied a list of the changes to the DOM, which you can then loop through and choose to react to.

This also means that any code you write will need to process the observer results in order to react to the changes you are looking for.

Consider the following example which adds and removes divs inside a container div using the add and remove buttons, and i use MutationObserver to look for the changes in the target element #container and update the div count inside the callback function after checking the the Mutation Event is for the ChildList which is triggered when you add or remove the child elements from the target container.

function startObserver() {
  // select the target node
  var target = document.querySelector('#container');
  
  // create an observer instance
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.type == 'childList') {
        $('.counter').html($("#container>div").length + ' div(s) total');
      }
    });
  });

  // configuration of the observer:
  var config = {
    childList: true,
  }

  // pass in the target node, as well as the observer options
  observer.observe(target, config);
}

jQuery(function($) {
  $("#add-more").on("click", function() {
    $("#container").append("<div>some thing " + Math.random() + "</div>")
  })

  $("#remove").on("click", function() {
    $("#container>div:eq(0)").remove()
  });

  startObserver();
});
.counter {
  float: right;
  font-size: 2em;
  color: red;
  margin-right: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="section"><button id="add-more">add more</button>
  <button id="remove">Remove</button>
  <div class="counter">0 div(s) total</div>
  <div id='container'>

  </div>

What you need to do is to wrap the form inside a div and provide it an id say container and add the call to the function getSum() inside the callback function you can copy the below code.

$this->registerJs("// select the target node
var target = document.querySelector('#container');

// create an observer instance
var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
       if (mutation.type == 'childList') {
           getSum();
       }
    });
});

// configuration of the observer:
var config = { childList: true};

// pass in the target node, as well as the observer options
observer.observe(target, config);     
", yii\web\View::POS_READY);

NOTE: Remove any other calls to the getSum() function if you have added it to any other event like below

 $(".remove-item").on("click", function() {
        getSum();
        alert("This Onclick is working");
    });

Hope this helps you sort the problem.



标签: yii2