Foundset property type
Purpose of this property type
The 'foundset' property type can be used by web components to access/change a foundset's data/state directly from the browser.
The foundset typed property in the browser will work based on a 'viewport' of the server's foundset. The viewport is controlled directly by the component's code. Server will adjust foundset viewport bounds/contents only when needed due to data changes, deletes, inserts...
The foundset property also gives the possibility of knowing/changing the selection of the foundset.
For advanced uses, the foundset property can be linked to/interact with other property types (dataprovider, tagstring, component, ...), so that those other properties will provide a viewport as well - representing the same rows/records as in the foundset's viewport. The properties that support foundset view of data will allow the web component to specify a "forFoundset: "[foundsetPropertyName]" in their own property's description in the .spec file.
For foundset property types Servoy Developer allows (in properties view) one of the following:
a (parent) form's foundset
a related foundset
a separate foundset (of any table; similar 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:
Browser side provided property content in model
foundsetId is controlled by the server; you should not change it
serverSize is controlled by the server; you should not change it
viewPort initial size can be changed using setPreferredViewportSize. When the component detects that more records that it needs are available, it care request viewPort contents using one of the two load async methods
viewPort.startIndex and viewPort.size will have the values requested by the async load methods. But if for example you are using data at the end of the foundset and records are deleted from there then viewport.size will be corrected/decreased from server (as there aren't enough records). A similar thing can happen to viewPort.startIndex. Do not modify these directly as that will have no effect. Use the load async methods instead.
viewPort.rows contains the viewPort data. Each item of the array represents data from a server-side record. Each item will always contain a "_svyRowId" entry that uniquely identifies the record on server. Then there's one entry for every dataprovider that the component needs to use (how those are selected is described below). You should never change the "_svyRowId" entry, but it is possible to change the values of any of the other entries - the new values will be pushed back into the server side record that they belong to (if pushToServer is set on the foundset property to allow/shallow or deep; see "Data synchronization" section of [https://wiki.servoy.com/display/public/DOCS/Specification]).
selectedRowIndexes is an array of selected foundset record indexes. This can get updated by the server if foundset selection changes server side. You can change the contents of this array to change foundset selection (new selection will be pushed to server). However, the preferred way of changing the record selection is by using "requestSelectionUpdate".
sortColumns is a string containing the sort columns of the foundset, like 'columnA desc,columnB asc'
multiselect represents the foundset multiselect state; do not change it as it will not be pushed to server.
columnFormats represents the default column formats for the columns given in the viewport; do not change this - only server pushes this information to the client if asked to do so by the .spec file. It is only present if you specify "provideColumnFormats": true inside the .spec file for this foundset property.
hasMoreRows true if the server side foundset has loaded only a part/chunk of it's records (in case of very large foundsets). In that case there are records even after 'serverSize'. It is controlled and updated by the server; you should not change it.
Adding a change listener
When updates are received from the server for this foundset property, any listeners registered via .addChangeListener() - see above - will get notified.
This was added in order to improve performance by removing the need for angular watches. You no longer need to add lots of angular watches, deep or collection watches in order to be aware of incoming server changes to the foundset property. Each such watch would slow down the page - as watches are triggered a lot for all kinds of user actions or socket traffic. Also the listener can give more detailed information in order to do more granular updates to the UI easier.
Look at this change listener from the client side foundset property's point of view, not from the server's point of view. For example a FoundsetChangeEvent.fullValueChanged does not necessarily mean that the server side foundset has changed by reference. It actually means that all client side contents of the foundset property did change - or might have changed. So it is meant to notify about changes in client side property value.
To add an incoming server change listener to this property type just call:
Adding a change listener (for incomming changes from server)
If you are using foundset linked properties with your foundset property you might want to add the listener as shown here.
what "changes" parameter can contain:
To make the "updates" part above clearer:
Let's say you had in your viewPort (before the incomming changes got applied to it):
row1 row2 row3 row4 row5
Then you got these "updates" from the listener :
that means that the viewport has changed like this after the first update got applied:
row1 row2 newRow1 row3 row4 row5
and like this after the second update got applied:
row1 row2 newRow1 row3 newRow2
Please note the when your listener is called the actual contents of the viewPort are already updated. So, at that time your viewport already looks like the last version above.
Always make sure to remove listeners when the component is destroyed
It is important to remove the listeners when your component is destroyed. For example if due to a tabpanel switch of tabs your form is hidden, the component and it's angular scope will be destroyed - at which point you have to remove any listeners that you added on model properties (like the foundset property), because the model properties will be reused in the future (for that form when it is shown again) and will keep any listeners in it. When that form will be shown again, it's UI will get recreated - which means your (new) component will probably add the listener again.
If you fail to remove listeners on your component's destroy, it will lead to memory leaks (model properties will keep listeners of obsolete components each time that component's form is hidden, which in turn will prevent those scopes and other objects that they can reference from being garbage collected) and probably weird exceptions (obsolete listeners executing on destroyed scopes of destroyed components).
Example of removing a listener:
How to remove listeners on component destroy
Defining/using a foundset property with a random set of dataproviders
A web component might want to work with as many dataproviders available in the viewport as the developer wants. Servoy Developer will allow selecting any number of dataproviders of the foundset to be sent to browser web component property value (through the properties view for the foundset typed property; use sub-property 'dataproviders').
For example a component that shows graphical representation of data might allow adding as many 'categories' to it as the developer wants to (each category getting data from one viewport column/dataprovider).
.spec file
So the component has a property called "myfoundset" that it wants linked to any foundset chosen in ServoyDeveloper, and it allows the developer to choose in properties view any number of dataproviders from the foundset.
browser js
Let's say the developer has chosen a foundset and 3 dataproviders (for example 3 database columns) from it. Those would generate for example a viewPort like this inside the browser property.
Browser side provided property content in model
Notice the fixed column names: dp0, dp1, ... dp[N-1] where N is the number of foundset dataproviders that the developer has chosen.
Defining/using a foundset property with a fixed set of dataproviders
A web component can specify in it's .spec file that it requires a foundset property and a fixed number of dataproviders from it. The foundset and required dataproviders are then selected by the developer when creating a solution (using the properties view, 'dataproviders' sub-property).
.spec file
So the component has a property called "myfoundset" that it wants linked to any foundset chosen in ServoyDeveloper, and it needs two dataproviders from that foundset to be present in the foundset's property viewport.
browser js
Let's say the developer has chosen a foundset and selected for "firstName" a foundset dataprovider (for example a database column called parentFirstName) and for lastName another dataprovider (for example a database column called parentLastName). Those would generate for example a viewport like this inside the browser property:
Browser side provided property content in model
In this way any foundset dataprovider/column can be mapped to one of the two dataproviders that the component requires. The actual foundset dataprovider name is not even used in browser js.
Defining/using a foundset property that provides default formatting information for columns
A web component can specify in it's .spec file that it requires the foundset property to provide default formatting information for it's columns. We will use a foundset property with fixed number of dataproviders as an example, but it will work the same for other ways of specifying the dataproviders.
.spec file
So the component has a property called "myfoundset" that it wants linked to any foundset chosen in ServoyDeveloper, and it needs two dataproviders from that foundset to be present in the foundset's property viewport. For each of the two columns it will also receive default formatting information.
browser js
Let's say the developer has chosen a foundset and selected for "image" a foundset dataprovider (for example a database column called 'photo') and for age another dataprovider (for example a database column called 'estimatedStructureAge'). Those would generate a viewport and formatting information similar to the following inside the browser property (note that the column format actual contents might change as needed - this is what Servoy default components receive as well for their component properties):
Browser side provided property content in model
The formatting information is similar to what default Servoy components get for their format properties, so it could be used in a similar way (for example through FormattingService).
Defining initial load and listener options for a foundset property
A web component can specify in it's .spec file that initially, at first show or each time the foundset gets completely refreshed it wants to automatically receive a number of rows in the viewport. This is useful to avoid some round trips between client and server and send data directly. It is configurable because some components may want to send no records initially while others might need to send many. This is done via the initialPreferredViewPortSize option. Default value is 50.
There is another option sendSelectionViewportInitially which allows a component to say whether this set of initial rows should contain the selected row (if any) or start at first row. This option is "false" by default. When this option is true, the selected row will be in the center of this initial viewPort (if possible) if option centerInitialViewportOnSelected (default: true, available starting with Servoy 2024.12) is true, otherwise a "paging like" viewport containing the selection will be used (it assumes the first page starts at the first record of the foundset).
All of these options can be altered at runtime from browser-side scripting using "setPreferredViewportSize(...)"; see above.
Note that the "foundsetInitialPageSize" property type that can be added "for" a foundset typed property allows you to change the "initialPreferredViewPortSize" (and the "centerInitialViewportOnSelected" would automatically be set to false if that property type is used) from properties view (in developer), or from solution code, but only before showing the form initially. This is useful for components that show pages of records.
A foundset based component can specify (starting with Servoy 2022.03) if it wants to know when the foundset's definition was changed, by adding a foundsetDefinitionListener property to the foundset property with the value true. If that is true, then the foundset's ChangeListener will also get a foundsetDefinitionChanged event passed in when the definition (sql query) of the underlying foundset is changed. This can be handy if you are in a grouped mode and the root foundset only has 200 records loaded but through grouping you really show 1000 records and because of a filter that is applied to the root the first 200 are not changed but the change is somewhere visible after that. Then a grouping table should reflect that by refreshing the groups. Don't use this property if you don't need it because it is not without cost - to calculate the query change and fire the event.
.spec file
Linking other "foundset aware" property types to a foundset property
Other property types can have content that is 'linked' to foundset records in some way. These property types can be configured in the .spec file as shown below - linking to any other property they have defined with 'foundset' type. When they are linked to a foundset, their javascript value in the browser is no longer only one value, but a viewPort of values (or it will also contain a viewPort of values - the exact content is property type specific) - corresponding to the records loaded in the linked foundset property's viewPort.
In this scenario, the viewPort of the foundset value only contains '_svyRowId' if it's own .spec property configuration doesn't list a dynamic or static list of dataproviders ("dataproviders" : [...] or "dynamicDataproviders": true), and the "foundset aware" property type value will have the viewPort contents in it (check each "foundset aware" type to see how that works, as it could differ from type to type).
Component type (child components that are linked to a foundset - for tables, lists, ...) or custom object types built of/containing other "foundset aware" property types (let's call them 'configurations' - can be used to build lightweight pure HTML tables, lists, ...) are the most common uses in this area.
Examples of foundset aware types are 'component', 'dataprovider', 'tagstring'.
.spec file
One child component linked to the foundset :
Multiple child components (array of them, notice 'elementConfig' that specifies a config value for each contained element) linked to the foundset. This type of linking is currently used by Servoy's tableviews, listviews and portals:
Have a look at 'component' page to see how these two properties above will look like in browser js.
'Configuration' object for sending other "foundset aware" types as viewPorts follows. In this case the value of those properties - so for example 'myconfigurations[0].mydataprovider' or 'myconfiguration.mydataprovider' will be arrays representing the foundset's viewport, not simple values. If the property is really linked to the record (so not global/form variables but record DP/column) then it will get a special 'idForFoundset' value - for example 'myconfiguration.mydataprovider.idForFoundset' - in it as well; that can be used with the foundset property's sort API. This 'idForFoundset' was added in version 8.0.3. (Note: "forFoundset" usage for "dataprovider" does not yet allow changing the value, but there is a case for making that work)
Runtime property access
At runtime, the foundset property is accessible in (server-side) javascript. If a bean named "myFoundsetBasedBean" has a foundset property named "myFoundset" it can be accessed like this:
That property gives access in scripting to:
the real underlying foundset
to the dataproviders that the property will send to the client webcomponent ( dataproviders contains key-value pairs where key is the name of the column used in web component client side scripting and value is the name of the foundset column attached to that). Both myFoundset.foundset and myFoundset.dataproviders are read-write properties under the foundset property type.
Setting myFoundset.foundset is only allowed if at design time you selected either "- none -" or a separate foundset for that property (so they are not related to the form directly). Parent form foundset and foundsets related to the form foundset are managed by Servoy automatically and they cannot be set through scripting at runtime. Of course you can alter the contents loaded by those form/related foundsets at runtime, but you cannot change completely the foundset by reference.
Examples:
(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:
All keys in the descriptor object above are optional except for "foundset". So if you don't provide "dataproviders", "initialPreferredViewPortSize", "sendSelectionViewportInitially" or "centerInitialViewportOnSelected", default values (see .spec section above) will be used for them. In a similar way you can simply set the foundset directly:
Combining Foundset Property Type, Foundset Reference Type, Record 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 example in implementing more advanced tree-like components, that need to operate with multiple foundsets.
In combination with Foundset Reference type ("foundsetRef"), Record type ("record") 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 return from the server-side scripting call the "foundsetId" using the Foundset Reference return type (so return a Foundset on an api call that has return type 'foundsetRef'). This means that on the client it has access to the new foundset and it can identify it via the "foundsetId" in the array-of-foundsets-property.
If server-side scripting needs a record from a client-side foundset in order 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 row from client side foundset property's viewport and on the server it will automatically be translated to a Record by the 'record' property type that is used as argument. Once you have the Record on server you have the foundset as well via Record.foundset.
Similarly, if one needs to send (from client-side) only a foundset as argument to server-side code, it can just give the value of the foundset property to an argument of type 'foundsetRef' and it will automatically be translated on server to a Foundset.
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:
Client-side .ts
Server-side .js
.spec file
Last updated
Was this helpful?