问题
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