Child pages
  • Foundset property type

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents
maxLevel2

Purpose of this property type

Info

This page is intended for NG web component creators, not for Servoy developers that just want to use web components.

 

The 'foundset' property type can be used by web components to access/change a foundset's data/state directly from the browser.

...

  • a (parent) form's foundset
  • a related foundset
  • a separate foundset (of any table; smilar to JSDatabaseManager.getFoundset()). When this option is chosen the user can also choose whether or not the separate foundset should load all records initially. (if not checked, contents can be loaded at any time from scripting)
  • "- none -" which means that you are going to set that foundset at runtime through scripting.

Foundset property value in browser scripting

In browser js, a foundset property value has the following content:

...

(Starting with Servoy 8.1.3) Foundset typed properties can be assigned directly to as well. This will create a completely new foundset type property value (if you are not assigning a new foundset). Assigning a completely new foundset value to a foundset type property allows you to configure as well some of the things that are normally defined in the .spec file:

Code Block
languagejs
// elements.myFoundsetBasedBean.myFoundset is the foundset typed property
var myNewFoundset = ...; // some Servoy foundset
elements.myFoundsetBasedBean.myFoundset = {
            foundset: myNewFoundset,
            dataproviders: {
                dp1 : "customerName",
                dp2 : "city"
            },
            sendSelectionViewportInitially: false,
            initialPreferredViewPortSize: 15
};

All keys in  the descriptor object above are optional except for "foundset". So if you don't provide "dataproviders" or "sendSelectionViewportInitially" or "initialPreferredViewPortSize" default values will be used for them. In a similar way you can simply set the foundset directly:

Code Block
languagejs
// elements.myFoundsetBasedBean.myFoundset is the foundset typed property
var myNewFoundset = ...; // some Servoy foundset
elements.myFoundsetBasedBean.myFoundset = myNewFoundset; // this will create a new foundset type property value
// that only sends the rowId (no other columns as dataproviders were not specified) and uses defaults for sendSelectionViewportInitially and initialPreferredViewPortSize

Combining Foundset Property Type, Foundset Reference Type, Record Finder type and client-to-server scripting calls

You might wonder - "why is setting a complete new foundset into a foundset typed property from server side scripting helpful?". This is helpful for for example in implementing more advanced tree-like components, that need to operate with multiple foundsets.

In combination with Foundset Reference type, Record Finder type and calls from client-side scripting to server-side component scripting, such components can query/create foundsets on server on-the-fly according to different requirements, put them in the model of the component (for example in a foundset array property that is initially empty []). Then they also store in the properties the "unique id" using the Foundset Reference type and return that id as well from the server-side scripting call. This means that on the client it has access to the new foundset and it can identify it via the "unique id". Also if server-side scripting needs a record from a foundset that is already on the client to create it's new foundset (maybe they need to be related in some way), then all the client has to do is send to the server the foundset reference "unique id" together with the rowId (from the foundset property type's viewport) of that record and on the server you will be able to find the record using the Record Finder type.

Here is a partial example of what a tree-table might need to do in order to handle large amounts of data properly on all levels:

Code Block
languagejs
titleClient-side .js
function getChildFoundSetHash(parentFoundsetHash, rowId, parentLevelGroupColumnIndex,
                                                  newLevelGroupColumnIndex) {
	// parentFoundsetHash comes from the foundset referece type property
    // rowId comes from the foundset property type's viewport
    // parentLevelGroupColumnIndex and newLevelGroupColumnIndex are indexes in
    // an array property that holds dataproviders
    var childFoundsetPromise;

    if (newLevelGroupColumnIndex) {
        childFoundsetPromise = $scope.svyServoyapi.callServerSideApi("getGroupedChildFoundsetUUID",
                      [parentFoundsetHash, rowId, parentLevelGroupColumnIndex, newLevelGroupColumnIndex]);
    } else {
        childFoundsetPromise = $scope.svyServoyapi.callServerSideApi("getLeafChildFoundsetUUID",
                      [parentFoundsetHash, rowId, parentLevelGroupColumnIndex]);
	}

    childFoundsetPromise.then(function(childFoundsetUUID) {
        var childFoundset = getFoundSetByFoundsetUUID(childFoundsetUUID);
        mergeData(..., childFoundset);
    }, function() {
        // some error happened
        (...)
    });
}
(...)
function getFoundSetByFoundsetUUID(foundsetHash) {
    if ($scope.model.hashedFoundsets)
        for (var i = 0; i < $scope.model.hashedFoundsets.length; i++) {
            if ($scope.model.hashedFoundsets[i].foundsetHash == foundsetHash)
                return $scope.model.hashedFoundsets[i].foundset;
		 
    return null;
}
Code Block
languagejs
titleServer-side .js
$scope.getGroupedChildFoundsetUUID = function(parentFoundset, parentRecordFinder, parentLevelGroupColumnIndex,
                                                              newLevelGroupColumnIndex) {
        if (!parentFoundset) parentFoundset = $scope.model.myFoundset.foundset;
        var childQuery = parentFoundset.getQuery();
		
        if (parentLevelGroupColumnIndex == undefined) {
            // this is the first grouping operation; alter initial query to get all first level groups
            (...)
        } else {
			// this is an intemediate group expand; alter query of parent level for the child level
			childQuery.groupBy.clear();
            childQuery.groupBy.add(childQuery
                      .columns[$scope.model.columns[newLevelGroupColumnIndex].dataprovider]);
            var parentGroupColumnName = $scope.model.columns[parentLevelGroupColumnIndex].dataprovider;
            childQuery.where.add(childQuery.columns[parentGroupColumnName]
                      .eq(parentRecordFinder(parentFoundset)[parentGroupColumnName]));
        }
		
        var childFoundset = parentFoundset.duplicateFoundSet();
		childFoundset.loadRecords(childQuery);
		
		var dps = {};
		for (var idx = 0; idx < $scope.model.columns.length; idx++) {
			dps["dp" + idx] = $scope.model.columns[idx].dataprovider;
		}
		
		$scope.model.hashedFoundsets.push({ foundset: {
			foundset: childFoundset,
			dataproviders: dps,
			sendSelectionViewportInitially: false,
			initialPreferredViewPortSize: 15
		}, foundsetUUID: childFoundset}); // send it to client as a foundset property with a UUID
		
		return childFoundset; // return the UUID that points to this foundset (return type will make it UUID)
	};
Code Block
languagejs
title.spec file
	"serverscript": "mycomppck/mycompname/mycomp_server.js",
(...)
	"model": 
	{
        "columns": { "type": "columnDef[]", "droppable": true },
        "hashedFoundsets": { "type": "hashedFoundset[]", "default": [] }
(...)
	"types": 
	{
        "columnDef": {
            "dataprovider": { "type": "dataprovider", "forFoundset": "myFoundset" }
            (...)
        },
        "hashedFoundset" : {
	  		"foundset": "foundset",
	  		"foundsetUUID": "foundsetRef"
		}	
	},
	"api" : {
		"getGroupedChildFoundsetUUID" : {
			"returns" : "foundsetRef",
			"parameters" : 
			[{
					"name" : "parentFoundset",
					"type" : "foundsetRef"
				}, {
					"name" : "parentRecordFinder",
					"type" : "rowRef"
				}, {
					"name": "parentLevelGroupColumnIndex",
					"type": "int"
				}, {
					"name": "newLevelGroupColumnIndex",
					"type": "int"
				}
			]
		},
(...)