Cloz
Cloz

Reputation: 83

Knockout causing problems with JQuery select? Validation not working

so I'm using Bootstrap, Jquery 2.2.3, and Knockout 3.4.0. I'm having a really odd issue where a checkbox will always come back as false or undefined no matter how I select it with JQuery. I think this may have something to do with the Knockout data-bind but I'm not certain.

I'm using a custom binding in ko.js in order to manipulate the checkboxes and have the other questions produce when the box is checked.

Then validation of the rblBracedBolted is supposed to be dependent on whether the checkbox is checked or not but all values come back as 'false,' or 'undefined,' regardless of checked status.

I know the current script for validation doesn't make sense but I've tried everything from .prop to .attr and even .is("checked") etc, etc.

<script type="text/javascript">

$(function () {
    ko.bindingHandlers.checkedProp = {
        init: function (element, valueAccessor) {
            Object.defineProperty(element, 'checked', {
                set: function (newValue) {
                    var value = valueAccessor();
                    value(newValue);
                }
            });
        },
        update: function (element, valueAccessor) {
            var value = ko.unwrap(valueAccessor());
            element.checked = value;
        }
    };
    ko.applyBindings(new viewModel());
});

$("#aspnetForm").validate({
    ignore: [],
    rules: { 
    <%=rblBracedBolted.UniqueID %>: {
        required: 
            {
                depends: function()
                {
                    var sel = $('[id$=cblAddlCoverage1]').val();

                    if (sel == 'Earthquake')
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
    },
  }
});
</script>
.btn-default {
  text-shadow: 0 1px 0 #fff;
  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
  border-color: #dbdbdb;
  border-color: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>

<body>
<label class="btn btn-default">
<input type="checkbox" name="cblAddlCoverage1" id="cblAddlCoverage1" runat="server" value="Earthquake" data-toggle="button" data-bind="checkedProp: Earthquake" />
Earthquake
</label>

<div class="col-xs-12" data-bind="visible: Earthquake()==true">
    <div class="form-group">
        <label for="rblBracedBolted" class="control-label">Is the dwelling braced/bolted/tied down?</label>
        <div class="btn-group" data-toggle="buttons" style="padding-left: 10px">
            <label class="btn btn-default">
                <input type="radio" name="rblBracedBolted" id="rblBracedBolted" runat="server" value="Yes" />
                Yes
            </label>
            <label class="btn btn-default">
                <input type="radio" name="rblBracedBolted" runat="server" value="No" />
                No
            </label>
        </div>
    </div>
</div>

</body>

Feel free to ask any questions if you need more info.

Upvotes: 0

Views: 82

Answers (1)

OfirD
OfirD

Reputation: 10461

This code:

Object.defineProperty(element, 'checked', {
    set: function (newValue) {
        var value = valueAccessor();
        value(newValue);
    }
});

defines a property named checked on the checkbox element. This overwrites the vanilla checked property of the element. However, you never set this property value, and actually, even if you would, it would cause an infinite loop.
Thus, although you may have thought that the value of the observable is set on each set of the checkbox, what actually happens is that set is never called, because the checked property was invalidated.

I suggest you drop the custom binding, and use Knockout's built-in checked binding (in the following snippet, I removed other attributes for brevity):

<input type="checkbox" id="cblAddlCoverage1" data-bind="checked: Earthquake" />

Here's a demonstration using your html (javascript is mine):

$(function () {
    var vm = function () {
      var self = this;
      self.Earthquake = ko.observable();
    }
    ko.applyBindings(new vm());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<body>
  <label class="btn btn-default">
    <input type="checkbox" name="cblAddlCoverage1" id="cblAddlCoverage1" runat="server" value="Earthquake" data-toggle="button" data-bind="checked: Earthquake" />
    Earthquake
  </label>
  <div class="col-xs-12" data-bind="visible: Earthquake()==true">
      <div class="form-group">
          <label for="rblBracedBolted" class="control-label">Is the dwelling braced/bolted/tied down?</label>
          <div class="btn-group" data-toggle="buttons" style="padding-left: 10px">
              <label class="btn btn-default">
                  <input type="radio" name="rblBracedBolted" id="rblBracedBolted" runat="server" value="Yes" />
                  Yes
              </label>
              <label class="btn btn-default">
                  <input type="radio" name="rblBracedBolted" runat="server" value="No" />
                  No
              </label>
          </div>
      </div>
  </div>
</body>

Upvotes: 1

Related Questions