Ag-grid viewport: cannot read property 'bind' of undefined

陌路散爱 提交于 2019-12-11 06:33:29

问题


I'm replicating the ag-grid Viewport example putting it in an object representing the table instead of a anonymous function. I cannot understand why it gives me the error in the title when trying to connect to the mockserver, given that it is exactly the same code.

Here it is the code that doesn't seem to work:

   function ViewportDatasource(mockServer) {
        this.mockServer = mockServer;
        this.connectionId = this.mockServer.connect(this.eventListener.bind(this));
    }

    ViewportDatasource.prototype.eventListener = function (event) {
        switch (event.eventType) {
            case 'rowCountChanged':
                this.onRowCountChanged(event);
                break;
            case 'rowData':
                this.onRowData(event);
                break;
            case 'dataUpdated':
                this.onDataUpdated(event);
                break;
        }
    };

here it is the whole object:

function WatcherTable($rootScope,$scope, $http) {

    this.FIELD_KEY_ID = "id";
    this.FIELD_KEY_ISSUER_SHORT_DESC= "isd";
    this.FIELD_KEY_ISSUER = "iss";
    this.FIELD_KEY_CUSIP = "cus";
    this.FIELD_KEY_ISIN = "isin";
    this.FIELD_KEY_BOARD_LABEL = "lbl";
    this.FIELD_KEY_IND_SECT_LABEL = "isl";
    this.FIELD_KEY_CURR="cur"

    this.FIELD_KEY_BEST_BID_SIZE = "bBidSz";
    this.FIELD_KEY_BEST_BID_PRICE = "bBidPrc";
    this.FIELD_KEY_BEST_ASK_PRICE = "bAskPrc";
    this.FIELD_KEY_BEST_ASK_SIZE = "bAskSz";
    this.FIELD_KEY_BEST_BID_SPREAD = "bBidSpd";
    this.FIELD_KEY_BEST_ASK_SPREAD = "bAskSpd";

    this.FIELD_KEY_ORDER_BID_SIZE = "oBidSz";
    this.FIELD_KEY_ORDER_BID_PRICE = "oBidPrc";
    this.FIELD_KEY_ORDER_ASK_PRICE = "oAskPrc";
    this.FIELD_KEY_ORDER_ASK_SIZE = "oAskSz";
    this.FIELD_KEY_ORDER_BID_SPREAD = "oBidSpd";
    this.FIELD_KEY_ORDER_ASK_SPREAD = "oAskSpd";

    this.headerMyOrder="ORDER";
    this.headerMyBidOrder="BID ORDER";
    this.headerMyAskOrder="ASK ORDER";


    this.cols = [{
        headerName : "Security Info",
        marryChildren : true,
        children : [{
            headerName : "Issuer Short Desc.",
            field : this.FIELD_KEY_ISSUER_SHORT_DESC,

            //width : 0,
            //hide : true
        },
        {
            headerName : "Industry Sector Label",
            field : this.FIELD_KEY_IND_SECT_LABEL,
            //width : 80,
            filter: 'set',
            filterParams: { values: ['Advertising', 'Aerospace/Defense', 'Agriculture', 'Airlines', 'Apparel', 'Auto Manufacturers', 'Auto Parts&Equipment', 'Banks', 'Basic Materials', 'Beverages', 'Biotechnology', 'Building Materials', 'Chemicals', 'Coal', 'Commercial Services', 'Communications', 'Computers', 'Consumer, Cyclical', 'Consumer, Non-cyclical', 'Cosmetics/Personal Care', 'Distribution/Wholesale', 'Diversified', 'Electrical Compo&Equip', 'Electronics', 'Energy', 'Energy-Alternate Sources', 'Engineering&Construction', 'Entertainment', 'Machinery-Constr&Mining', 'Household Products/WaresIndustrial', 'Insurance', 'Internet', 'Investment Companies', 'Iron/Steel', 'Kangaroos', 'Leisure Time', 'Lodging', 'Machinery-Constr&Mining', 'Machinery-Diversified', 'Media', 'Metal Fabricate/Hardware', 'Mining', 'Miscellaneous Manufactur', 'Multi-National', 'Office Furnishings', 'Office/Business ', 'Oil&Gas', 'Oil&Gas Services', 'Packaging&Containers', 'Pharmaceuticals', 'Pipelines', 'Real Estate', 'Regional(state/provnc)', 'REITS', 'Retail', 'Savings&Loans'],
                            newRowsAction: 'keep'},
            },
        {
            headerName : "Board Label",
            field : this.FIELD_KEY_BOARD_LABEL,
            //width : 80,
            filter: 'text',
            filterParams: { apply: true }

        }, {
            headerName : "CUSIP",
            field : this.FIELD_KEY_CUSIP,
            //width : 150,
            //suppressFilter: true
        },
        {
            headerName : "ISIN",
            field : this.FIELD_KEY_ISIN,
            //width : 150,
            //suppressFilter: true
        },
        {
            headerName : "Currency",
            field : this.FIELD_KEY_CURR,
            //width : 150,
            //suppressFilter: true
        }
        ]},
        {
        headerName : "Best",
        marryChildren : true,

        children : [ {
            headerName : "Bid Size",
            pinned: 'right',
            field : this.FIELD_KEY_BEST_BID_SIZE,
            cellStyle: {'border-left': '1px solid #E82043', 'color':'#E82043', 'font-weight':'bold', 'text-align':'right'},
            cellRenderer: BidRenderer,
            filter:'number',


            //width : 125,
            //suppressFilter: true
        }, {
            headerName : "Bid Price",
            pinned: 'right',
            field : this.FIELD_KEY_BEST_BID_PRICE,
            cellStyle: {'border-right': '1px solid #E82043', 'color':'#E82043', 'font-weight':'bold', 'text-align':'right'},
            //cellRenderer: 'animateShowChange',
            cellFormatter: numberFormatter,
            cellRenderer: BidRenderer,
            width : 125,
            filter:'number',


            //suppressFilter: true
        },
        {
            headerName : "Ask Price",
            pinned: 'right',
            field : this.FIELD_KEY_BEST_ASK_PRICE,
            //cellRenderer: 'animateShowChange',
            cellFormatter: numberFormatter,
            cellRenderer: AskRenderer,
            cellStyle: {'color':'#19B092', 'font-weight':'bold', 'text-align':'right'},
            filter:'number',
            //width : 125,
            //suppressFilter: true
        },
        {
            headerName : "Ask Size",
            pinned: 'right',
            field : this.FIELD_KEY_BEST_ASK_SIZE,
            cellStyle: {'border-right': '1px solid #19B092', 'color':'#19B092', 'font-weight':'bold', 'text-align':'right'},
            cellRenderer: AskRenderer,
            filter:'number',
            //width : 125,
            //suppressFilter: true
        } ]
    } ];


    //definizione della tabella//// rowModelType: 'virtual', rowModelType: 'pagination',



    this.table = {
            showPrice: true,
            showSpread: true,
            orderSize: 0,
            orderFilter: '',
            enableServerSideFilter: true,
            enableServerSideSorting: true,
            sortingOrder: ['desc','asc',null],
            enableColResize : true,
            debug : true,
            rowSelection : 'multiple',
            rowDeselection : true,
            columnDefs : this.cols,
            rowModelType : 'viewport',
            headerHeight: 20,
            rowHeight: 20,
            viewportRowModelPageSize:30,
            viewportRowModelBufferSize: 15,         
            suppressColumnVirtualisation: true, 
            suppressMenuColumnPanel: true,
            onCellDoubleClicked: WatcherTable.prototype.onCellDoubleClicked.bind(this,$rootScope),          
            getContextMenuItems: WatcherTable.prototype.getContextMenuItems.bind(this,$rootScope),
            getMainMenuItems: WatcherTable.prototype.getMainMenuItems.bind(this, $rootScope), 
            getRowNodeId: function (data) {
                // the code is unique, so perfect for the id
                return data.isin;
            },
            onGridReady:setRowData($http)
    };

    function numberFormatter(params) {
        if (typeof params.value === 'number') {
            return params.value.toFixed(4);
        } else {
            return params.value;
        }
    }



    function BidRenderer () {}

    BidRenderer.prototype.init = function(params) {
        // create the cell
        this.eGui = document.createElement('div');
        this.eGui.innerHTML = '<div></div>';

        // set value into cell
        this.eValue = this.eGui.querySelectorAll('div')[0];
        this.eValue.innerHTML = params.valueFormatted ? params.valueFormatted : params.value;

    };

    // gets called once when grid ready to insert the element
    BidRenderer.prototype.getGui = function() {
        return this.eGui;
    };

    // gets called whenever the user gets the cell to refresh
    BidRenderer.prototype.refresh = function(params) {
        // set value into cell again
        this.eGui.innerHTML = '<div class="bid"></div>';
        this.eValue = this.eGui.querySelectorAll('div')[0];
        this.eValue.innerHTML = params.valueFormatted ? params.valueFormatted : params.value;

    };

    function AskRenderer () {}

    AskRenderer.prototype.init = function(params) {
        // create the cell
        this.eGui = document.createElement('div');
        this.eGui.innerHTML = '<div></div>';

        // set value into cell
        this.eValue = this.eGui.querySelectorAll('div')[0];
        this.eValue.innerHTML = params.valueFormatted ? params.valueFormatted : params.value;

    };

    // gets called once when grid ready to insert the element
    AskRenderer.prototype.getGui = function() {
        return this.eGui;
    };

    // gets called whenever the user gets the cell to refresh
    AskRenderer.prototype.refresh = function(params) {
        // set value into cell again
        this.eGui.innerHTML = '<div class="ask"></div>';
        this.eValue = this.eGui.querySelectorAll('div')[0];
        this.eValue.innerHTML = params.valueFormatted ? params.valueFormatted : params.value;
    };

    // client code (ie your code) will call this constructor, pass in whatever you need for the
    // viewport to do it's job
    function ViewportDatasource(mockServer) {
        this.mockServer = mockServer;
        this.connectionId = this.mockServer.connect(this.eventListener.bind(this));
    }

    // gets called by the grid, tells us what rows the grid is displaying, so time for
    // us to tell the server to give us the rows for that displayed range
    ViewportDatasource.prototype.setViewportRange = function (firstRow, lastRow) {
        this.mockServer.setViewportRange(this.connectionId, firstRow, lastRow);
    };

    // gets called by the grid, provides us with the callbacks we need
    ViewportDatasource.prototype.init = function (params) {
        this.params = params;
    };

    // gets called by grid, when grid is destroyed or this datasource is swapped out for another one
    ViewportDatasource.prototype.destroy = function () {
        this.mockServer.disconnect(this.connectionId);
    };

    // manages events back from the server
    ViewportDatasource.prototype.eventListener = function (event) {
        switch (event.eventType) {
            case 'rowCountChanged':
                this.onRowCountChanged(event);
                break;
            case 'rowData':
                this.onRowData(event);
                break;
            case 'dataUpdated':
                this.onDataUpdated(event);
                break;
        }
    };

    // process rowData event
    ViewportDatasource.prototype.onRowData = function (event) {
        var rowDataFromServer = event.rowDataMap;
        this.params.setRowData(rowDataFromServer);
    };

    // process dataUpdated event
    ViewportDatasource.prototype.onDataUpdated = function (event) {
        var that = this;
        event.changes.forEach(function (change) {
            var rowNode = that.params.getRow(change.rowIndex);
            // if the rowNode is missing, it means the grid is not displaying that row.
            // if the data is missing, it means the rowNode is there, but that data has not
            // loaded into it yet, so to early to set delta changes.
            if (!rowNode || !rowNode.data) {
                return;
            }
            // rowNode.data[change.columnId] = change.newValue;
            // this is a trick, it gets the row to refresh
            rowNode.setDataValue(change.columnId, change.newValue);
        });
    };

    // process rowCount event
    ViewportDatasource.prototype.onRowCountChanged = function (event) {
        var rowCountFromServer = event.rowCount;
        // this will get the grid to make set the height of the row container, so we can scroll vertically properly
        this.params.setRowCount(rowCountFromServer);
    };

    function setRowData($http) {
        // set up a mock server - real code will not do this, it will contact your
        // real server to get what it needs
        var mockServer = new MockServer();
        $http.get('data.json').then(function(response){
            mockServer.init(response.data);
        });

        var viewportDatasource = new ViewportDatasource(mockServer);
        table.api.setViewportDatasource(viewportDatasource);
        // put the 'size cols to fit' into a timeout, so that the scroll is taken into consideration
        setTimeout(function () {
            table.api.sizeColumnsToFit();
        }, 100);
    }

    // setup the grid after the page has finished loading
   /* document.addEventListener('DOMContentLoaded', function () {
        var gridDiv = document.querySelector('#liveStreamExample');
        new agGrid.Grid(gridDiv, table);

        // do http request to get our sample data - not using any framework to keep the example self contained.
        // you will probably use a framework like JQuery, Angular or something else to do your HTTP calls.
        var httpRequest = new XMLHttpRequest();
        httpRequest.open('GET', 'data.json');
        httpRequest.send();
        httpRequest.onreadystatechange = function () {
            if (httpRequest.readyState == 4 && httpRequest.status == 200) {
                var httpResponse = JSON.parse(httpRequest.responseText);
                setRowData(httpResponse);
            }
        };
    });*/

};

WatcherTable.prototype.getContextMenuItems = function ($rootScope,params){
    var result= [{name:"Show Book", action:WatcherTable.prototype.changeBookSubscription.bind(this,$rootScope,params.node.data)}];

    return result;
}

WatcherTable.prototype.onCellDoubleClicked = function ($rootScope,params){
    $rootScope.$broadcast("changeBookSubscription",{instrkey:params.data.cus+"."+params.data.isin,boardLabel:params.data.isd+" "+params.data.lbl});
    if(params.colDef.field.indexOf("bBid")>-1){
        $rootScope.$broadcast("showHitDialog",params);
        log("Show hit dialog");
        console.log(params);
    }
    else if(params.colDef.field.indexOf("bAsk")>-1){
        $rootScope.$broadcast("showLiftDialog",params);
        log("Show lift dialog");
        console.log(params);
    }
}

WatcherTable.prototype.changeBookSubscription = function ($rootScope,data) {
    $rootScope.$broadcast("changeBookSubscription",{instrkey:data.cus+"."+data.isin,boardLabel:data.isd+" "+data.lbl});
}

WatcherTable.prototype.getMainMenuItems = function($rootScope, params){
    var prcCols=["bBidPrc","bAskPrc","oBidPrc","oAskPrc"];
    var spdCols=["bBidSpd","bAskSpd","oBidSpd","oAskSpd"];
    var menuItems= [
        {name:'Show Price', 
            action:function(){
                        params.columnApi.setColumnsVisible(prcCols, !params.api.gridCore.gridOptions.showPrice);
                        params.api.gridCore.gridOptions.showPrice= !params.api.gridCore.gridOptions.showPrice;      
                    }, 
             checked: params.api.gridCore.gridOptions.showPrice
             },
        {name:'Show Spread', 
        action:function(){
                    params.columnApi.setColumnsVisible(spdCols, !params.api.gridCore.gridOptions.showSpread);
                    params.api.gridCore.gridOptions.showSpread= !params.api.gridCore.gridOptions.showSpread;        
                }, 
         checked: params.api.gridCore.gridOptions.showSpread
         },
         {
             name:'Orders',
                subMenu:[
                    {name:'Live Orders Only', 
                        action:function(){
                        if (params.api.gridCore.gridOptions.orderFilter==='live'){
                            params.api.gridCore.gridOptions.orderFilter='';
                            //TODO filter
                        }
                        else {params.api.gridCore.gridOptions.orderFilter='live';
                            //TODO filter
                        }

                    }, checked:(params.api.gridCore.gridOptions.orderFilter==='live')},
                    {name:'My Orders Only',     action:function(){
                        if (params.api.gridCore.gridOptions.orderFilter==='mine'){
                            params.api.gridCore.gridOptions.orderFilter='';
                            //TODO filter
                        }
                        else {params.api.gridCore.gridOptions.orderFilter='mine';
                            //TODO filter
                        }

                    }, checked:(params.api.gridCore.gridOptions.orderFilter==='mine')},
                    {name:'My Firm\'s Orders Only', action:function(){
                        if (params.api.gridCore.gridOptions.orderFilter==='firm'){
                            params.api.gridCore.gridOptions.orderFilter='';
                            //TODO filter
                        }
                        else {params.api.gridCore.gridOptions.orderFilter='firm';
                            //TODO filter
                        }

                    }, checked:(params.api.gridCore.gridOptions.orderFilter==='firm')},
                ]
         },
         {name: 'Size ...', action: function() {

             console.log(params.api.gridCore.gridOptions.orderSize);
             $rootScope.$broadcast("orderSizeDialog",{size:parseInt(params.api.gridCore.gridOptions.orderSize)});
            },
            }
    ];
    return menuItems;
}

Can you help me?

EDIT

I noticed that eventListener function isn't being called when creating ViewportDatasource object. How can I force it?

EDIT 2

I took ViewportDatasource declaration out of WatcherTable scope. Now I got over the starting issue, but I cannot load data into the grid.

I created a plunker: https://plnkr.co/edit/EEEJULRE72nbPF6G0PCK


回答1:


(Taken from your question today, similar problems here I think)

You have a timing issue in your plunker - your MockServer is trying to process data before it's available.

You need to do two things to resolve this - the first is to only try set the data source once the data is available in the MockServer:

WatcherTable.prototype.setRowData = function ($http) {
    // set up a mock server - real code will not do this, it will contact your
    // real server to get what it needs
    var mockServer = new MockServer();
    var that = this;
    $http.get('data.json').then(function (response) {
        mockServer.init(response.data);
        var viewportDatasource = new ViewportDatasource(mockServer);
        that.table.api.setViewportDatasource(viewportDatasource);
        // put the 'size cols to fit' into a timeout, so that the scroll is taken into consideration
        setTimeout(function () {
            that.table.api.sizeColumnsToFit();
        }, 100);
    });
}

Secondly, along the same theme, you need to prevent the periodic updates from trying to process data before its ready. Here you can either kick off the periodical updates AFTER the data is available, or more simply add a check before you try use it:

MockServer.prototype.periodicallyUpdateData = function() {
    if(!this.allData) return;

I've forked your plunker (with the above changes) here: https://plnkr.co/edit/cY30aHIPydVOjcihX8Zh?p=preview



来源:https://stackoverflow.com/questions/41810448/ag-grid-viewport-cannot-read-property-bind-of-undefined

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!