Ali Khakpouri
Ali Khakpouri

Reputation: 873

Knockout foreach $parent indicates grandparent instead of parent

When iterating through a foreach loop of the pager.Pages object, $data is self (as expected). However, $parent should be the pager object, but instead it is returning WaterQualityResultViewModel. What am i doing wrong?

ko.applyBindings(wqrvm, $('#dv_waterReports')[0]);
function WaterQualityResultViewModel() {
    var self = this;
    self.searchItem = new SearchItem();
    self.items = ko.observableArray([]);
    self.pager = new Pager();
    self.search = function() {
        $.ajax({
            url: 'URL GOES HERE',
            dataType: 'json',
            data: {
                'param': 'value'
            },
            async: false,
            success: function(data) {
                if ((data != null) && (data.searchResults !== undefined)) {                 
                    self.items(mappedItems);
                    self.pager.totalItemCount(data.resultsCount);
                    self.pager.lastPage(data.totalPages);
                }
            }
        });
    }
    self.initFromUrl = function() {
        var hash = getHash();
        self.searchItem.geolocation(new geoLocation(0, 0, '', hash));       
        if (hash.currentpage !== 'undefined')
            self.pager.currentPage(hash.currentpage);
        if (hash.pagesize !== 'undefined')
            self.pager.pageSize(hash.pagesize);
    };
    self.initialize = function() {
        if (window.location.hash) {
            self.initFromUrl();
            self.search();
        }
    };
    self.initialize();
}

function Pager() {
    var self = this;
    self.lastPage = ko.observable(1);
    self.totalItemCount = ko.observable(0);
    self.currentPage = ko.observable(1);
    self.pageSize = ko.observable(10);
    self.pageSlide = 2;
    self.HasNextPage = ko.computed(function () {
        return self.currentPage() < self.lastPage();
    });
    self.HasPrevPage = ko.computed(function () {
        return self.currentPage() > 1;
    });
    self.FirstItemIndex = ko.computed(function () {
        return self.pageSize() * (self.currentPage() - 1) + 1;
    });
    self.LastItemIndex = ko.computed(function () {
        return Math.min(self.FirstItemIndex() + self.pageSize() - 1, self.totalItemCount());
    });
    self.Pages = ko.computed(function () {
        //debugger;
        var pageCount = self.lastPage();
        var pageFrom = Math.max(1, self.currentPage() - self.pageSlide);
        var pageTo = Math.min(pageCount, self.currentPage() + self.pageSlide);
        pageFrom = Math.max(1, Math.min(pageTo - 2 * self.pageSlide, pageFrom));
        pageTo = Math.min(pageCount, Math.max(pageFrom + 2 * self.pageSlide, pageTo));

        var result = [];
        for (var i = pageFrom; i <= pageTo; i++) {
            result.push(i);
        }
        return result;
    });
    self.buildUrl = function () {
        var locHash = encodeQueryData({
            'currentpage': self.currentPage(),
            'pagesize': self.pageSize()
        });
        return locHash;
    };
}

The following template returns:

<!-- ko foreach:pager.Pages -->
            <pre data-bind="text: 'pager is ' + JSON.stringify(ko.toJS($data))"></pre>
            <pre data-bind="text: 'parent is: ' + JSON.stringify(ko.toJS($parent))"></pre>
<!-- /ko -->

enter image description here

Upvotes: 1

Views: 308

Answers (1)

Jonathan
Jonathan

Reputation: 245

$parent should be the pager object

Based on what are you making this assumption? It's unclear in the OP because you haven't posted the full HTML.

Since you've called applyBindings(new WaterQualityResultViewModel()); The view model is the $parent.

Maybe you're thinking $parent should refer to pager because you're data-binding foreach: pager.Pages. This assumption is incorrect. Knockout is aware of the DOM binding context that you provide to it; it is not aware of your Javascript object structure.

$parent referring to the viewModel itself and $data referring to each value within the Pages array is absolutely correct.

Upvotes: 2

Related Questions