Wings Engine

Data Reading and Processing

The data processing in secondary development is mainly divided into three parts: reading data, monitoring data changes, and triggering and withdrawing data linkage.

0. Test data preparation

First, we prepare a test data table in Excel as follows:

Area Salesperson Type Product Sales
A 1 drinks coffee 329
B 2 drinks juice 725
C 3 drinks plum juice 363
D 4 nut pistachio 619
E 5 nut Pecans 243

Importing data into Wings Engine:

1. Data reading

There are currently two ways to read data in secondary development. One is to read directly from the attribute items defined in the secondary development, and the other is to directly read other data setting items of the existing component. We recommend the first form.

1.1 Secondary development data attributes

1.1.1 Reading a single attribute

As mentioned in the previous custom attribute panel, we can read by directly defining a data field in secondary development. Currently, two functions are provided, readData and readDataAsync. For details, please refer to the API documentation:

Extension lifecycle functions

Tip: It is recommended to use the readData method for reading, because readData will trigger a callback both when reading for the first time and when the data changes. Therefore, the data processing code can be written uniformly in the callback function without having to handle the first reading and data changes separately.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ButtonSample {
setting = Field.default({
maxFields: 3, // Maximum number of fields allowed
});
init() {
this.setting.readData(
(data) => {
// This callback is triggered whenever data content changes or data settings are modified
console.log("data", data);
},
{
// Enable callback on data change
callbackOnDataChanged: true,
}
);
}
}
export default ButtonSample;

After loading, we can see a new data item under the data tab.

Drag the imported data into the fields:

After setting, click the button to view the content of the print information:

As you can see, the data is returned in the form of an array. If you want to get the data in other forms, you can also pass in the corresponding type:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ButtonSample {
setting = Field.default({
maxFields: 3, // Maximum number of fields allowed
});
init() {
this.setting.readData(
(data) => {
// This callback is triggered whenever data content changes or data settings are modified
console.log("data", data);
},
{
dataFormat: "object",
callbackOnDataChanged: true,
}
);
}
}
export default ButtonSample;

We currently provide three types of data reading methods: object, row, and column. The specific reading results are as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Asynchronously reads the data set in this field
* @since 4.2.0
* @param options
* * dataFormat: Optional values are "row", "column", "object". Default is "row".
* For the following example table data:
* | A | B | C |
* | a1 | b1 | c1 |
* | a2 | b2 | c2 |
* | a3 | b3 | c3 |
* The return results are as follows:
* "object" : [{A:"a1", B:"b1", C:"c1"}, {A:"a2", B:"b2", C:"c2"}, {A:"a3", B:"b3", C:"c3"}]
* "row" : [[a1, b1, c1], [a2, b2, c2], [a3, b3, c3]]
* "column" : [[a1, a2, a3], [b1, b2, b3], [c1, c2, c3]]
* @returns A Promise that resolves to the data read results
*/
async readDataAsync(options?: ReadDataAsyncOptions): Promise<any[]>;

After reloading the code, the printed results are as follows:

1.1.2 Merge reading of multiple attributes

Sometimes, we need multiple data attributes, and multiple attributes belong to the same attribute at the same time, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ButtonSample {
latitude = Field.default({
maxFields: 1, // The maximum number of fields allowed
});
longitude = Field.default({
maxFields: 1, // The maximum number of fields allowed
});
init() {
Field.readData(
[this.latitude, this.longitude],
(data) => {
// This callback is triggered whenever the data content changes or the data settings are modified
console.log("data", data);
},
{
dataFormat: "object",
callbackOnDataChanged: true,
}
);
}
}
export default ButtonSample;

1.2 Read existing data items of widgets

For data items of existing components, such as data fields in table data, secondary development also provides a way to read them, as follows:

First, we add a indicator card widget and bind the data:

Since this data item is generated by the widget itself, there is no direct reference to this attribute in the er code, so you need to call the method on the Element class to read it. For details, refer to the following API documentation: Element class

First, we need to get the path of the data field we need to read. Move the mouse to the data field, click on the three points, and choose to call the code example:

Open the window and copy the parameter value in getOption, which is the path of the attribute:

Similarly, we get the data content of the table in the click event:

Tip: We recommend using the readData method to read, because readData will trigger callbacks both when reading for the first time and when the data changes, so the data processing code can be written uniformly in the callback function, without having to handle the first reading and data changes separately.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TableSample {
init() {
this.element.readData(
["axis-fields"],
(data) => {
// This callback is triggered whenever the data content changes or the data settings are modified
console.log("data", data);
},
{
dataFormat: "object",
callbackOnDataChanged: true,
}
);
}
}
export default TableSample;

Click the indicator card to view the printed results:

2. Monitoring of data changes

Note that we can actually monitor data changes automatically when we use the readData method, and the callback will be automatically triggered when changes occur. However, sometimes we still need to monitor data changes separately. The following explains how to monitor in these cases.

There are actually two types of data changes: one is the change in data item settings, and the other is the change in data content:

2.1 Monitoring data field settings changes

There are also two types of changes in data field settings, which are the changes mentioned above, the data fields generated by the secondary development code or the changes in the data field settings that come with the component. The following introduces these two situations respectively:

2.1.1 Monitoring data field changes generated by secondary development code

You can refer to the previous monitoring method for secondary development property changes: onPropertyChanged. The specific code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
class ButtonSample {
setting = Field.default({
maxFields: 1, // Maximum number of fields allowed
});
async onPropertyChanged(property) {
if (property === "setting") {
// Note: Here we can't use readData because readData automatically listens for data changes
const data = await this.setting.readDataAsync();
console.log(data);
}
}
}
export default ButtonSample;

Drag the salesperson’s data field into the data field generated by the secondary development code. After releasing the mouse, you can see that the data results have been printed in the debug window:

2.1.2 Listening for changes in data fields that come with components

Different from the listening method in er, for listening to data fields that come with widgets, we use the method of listening to option-changed events on the Element class. For details, please refer to the API documentation: Element class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TableSample {
init() {
// For performance optimization, the property must be read once first in order to listen for its change events
const fields = this.element.getOption(["axis-fields"]);

this.element.addEventListener("option-changed", async (ev) => {
const paths = ev.paths;
// If multiple properties are being monitored, check if paths match the target value
if (Paths.equals(paths, ["axis-fields"])) {
const data = await this.element.readDataAsync(["axis-fields"], {
dataFormat: "object",
});
console.log(data);
}
});
}
}
export default TableSample;

2.2 Listening for changes in data content

To change the data content, you only need to listen to the data-changed event. The code is as follows:

1
2
3
4
5
6
7
8
9
10
11
class TableSample {
init() {
this.element.addEventListener("data-changed", async (ev) => {
const data = await this.element.readDataAsync(["axis-fields"], {
dataFormat: "object",
});
console.log(data);
});
}
}
export default TableSample;

3. Data linkage

Sometimes, we need to directly trigger or cancel data linkage in the secondary development code. Here we implement a function to filter table data by clicking a button, and then click again to cancel the filtering linkage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class ButtonSample {
setting = Field.default({
maxFields: 3, // Maximum number of fields
});
#linkageApplied = false;
init() {
this.element.addEventListener("click", () => {
if (!this.#linkageApplied) {
// Trigger data filter linkage on first click
// name: fill in the field name
// value: fill in the target value for the filter
this.element.applyLinkage({
name: "Region",
value: "North China",
});
} else {
// Cancel data filter linkage on the second click
this.element.withdrawLinkage();
}
this.#linkageApplied = !this.#linkageApplied;
});
}
}
export default ButtonSample;

We can also constrain multiple data conditions at the same time. The code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class ButtonSample {
setting = Field.default({
maxFields: 3, //最多能放几个字段
});
#linkageApplied = false;
init() {
this.element.addEventListener("click", () => {
if (!this.#linkageApplied) {
//name填入字段的名称
//value填入筛选的目标值
this.element.applyLinkage([
{
name: "地区",
value: "华北",
},
{
name: "销售员",
value: "张伟",
},
]);
} else {
this.element.withdrawLinkage();
}
this.#linkageApplied = !this.#linkageApplied;
});
}
}
export default ButtonSample;