简体   繁体   中英

Knockout errors with containerless control flow syntax

I'm still new to knockout, so maybe I'm doing something wrong. I have an html form with dynamic input controls which can be added by the user. I don't know if the problem is caused by the containerless control flow syntax, but I don't know how I can achieve the same result without it.

The markup for the dynamic part is this:

  //begin form

  <!-- ko foreach: durationValues -->
      <div class="form-group">
          <!-- ko if: ($index() === 0) -->
              <label for="Values[0].Value">Values</label>
          <!-- /ko -->
          <div class="input-group">
              <input class="form-control" type="text" data-bind="value: text, attr: { name: 'Values[' + $index() + '].Value' }" data-val="true" data-val-required="Value required." />
              <span class="input-group-btn">
                  <!-- ko if: ($index() === 0) -->
                      <button class="btn btn-outline-secondary" type="button" data-bind="click: addDurationValue"><i class="fa fa-plus-circle"></i> Add</button>
                  <!-- /ko -->
                  <!-- ko if: ($index() > 0)-->
                      <button class="btn btn-outline-secondary" type="button" data-bind="click: $parent.removeDurationValue"><i class="fa fa-trash"></i> Remove</button>
                  <!-- /ko -->
              </span>
          </div>
          <span class="field-validation-valid invalid-feedback" data-bind="attr: { 'data-valmsg-for': 'Values[' + $index() + '].Value' }" data-valmsg-replace="true"></span>
      </div>
  <!-- /ko -->

  //endform
  //jquery, jquery-validate, jquery-validate-unobtrusive, bootstrap and knockout script files loaded

  <script>
  function DurationValue(text) {
        this.text = text;
    }

    function DurationValuesViewModel() {
        var self = this;

        self.durationValues = ko.observableArray([
            new DurationValue("")
        ]);

        self.addDurationValue = function () {
            self.durationValues.push(new DurationValue(""));

            //Remove current form validation information
            $("form")
                .removeData("validator")
                .removeData("unobtrusiveValidation");

            //Parse the form again
            $.validator.unobtrusive.parse("form");
        };

        self.removeDurationValue = function (durationValue) { self.durationValues.remove(durationValue); };
    }

    ko.applyBindings(new DurationValuesViewModel());
  </script>

The page keeps yelling me these errors:

Uncaught ReferenceError:

Unable to process binding "foreach: function (){return durationValues }"

Message: Unable to process binding "if: function (){return ($index() === 0) }"

Message: Unable to process binding "click: function (){return addDurationValue }"

Message: addDurationValue is not defined at click (eval at createBindingsStringEvaluator (knockout-3.4.2.debug.js:2992), :3:58) at newValueAccessor (knockout-3.4.2.debug.js:4231) at init (knockout-3.4.2.debug.js:4241) at init (knockout-3.4.2.debug.js:4234) at knockout-3.4.2.debug.js:3368 at Object.ignore (knockout-3.4.2.debug.js:1480) at knockout-3.4.2.debug.js:3367 at Object.arrayForEach (knockout-3.4.2.debug.js:159) at applyBindingsToNodeInternal (knockout-3.4.2.debug.js:3353) at applyBindingsToNodeAndDescendantsInternal (knockout-3.4.2.debug.js:3233)

Your containerless control flow syntax is fine. But, you need to add $parent or $root before the addDurationValue used in click binding function to provide proper binding context

Inside the foreach binding, knockout looks for addDurationValue in each DurationValue object rather than the DurationValuesViewModel instance. So, we need to specify where to look for the function. In this case, $root and $parent refer to the same object.

 function DurationValue(text) { this.text = text; } function DurationValuesViewModel() { var self = this; self.durationValues = ko.observableArray([ new DurationValue("") ]); self.addDurationValue = function() { self.durationValues.push(new DurationValue("")); //Remove current form validation information $("form") .removeData("validator") .removeData("unobtrusiveValidation"); // Commented for now //Parse the form again // $.validator.unobtrusive.parse("form"); }; self.removeDurationValue = function(durationValue) { self.durationValues.remove(durationValue); }; } ko.applyBindings(new DurationValuesViewModel()); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <!-- ko foreach: durationValues --> <div class="form-group"> <!-- ko if: ($index() === 0) --> <label for="Values[0].Value">Values</label> <!-- /ko --> <div class="input-group"> <input class="form-control" type="text" data-bind="value: text, attr: { name: 'Values[' + $index() + '].Value' }" data-val="true" data-val-required="Value required." /> <span class="input-group-btn"> <!-- ko if: ($index() === 0) --> <button class="btn btn-outline-secondary" type="button" data-bind="click: $parent.addDurationValue"><i class="fa fa-plus-circle"></i> Add</button> <!-- /ko --> <!-- ko if: ($index() > 0)--> <button class="btn btn-outline-secondary" type="button" data-bind="click: $parent.removeDurationValue"><i class="fa fa-trash"></i> Remove</button> <!-- /ko --> </span> </div> <span class="field-validation-valid invalid-feedback" data-bind="attr: { 'data-valmsg-for': 'Values[' + $index() + '].Value' }" data-valmsg-replace="true"></span> </div> <!-- /ko --> 

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