Expand All

  Getting Started

  Interfacing

  Features

  Row Models

  Themes

  Components

  Examples

  Third Party

Misc

Github stars make projects look great. Please help, donate a star, it's free.
Read about ag-Grid's Partnership with webpack.
Get informed on releases and other ag-Grid news only - never spam.
Follow on Twitter

Viewport Row Model

A Viewport is a rowModel that allows showing a 'window' of data in your client. Typically all the data will reside on the server and the server will know what data is displayed in the client. This is again useful for the server to push changes out to the client as it knows what data is currently displayed.

To enable the ViewPort, set the grid property rowModelType='viewport'.

The term 'viewport' is a common term in GUI's used to describe the visible area when scrolls are used to display content that is larger than the visible area. In ag-Grid, the viewport is referred to as the vertical scroll position, thus it defines the rows that are currently rendered by the grid.

ag-Grid uses 'DOM row virtualisation' which means it only renders the rows you currently see. So ag-Grid already uses the concept of a viewport for rendering the rows. The grid extends this concept and maps the viewport information to the viewportRowModel.

Use a viewport to display large live sets of data in the grid. The 'large' referring to you only want to load a subset of the data into the grid. The 'live' referring to the data is updating at the source (typically a server) and the source sends updates to the grid when displayed data is changed.

The diagram belows shows how the viewport maps to a connection to your dataset. The dataset connection knows what the viewport is displaying and sends up data accordingly. When the user scrolls, the viewport will 'get' data from the source. If / when the data changes, the source will 'push' the data to the viewport if it knows the viewport is displaying that data.

It is the responsibility of the grid to display the data. It is the responsibility of the application (ie your code) to fetch the data. So if you are doing WebSockets or otherwise, all of that coding belongs in the client code.

Interface IViewportDatasource

To use the viewportRowModel you provide the grid with a viewportDatasource. A viewportDatasource should look like the following:

interface IViewportDatasource {

    // Gets called exactly once before viewPort is used.
    // Passes methods to be used to tell viewPort of data loads / changes.
    init(params: IViewportDatasourceParams): void;

    // Tell the viewport what the scroll position of the grid is, so it knows what rows it has to get
    setViewportRange(firstRow: number, lastRow: number): void;

    // Gets called once when viewPort is no longer used. If you need to do any cleanup, do it here.
    destroy?(): void;
}
        
interface IViewportDatasourceParams {

    // datasource calls this method when the total row count changes. 
    // This in turn sets the height of the grids vertical scroll.
    setRowCount: (count:number) => void;

    // datasource calls this when new data arrives. The grid then updates 
    // the provided rows. The rows are mapped [rowIndex]=>rowData].
    setRowData: (rowData:{[key:number]:any}) => void;

    // datasource calls this when it wants a row node - typically used
    // when it wants to update the row node data
    getRow: (rowIndex: number) => RowNode;
}

Example Sequence

Reading the interfaces will look confusing if you are looking at the for the first time as the different parts don't make sense individually, it's how they all work together that creates the magic. So to explain, the following is a sequence of what may happen.

  1. You provide a new viewportDatasource to the grid. The grid will then call datasource.init() and provide the callbacks the datasource needs. The datasource should store a reference to these callbacks and then make an asynchronous call to the server to find out how large the set of data is that needs to be displayed.
  2. The datasource responds with the size of the data (eg 1,000 rows) and calls params.setRowCount(1000). The grid responds by sizing the vertical scroll to fit 1,000 rows.
  3. The grid, due to its physical size on the screen, works out it can display 20 rows at any given time. Given the scroll position is at the start, it calls datasource.setViewportRange(0,19) informing the datasource what data it needs. The grid will display blank rows for the moment.
  4. The datasource will make an asynchronous call to the server asking for rows 0 to 19. Some time later the result will come back and the datasource will call params.setRowData(map) where the map will have 20 entries, the keys will be the strings (a JavaScript object only allows strings as object keys, not numbers) 0 to 19 and the values will be the row data.
  5. The grid will refresh all the rows for 0 to 19 with the new data. At this point the current sequence is complete. The grid will remain static until either the user scrolls, or the datasource informs of a data change.
  6. If for example the user scrolls down 100 rows, the sequence above partially repeats, the grid calls datasource.setViewportRange(100,119), the datasource asynchronously responds with params.setRowData(map).

Updating Data

If your data changes, you should get a reference to the node by calling params.getRowData(rowIndex) and then call ONE of the following:

  • rowNode.setData(newData): Call this to set the entire data into the node. The new data will be stored inside the rowNode replacing the old data. This will result in the grid ripping out the rendered row in the DOM and replacing with a new rendered row. If you have any custom cellRenderers, they will be destroyed and new ones created, so no way to achieve animation.
  • rowNode.setDataValue(colKey, newValue): Call this to set one value into the node. The new value will be stored inside the old data, leave the rest of the data untouched. This will result in the grid refreshing only the cell that was updated. If the cell has a component with a refresh method, the refresh method will be called thus allowing animation. If no refresh method is provided, the grid will remove the cell (and destroy the cellRenderer if it exists) and create the cell again from scratch.

Replacing Data

You may want to completely change data in the viewport, for example if you are showing 'latest 10 trades over 10k' which changes over time as to what the trades are, then you just call setRowData() again with the new data. The grid doesn't care how many times you call setRowData() with new data. You could alternatively call rowNode.setData(data) on the individual row nodes, it will have the same effect.

If you want to change the length of data (eg you apply a filter, or the result set otherwise grows or shrinks) then you call setRowCount() again. The grid doesn't are how many times you call setRowCount().

Sorting

Only server side sorting is supported, if you want sorting you have to do it yourself on the server side. This is done by listening for the sortChanged event and then calling setRowData() with the new data when it arrives.

Filtering

As with sorting, filtering also must be done on the server side. To implement, listen for the filterChanged event and apply the filter to your server side set of data. Then call setRowCount() and setRowData() to display the new data.

Selection

Selection works with viewport. It is recommended that you implement getRowNodeId() to give a unique key to each row. That way, should the same row appear again but in a different location, it will keep its selection value. See the example below for setting up getRowNodeId().

Grouping

And you guessed it, if you are doing grouping, you will need to implement this yourself on the server side. If you group, then you will need to provide your own groupCellRenderer that gives functionality to your own custom grouping. You will also need to manage how the grouping impacts the overall grid's set size yourself (ie if you expand a group, the number of rows increases, and likewise contracting will decrease).

Viewport Settings

For simplicity the above said the viewport was the rows the grid is currently displaying. This is almost true except there are two properties, viewportRowModelPageSize and viewportRowModelBufferSize, to make the communication with the server better.

viewportRowModelPageSize

It is not good to have the grid ask for rows one at a time if the user is scrolling slowly. To get around this, the grid defines a page size, so it will ask for rows in 'pages'. For example, if the pages size is 5, then the viewport will always start and end in numbers divisible by 5 such as 0 to 20 or 75 to 100. So if the user is scrolling slowly, the viewport will only be requested to get new rows after the grid hits 'the next five rows'. The default page size is 5. To change this, set the grid property viewportRowModelPageSize.

viewportRowModelBufferSize

In addition to the page size, the grid will also extend the viewport outside the viewable area by the buffer size. For example, if the viewport is showing rows 30 to 50, and the buffer is set to 5, the grid will request rows 25 to 55 from the viewport. This will reduce 'loading flicker' as the user scrolls through the data. The default buffer size is 5. To change this, set the grid property viewportRowModelBufferSize.

Example Viewport

The example below shows a viewport in action.

Two built in cellRenderers are used: animateShowChange (bid, mid and ask columns) and animateSlide (volume column). You may find these useful, however they are provided to demonstrate how one could achieve a change animation. You will probably want to provide your own custom animation cellRenderer as how the animation happens will be depend on your application, the type of data and frequency of change.

The example uses a 'mockServer'. This is because all of the examples in this documentation work without any dependencies on any server. In your application, instead of using a mock server, you should connect to your real server. However the code in the mockServer example can be used to observe what your server code should be doing - it demonstrates keeping a connection open that is aware of the viewport position and pushes data to the client based on the viewport position.

Example Viewport with Pagination

The example below is almost identical to the above example with the following differences:

  • pagination=true: To enable pagination.
  • paginationAutoPageSize=true: To set the pagination size to the height of the grid, so no vertical scrolls are used.
  • viewportRowModelPageSize=1: Because we are showing exact pages, the user will not be scrolling, so there is no need to set a minimum page size. Setting page size to 1 means the grid will always ask from the top row through to the bottom row.
  • viewportRowModelBufferSize=0: Likewise because there is no scrolling, there is no sense in bringing back extra rows to act as a buffer.