0
votes

I have a view model something like below, when onAfterRender is fired by Knockout then the function in the viewmodel (also called onAfterRender) is executed but the values for this.gridColumns, this.gridOptions are undefined is there anyway to fix this? I would prefere to keep the object function rather than using an object literal.

I create my viewModel like this:

var model = new i2owater.viewmodels.AlarmsForViewModel(somedata);

and call ko.applyBindings(model);

this is my view model:

viewModel = function (serverData) {
var alarmGrid = {};

function onAfterRender() {
    var that = this;
    this.alarmGrid = new i2owater.Slickgrid();

    // this.gridColumns and this.gridOptions are both undefined
    this.alarmGrid.setupGrid("#alarmsGrid", [], this.gridColumns, this.gridOptions);
};

return {
    data: data,
    tabs: tabs,
    selectedPriority: selectedPriority,
    company: company,
    zone: zone,
    rows: rows,
    alarmPeriod: alarmPeriod,
    //alarmGrid: alarmGrid,
    gridColumns: [{ id: "id", name: "ID", field: "id", sortable: true },
        { id: "date", name: "Date", field: "date", sortable: true },
        { id: "description", name: "Description", field: "description"}],
    gridOptions: {
        editable: true,
        enableCellNavigation: true,
        asyncEditorLoading: true,
        forceFitColumns: false,
        topPanelHeight: 25,
        rowHeight: 40
    }
    onAfterRender: onAfterRender
};

};

1

1 Answers

1
votes

There are a several ways that you could ensure that this is correct in this situation.

One option would be to create a result variable, bind your function to that variable, then return result.

var result = {
    data: data,
    tabs: tabs,
    selectedPriority: selectedPriority,
    company: company,
    zone: zone,
    rows: rows,
    alarmPeriod: alarmPeriod,
    //alarmGrid: alarmGrid,
    gridColumns: [{ id: "id", name: "ID", field: "id", sortable: true },
        { id: "date", name: "Date", field: "date", sortable: true },
        { id: "description", name: "Description", field: "description"}],
    gridOptions: {
        editable: true,
        enableCellNavigation: true,
        asyncEditorLoading: true,
        forceFitColumns: false,
        topPanelHeight: 25,
        rowHeight: 40
    }
};

result.onAfterRender = onAfterRender.bind(result);

return result;

Otherwise, rather than returning an anonymous object literal, you can build it like this:

viewModel = function (serverData) {
    var alarmGrid = {};

    function onAfterRender() {
        var that = this;
        this.alarmGrid = new i2owater.Slickgrid();

        // this.gridColumns and this.gridOptions are both undefined
        this.alarmGrid.setupGrid("#alarmsGrid", [], this.gridColumns, this.gridOptions);
    };

    this.data = data;
    this.tabs = tabs;
    this.selectedPriority = selectedPriority;
    this.company = company;
    this.zone = zone;
    this.rows = rows;
    this.alarmPeriod = alarmPeriod;
    this.gridColumns = [{ id: "id", name: "ID", field: "id", sortable: true },
            { id: "date", name: "Date", field: "date", sortable: true },
            { id: "description", name: "Description", field: "description"}];
    this.gridOptions = {
        editable: true,
        enableCellNavigation: true,
        asyncEditorLoading: true,
        forceFitColumns: false,
        topPanelHeight: 25,
        rowHeight: 40
    };
    this.onAfterRender = onAfterRender.bind(this);
};

or use an extend function like in KO 1.3 ko.utils.extend to extend the current this like:

viewModel = function (serverData) {
    var alarmGrid = {};

    function onAfterRender() {
        this.alarmGrid = new i2owater.Slickgrid();
        this.alarmGrid.setupGrid("#alarmsGrid", [], this.gridColumns, this.gridOptions);
    };

    ko.utils.extend(this, {
        data: data,
        tabs: tabs,
        selectedPriority: selectedPriority,
        company: company,
        zone: zone,
        rows: rows,
        alarmPeriod: alarmPeriod,
        //alarmGrid: alarmGrid,
        gridColumns: [{ id: "id", name: "ID", field: "id", sortable: true },
            { id: "date", name: "Date", field: "date", sortable: true },
            { id: "description", name: "Description", field: "description"}],
        gridOptions: {
            editable: true,
            enableCellNavigation: true,
            asyncEditorLoading: true,
            forceFitColumns: false,
            topPanelHeight: 25,
            rowHeight: 40
        }
        onAfterRender: onAfterRender.bind(this)
    });
};

Also, an alternative to using bind would be to do a var self = this; at the beginning of the constructor function, then use self inside the onAfterRender function.