5.20231.904
5.20231.904

Wijmo's RESTCollectionView

Wijmo's RESTCollectionView class extends the CollectionView class to allow you to incorperate REST functionality into the CollectionView, and by extension, all controls that make use of the CollectionView class.

The RESTCollectionView supports CRUD functionality. To use it, create a class that extends the RESTCollectionView and add overrides for the following methods:

  • getItems: Gets a list of items from the server. The list may be sorted, filtered, and paged.
  • addItems: Adds an item to the collection on the server.
  • patchItem: Edits an item in the collection on the server.
  • deleteItem: Deletes an item from the collection on the server.

By default, the class should perform sorting, filtering, and paging on the server.

If the REST service does not support any of these operations, make sure the sortOnServer, pageOnServer, or filterOnServer properties are set to false, and the corresponding operations will be performed on the client instead.

Extending the RESTCollectionView

You can extend the RESTCollectionView class to create custom RESTCollectionView classes that talk to your data sources directly. For example, you can extend the RESTCollectionView class to create a custom RESTCollectionViewOData class that talks to a JSONPlaceholder source.

First, we'll need to initializes our variables and create a couple of methods for our CRUD operations to use:

import { RESTCollectionView } from '@grapecity/wijmo.rest';
import { httpRequest, copy, asString, assert } from '@grapecity/wijmo';

export class RESTCollectionViewJSON extends RESTCollectionView {
    constructor(tableName, options) {
        super();
        this._url = 'https://jsonplaceholder.typicode.com/';
        this._tbl = asString(tableName);
        copy(this, options);
        // this source does not support server-side pagination, sorting, or filtering.
        this.pageOnServer = false;
        this.sortOnServer = false;
        this.filterOnServer = false;
    }
    /**
     * Gets or the name of the key field.
     *
     * Key fields are required for update operations (add/remove/delete).
     */
    get key() {
        return this._key;
    }
    set key(value) {
        this._key = asString(value);
    }
    // ** implementation
    _getWriteUrl(item) {
        let url = this._url + this._tbl;
        assert(this.key != null, 'write operations require keys');
        return url + '/' + item[this.key];
    }
    _jsonReviver(key, value) {
        if (typeof value === 'string' && _rxDate.test(value)) {
            value = value.indexOf('/Date(') == 0 // verbosejson
                ? new Date(parseInt(value.substr(6)))
                : new Date(value);
        }
        return value;
    }
}

The get/set key() methods will be used by the update operations, _getWriteUrl() constructs our URLs, and jsonReviver() will update our JSON.

The RESTCollectionViewOData class functions similarly to the ODataCollectionView class that ships with Wijmo. It supports CRUD operations as well as server-based sorting, filtering, and pagination. In order to use CRUD functionality, we'll need to override the CRUD methods:

getItems() {
    return __awaiter(this, void 0, void 0, function* () {
        // cancel any pending requests
        if (this._pendingRequest) {
            //console.log('aborting pending request');
            this._pendingRequest.abort();
        }
        return new Promise(resolve => {
            let url = this._url + this._tbl;
            this._pendingRequest = httpRequest(url, {
                success: (xhr) => __awaiter(this, void 0, void 0, function* () {
                    let arr = JSON.parse(xhr.responseText, this._jsonReviver);
                    resolve(arr);
                }),
                error: xhr => this._raiseError(xhr.responseText, false),
                complete: xhr => this._pendingRequest = null // no pending requests
            });
        });
    });
}
addItem(item) {
    return new Promise(resolve => {
        let url = this._url + this._tbl;
        let requestHeaders = {
            'Content-Type': 'application/json; charset=UTF-8'
        };
        if (this.requestHeaders) {
            for (let k in this.requestHeaders) {
                requestHeaders[k] = this.requestHeaders[k];
            }
        }
        let newItem = {};
        for (let k in item) {
            if (k != this.key) {
                newItem[k] = item[k];
            }
        }
        httpRequest(url, {
            method: 'POST',
            requestHeaders: requestHeaders,
            data: newItem,
            success: xhr => {
                let newItem = JSON.parse(xhr.responseText, this._jsonReviver);
                item[this.key] = newItem[this.key];
                this.refresh();
            },
            error: xhr => this._raiseError(xhr.responseText, true)
        });
    });
}
patchItem(item) {
    return new Promise((resolve) => {
        let url = this._getWriteUrl(item);
        httpRequest(url, {
            method: 'PUT',
            requestHeaders: this.requestHeaders,
            data: item,
            success: xhr => resolve(item),
            error: xhr => this._raiseError(xhr.responseText, true)
        });
    });
}
deleteItem(item) {
    return new Promise(resolve => {
        let url = this._getWriteUrl(item);
        httpRequest(url, {
            method: 'DELETE',
            requestHeaders: this.requestHeaders,
            success: xhr => {
                resolve(item);
            },
            error: xhr => this._raiseError(xhr.responseText, true)
        });
    });
}

Now, you're able to call the RESTCollectionView in your JavaScript file and use that as your data source for your FlexGrid control:

// Extended RESTCollectionView class
import { RESTCollectionViewJSON } from './rest-collection-view-json';
import { FlexGrid } from '@grapecity/wijmo.grid';

function init() {
    // create the grid to show the data
    let theGrid = new FlexGrid('#theGrid', {
        allowAddNew: true,
        allowDelete: true,
        showMarquee: true,
        selectionMode: 'MultiRange',
        deferResizing: true,
        alternatingRowStep: 0,
        // create RESTCollectionViewJSON
        itemsSource: new RESTCollectionViewJSON('todos', {
            key: 'id',
            pageSize: 8
        })
    });
}