0
votes

I am simply trying to create some checkboxes and inputs that get the data from database and saving it back to database after edit. But I am getting the following error:

Uncaught TypeError: Unable to process binding "if: function(){return $root.editAlarmValues }" Message: Unable to process binding "enable: function(){return $root.editAlarmValues().setAlarmValues() }" Message: $root.editAlarmValues(...).setAlarmValues is not a function

I am not sure what I am doing wrong. I checked in the console and the values get mapped correctly to the array but they don't seem to bind to view. Any help will be highly appreciated!

Here is the code:

        <!--ko if: $root.editAlarmValues -->
       
            <div class="row">
                <div class="col-md-6">
                    <input type="checkbox" data-bind="iCheck: $root.editAlarmValues().setAlarmValues" class="large-check"/>
                </div>
            </div>

            <div class="row">
                <div class="col-md-5 form-inline">
                    <input type="checkbox" data-bind="iCheck: $root.editAlarmValues().setOutputCurrentPPLowValue, enable: $root.editAlarmValues().setAlarmValues()" class="large-check"/>
                            <input type="text" id="OutputCurrentPPLowValue" data-bind="value: $root.editAlarmValues().outputCurrentPPLowValue, enable: $root.editAlarmValues().setOutputCurrentPPLowValue()" class="form-control" maxlength="30" />
                 </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <div class="pull-right">

                        <button type="button" class="btn btn-primary btn-flat" data-bind="event: {click: $root.editSave}">Save</button>
                    </div>
                </div>
            </div>

            <!-- /ko -->

and script:

 var AlarmsViewModel = function (wellID) {

        function EditAlarms(setAlarmValues, setOutputCurrentPPLowValue, outputCurrentPPLowValue) {
            var self = this;
            self.setAlarmValues = ko.observable(setAlarmValues);
            self.setOutputCurrentPPLowValue = ko.observable(setOutputCurrentPPLowValue);
            self.outputCurrentPPLowValue = ko.observable(outputCurrentPPLowValue);
        }

        var self = this;
        self.wellID = ko.observable(wellID);
        self.editAlarmValues = ko.observableArray(); 
     
        self.init = function () {
            self.editAlarmInit();
        };

        self.editAlarmInit = function () {
            APIHelper.getData("/api/alarmapi/EditAlarms?wellID=" + self.wellID(), self.editAlarmsCallback, "");
        };

        self.editAlarmsCallback = function (data) {
            //Map results
            var temp = $.map(data.result, function (item) {
                return new EditAlarms(item.setAlarmValues, item.setOutputCurrentPPLowValue, item.outputCurrentPPLowValue);
            });
            self.editAlarmValues(temp);                
        };

        self.editSave = function () {
            var jsonData = ko.toJSON(self.editAlarmValues);        
            APIHelper.postData("/api/alarmapi/EditAlarmsPost", jsonData);
        };

        self.init();
    };

    var wellID = @ViewBag.WellID;
   
    ko.bindingHandlers.iCheck = {
        init: function (el, valueAccessor) {
            var observable = valueAccessor();
            $(el).on("ifChanged", function () {
                observable(this.checked);
            });
        },

        update: function (el, valueAccessor) {
            var val = ko.utils.unwrapObservable(valueAccessor());
            if (val) {
                $(el).iCheck('check');
            } else {
                $(el).iCheck('uncheck');
            }
        }
    };


    var vm = new AlarmsViewModel(wellID);
    ko.applyBindings(vm);
1

1 Answers

0
votes

You don't want a <!-- ko if: editAlarmValues -->, you want a <!-- ko foreach: editAlarmValues -->. The foreach will not run when the target array is empty, so it fundamentally fulfills the same function.

Inside the foreach, the binding context is the EditAlarms object in question, so you should refer to its properties directly (iCheck: setOutputCurrentPPLowValue instead of iCheck: $root.editAlarmValues().setOutputCurrentPPLowValue).

Also think about your naming. EditAlarms is not a good name for a single object. The prefix set... should refer to a method that sets something. In this case it's just an observable property. setAlarmValues should be called alarmValues, and because it's not an array, it probably should actually be called alarmValue. And so on.

<!-- ko foreach: editAlarmValues -->
<div class="row">
    <div class="col-md-6">
        <input type="checkbox" data-bind="iCheck: setAlarmValues" class="large-check">
    </div>
</div>
<div class="row">
    <div class="col-md-5 form-inline">
        <input type="checkbox" class="large-check" data-bind="
            iCheck: setOutputCurrentPPLowValue,
            enable: setAlarmValues
        ">
        <input type="text" id="OutputCurrentPPLowValue" class="form-control" maxlength="30" data-bind="
            value: outputCurrentPPLowValue,
            enable: setOutputCurrentPPLowValue
        ">
     </div>
</div>
<div class="row">
    <div class="col-md-12">
        <div class="pull-right">
            <button type="button" class="btn btn-primary btn-flat" data-bind="click: $root.editSave">Save</button>
        </div>
    </div>
</div>
<!-- /ko -->

Revised JS code (move the binding handler definitions to the top, don't nest viewmodels)

ko.bindingHandlers.iCheck = {
    init: function (el, valueAccessor) {
        var observable = valueAccessor();
        $(el).on("ifChanged", function () {
            observable(this.checked);
        });
    },
    update: function (el, valueAccessor) {
        var val = ko.unwap(valueAccessor());
        $(el).iCheck(val ? 'check' : 'uncheck');
    }
};

function EditAlarms(setAlarmValues, setOutputCurrentPPLowValue, outputCurrentPPLowValue) {
    this.setAlarmValues = ko.observable(setAlarmValues);
    this.setOutputCurrentPPLowValue = ko.observable(setOutputCurrentPPLowValue);
    this.outputCurrentPPLowValue = ko.observable(outputCurrentPPLowValue);
}

function AlarmsViewModel(wellID) {
    var self = this;

    self.wellID = ko.observable(wellID);
    self.editAlarmValues = ko.observableArray();

    self.editAlarmInit = function () {
        APIHelper.getData("/api/alarmapi/EditAlarms?wellID=" + self.wellID(), function (data) {
            var alarms = data.result.map(item => new EditAlarms(
                item.setAlarmValues,
                item.setOutputCurrentPPLowValue,
                item.outputCurrentPPLowValue
            ));
            self.editAlarmValues(alarms);
        });
    };
    self.editSave = function () {
        APIHelper.postData("/api/alarmapi/EditAlarmsPost", ko.toJSON(self.editAlarmValues));
    };

    self.editAlarmInit();
}

var vm = new AlarmsViewModel(@ViewBag.WellID);
ko.applyBindings(vm);