Array Data Provider 2

Like the legacy Array Data Provider, the built-in Array Data Provider 2 can be bound to collection components.

Like ArrayDataProvider, this built-in type is a data provider implementation where the data is available as an array. All the data is set once, and the data itself can fetched from a backend service (say a list of countries), but it is assumed that array once created is static, that is, data changes infrequently or has limited and infrequent adds, updates and removes done to it.

The vb/ArrayDataProvider2 can be bound to collection components such as listView and table components. Operations on the data, such as sorts, adds, removes, and updates, are managed by the vb/ArrayDataProvider2 itself. This is different from the vb/ServiceDataProvider, where all operations generally are processed in the back end via REST calls.

ArrayDataProvider2 behaves differently from the legacy ArrayDataProvider in the following ways:

  • Writes to individual properties of the ArrayDataProvider2.data are NOT allowed, and users will see an error when this occurs. Usually this happens when components use writable binding expressions that write directly to properties within individual data (array) items.

  • ArrayDataProvider2 SUPPORTS using the fireDataProviderEventAction to mutate data, in addition to the assignVariablesAction.

  • ArrayDataProvider2 tracks mutations to data made using fireDataProviderEventAction and notifies listeners (that is, components) of just the changes. This has the benefit of only updating the necessary parts of the UI.

A variable of this type is generally defined on the page, using the built-in type vb/ArrayDataProvider2.

{
 
  "variables": {
    "productListADPA": {
      "type": "vb/ArrayDataProvider2",
      "defaultValue": {
        "itemType": "application:productSummary",
        "keyAttributes": "id"
      }
    }
  }
  ...

ArrayDataProvider2 has several properties available.

data

The static array of data that the ArrayDataProvider2 wraps. The data property is set once when the page loads. The implicitSort criteria that the data is pre-sorted with is also set once the page loads.

keyAttributes

A string or array of string field names that represent the primary key for each row. Can be one of:

  • a field name - the key value is a primitive or whatever the field value represents.

  • an array of field names - the key will also be an array of values. For example, for keyAttributes: ['id'], when data is [{id: 'ie', name: "IE"}, {id: 'chrome', name: "Chrome"}], the corresponding keys will be [['ie'], ['chrome']]

  • @value, use all properties - the key will also be an array of all values.

  • @index, use the index as the key - the key will be an integer.

implicitSort

The implicit sort criteria by which the data is pre-sorted. This is an array of objects, where each object is an atomic sort expression of the form:

{
  "attribute": "<name of the field>", 
  "direction": "<'ascending' (default) or 'descending'>" 
}

itemType

The type of each item in the data array. This is usually a string that points to an application type or to a definition.

sortComparators

An optional object with a 'comparators' property that is either an array of arrays where each inner array has 2 items - name of the attribute that the sortCriteria applies to, and a comparator function callback that is used by ADP to sort the attribute (column), or is a Map of attribute to comparator function. This API is similar to the JET SortComparator API.

Here are some examples of configuration for array or arrays.

"sortComparators": {
  "comparators": [
    [
      "Category", "{{ $page.functions.alphaSort }}"
    ],
    [
      "Product", "{{ $page.functions.alphaSort }}"
    ]
  ]
}

Using a Map:

sortComparators: {
  comparators: "{{ new Map([['name', $page.functions.alphaSort]]) }}",
}

The comparator function will look like this:

var alphaSort = function (a, b) {
  return a.localeCompare(b);
}

textFilterAttributes

An array of attributes to filter on. See the JET documentation for ArrayDataProvider textFilterAttributes.

"customerListADP": {
  "type": "vb/ArrayDataProvider2",
  "defaultValue": {
    "keyAttributes": "id",
    "itemType": "flow:customer",
    "textFilterAttributes": [
      "lastName", "firstName"
    ]
  }
}

Features and Capabilities

ArrayDataProvider2 supports the same capabilities as the legacy ArrayDataProvider:

sort

  • {capabilityName: 'full', attributes: 'multiple} means the endpoint has support for sorting results by one or more fields.

  • null means the endpoint has no support for sorting.

Data Mutation and Refresh Events

vb/ArrayDataProvider2 notifies components when the underlying data mutates or is changed in a way that requires a refresh. The events currently supported by any iterating data providers are the 'mutate' ('add', 'remove' and 'update') event and 'refresh'. See Assigning Data for details.

Variable Events

All variables including vb/ArrayDataProvider2 raise the variable onValueChanged event when any of its properties change. ArrayDataProvider2 in particular will detect which of its data has changed, and will automatically notify subscribers of just the change (these are typically components that are bound to the ArrayDataProvider2 variable and have registered a listener).

Assigning Data

The data property of the vb/ArrayDataProvider2 variable is set once, when the page or component loads. The implicitSort criteria that the data is pre-sorted with is also set once the page or component loads.

After the initial load, a page author can mutate the data either by directly manipulating the data array using the 'assignVariablesAction' action or by using the 'fireDataProviderEventAction'.

Using a fireDataProviderEventAction, authors can mutate data property, and also notify components in one shot. When the mutation events 'add', 'remove' and 'update' are called the vb/ArrayDataProvider2 implementation will automatically mutate the underlying data, so users are not required to mutate the ArrayDataProvider2.data prior to raising this event, say, using an assignVariablesAction. This is a convenience offered only by the vb/ArrayDataProvider2 implementation, not by vb/ArrayDataProvider. See Fire Data Provider Event Action for details.

Often the mutation to the data is triggered by the UI or some other app logic, which might require the use of assignVariablesAction. This is another way to update the ArrayDataProvider2.data, in which case It's not required to use the fireDataProviderEventAction. See Assign Variables Action for details.

Note:

ADP data in a JSON file needs to be assigned a valid JSON value. ADP data that is assigned a value from the result of a previous action (for example, a call module action or REST action), must also be valid JSON. When a non-JSON value (such as JavaScript values like NaN or Infinity) is provided, you should choose the correct JSON value that should be used and then replace it. For example, the JavaScript value "NaN" can be replace by "0", which is an accepted JSON value.

Example 1-8 Where the data is literally inlined

In this example, the ArrayDataProvider2 variable productsADPB has its initial data inlined.

"variables": {
  "productsADPB": {
    "type": "vb/ArrayDataProvider2",
    "description": "mutations are done on 'data' property using assignVariables",
    "defaultValue": {
      "itemType": "ProductType",
      "keyAttributes": "id",
      "data": [{
        "Amount": 30,
        "CurrencyCode": "USD",
        "Quantity": 3,
        "RegisteredPrice": 30,
        "Type": "Literal",
        "Product": "Product-Literal",
        "id": 30
      }]
    }
  }
}

To remove an item from the above ArrayDataProvider2 data you can use an assignVariablesAction.

  • Line 16: filters the data array of productsADPB by removing the item with the matching key

1  "removeProductsADPB": {
2    "root": "removeFromProductsADPB",
3    "description": "",
4    "variables": {
5      "key": {
6        "type": "number",
7        "required": true,
8        "input": "fromCaller"
9      }
10   },
11   "actions": {
12     "removeFromProductsADPB": {
13       "module": "vb/action/builtin/assignVariablesAction",
14       "description": "splice returns the removed item, so filter is used instead, which mutates and returns the original array",
15       "parameters": {
16         "$page.variables.productsADPB.data": {
17           "source": "{{ $page.variables.productsADPB.data.filter((p) => p.id !== $chain.variables.key) }}",
18           "reset": "empty",
19           "auto": "always"
20         }
21       }
22     }
23   }
24 }

When the data is inlined or is assigned from a vbEnter action chain, you can add or update items to the array using the assignVariablesAction.

  • Line 1: shows an example action where the product is updated directly

  • Line 12: shows an example action where the new product is added to the tail end of the data array

1  "updateProductsADPB": {
2    "module": "vb/action/builtin/assignVariablesAction",
3    "description": "directly updating ADP2.data item is possible when data has no expression",
4    "parameters": {
5      "$page.variables.productsADPB.data[$page.variables.productsADPB.data.findIndex(p => p.id === $chain.variables.key)]": {
6        "source": "{{ $chain.variables.product }}",
7        "auto": "always",
8        "reset": "empty"
9      }
10   }
11 }
12 "addToProductsADPBTail": {
13   "module": "vb/action/builtin/assignVariablesAction",
14   "parameters": {
15   "$page.variables.productsADPB.data[$page.variables.productsADPB.data.length]": {
16       "source": "{{ $chain.results.generateNewProduct }}"
17     }
18   }
19 }

Example 1-9 Where the productsADPC is updated via a fireDataProviderEventAction

In this example, productsADPC has its data coming from another variable.

"productsADPC": {
  "type": "vb/ArrayDataProvider2",
  "description": "mutations on data can be done on the referenced 'products' or on "
    + "the 'data' property directly. The latter will disconnect the reference",
  "defaultValue": {
    "data": "{{ $page.variables.products }}",
    "itemType": "ProductType",
    "keyAttributes": "id"
  }
}

To update a specific product, you can use the fireDataProviderEventAction to set the target, data and keys properties.

  • Line 28: set the event payload using the fireDataProviderEventAction

1  "updateProductsADPC": {
2    "root": "updateProduct",
3    "description": "updates productsADPC using data provider mutation event",
4    "variables": {
5      "product": {
6        "type": "page:ProductType",
7        "required": false,
8        "input": "fromCaller"
9      }
10   },
11   "actions": {
12     "updateProduct": {
13       "module": "vb/action/builtin/assignVariablesAction",
14       "parameters": {
15         "$chain.variables.product": {
16           "source": {
17             "Amount": "{{ $chain.variables.product.Amount * (1+Math.floor(Math.random() * Math.floor(5))) }}",
18             "Quantity": "{{ $chain.variables.product.Quantity * (1+Math.floor(Math.random() * Math.floor(5))) }}"
19           },
20           "reset": "none",
21           "auto": "always"
22         }
23       },
24       "outcomes": {
25         "success": "fireEventProductsADPC"
26       }
27     },
28     "fireEventProductsADPC": {
29       "module": "vb/action/builtin/fireDataProviderEventAction",
30       "parameters": {
31         "target": "{{ $page.variables.productsADPC }}",
32         "update": {
33           "keys": "{{ [ $chain.variables.product.id ] }}",
34           "data": "{{ [ $chain.variables.product ] }}"
35         }
36       }
37     }
38   }
39 },