Matt
Matt

Reputation: 6963

Knockout foreach bidning not working

I'm trying to get the Knockout foreach binding working in my code. I've done it many times before, but in this particular case I can't seem to get it right. I must be doing something wrong here, but I can't see it. I created a jsfiddle here: https://jsfiddle.net/9Lc144jv/

JavaScript:

var ReportModel = function (parent) {
            var self = this;
            self.parent = parent;
            self.filters = ko.observableArray([]);

            self.addFilter = function () {
                self.filters.push({ logicOperator: 0, columnName: null, comparisonOperator: 0, value: null });
            };

            self.removeFilter = function () {
                self.filters.remove(this);
            };
        };

        var ViewModel = function () {
            var self = this;
            self.reportModel = false;

            self.init = function () {
                self.reportModel = new ReportModel(self);
            };
        };

        var viewModel;
            $(document).ready(function () {
                viewModel = new ViewModel();
                ko.applyBindings(viewModel);
                viewModel.init();
            });

HTML:

<body>
    <table class="table table-bordered">
        <thead>
            <tr>
                <th></th>
                <th>Column</th>
                <th>Operator</th>
                <th>Value</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            <!-- ko foreach: reportModel.filters -->
            <tr>
                <td><input type="text" class="form-control" data_bind="value: logicOperator" /></td>
                <td><input type="text" class="form-control" data_bind="value: columnName" /></td>
                <td><input type="text" class="form-control" data_bind="value: comparisonOperator" /></td>
                <td><input type="text" class="form-control" data_bind="value: value" /></td>
                <td>
                    <button type="button" class="btn btn-danger" data-bind="click: $parent.removeFilter">
                        Remove
                    </button>
                </td>
            </tr>
            <!-- /ko -->
        </tbody>
        <tfoot>
            <tr>
                <td colspan="5" style="text-align: right;">
                    <button type="button" class="btn btn-primary" data-bind="click: reportModel.addFilter">
                        Add
                    </button>
                </td>
            </tr>
        </tfoot>
    </table>
</body>

UPDATE

A few notes:

  1. I was using the wrong attribute: "data_bind" instead of "data-bind". I corrected it now and the updated code is here: https://jsfiddle.net/9Lc144jv/2/

  2. It's still not working even though I made that fix

  3. When I copied and pasted it to a plain .html file and ran it, I could see something interesting in Firebug:

enter image description here

As you can see, running the following script in the command window shows there is nothing in the collection before clicking Add, and then something afterwards:

JSON.stringify(viewModel.reportModel.filters());

So the new object is in the observable array, but it's not binding to the table in the foreach block. But, why? From what I can see, everything looks fine.. but maybe I need a fresh pair of eyes on this. Someone please show me what I am doing wrong here...

Upvotes: 1

Views: 257

Answers (1)

brianlmerritt
brianlmerritt

Reputation: 2852

You are setting reportModel after the bindings plus I had to add the function call to the buttons() .

slight changes:

    var ReportModel = function (parent) {
        var self = this;
        self.parent = parent;
        self.filters = ko.observableArray([]);

        self.addFilter = function () {
            self.filters.push({ logicOperator: 0, columnName: null, comparisonOperator: 0, value: null });
        };

        self.removeFilter = function () {
            self.filters.remove(this);
        };
    };

    var ViewModel = function () {
        var self = this;
        self.reportModel = new ReportModel(self);

        self.init = function () {
            console.info(self);
    //self.reportModel = new ReportModel(self);
        };
    };

    var viewModel;
        $(document).ready(function () {
            viewModel = new ViewModel();
            ko.applyBindings(viewModel);
            viewModel.init();
        });

HTML

<body>
    <table class="table table-bordered">
        <thead>
            <tr>
                <th></th>
                <th>Column</th>
                <th>Operator</th>
                <th>Value</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            <!-- ko foreach: reportModel.filters -->
            <tr>
                <td><input type="text" class="form-control" data_bind="value: logicOperator" /></td>
                <td><input type="text" class="form-control" data_bind="value: columnName" /></td>
                <td><input type="text" class="form-control" data_bind="value: comparisonOperator" /></td>
                <td><input type="text" class="form-control" data_bind="value: value" /></td>
                <td>
                    <button type="button" class="btn btn-danger" data-bind="click: $parent.removeFilter()">
                        Remove
                    </button>
                </td>
            </tr>
            <!-- /ko -->
        </tbody>
        <tfoot>
            <tr>
                <td colspan="5" style="text-align: right;">
                    <button type="button" class="btn btn-primary" data-bind="click: reportModel.addFilter()">
                        Add
                    </button>
                </td>
            </tr>
        </tfoot>
    </table>
</body>

https://jsfiddle.net/vw2kngqq/

Upvotes: 1

Related Questions