Webix DataProcessor is a mixin that lets you "communicate" with a server-side backend. DataProcessor:
Without DataProcessor, you need to attach corresponding functions to component events (onAfterInsert/Update/Delete) to get data ready for processing.
You can find the full list of DataProcessor methods, properties and events in the API Reference.
DataProcessor can be initialized during component initialization or standalone.
DataProcessor is created automatically if you define the save property of a data component. In the simplest case, save can be the path to the script for saving data:
webix.ui({
view:"datatable",
autoConfig:true,
url:"data_load.php", // your custom script for loading
save:"data_save.php" // your custom script for saving
});
Related sample: Server-side Integration: List
If you use the same script for loading and saving, set save as true:
webix.ui({
view:"datatable",
autoConfig:true,
url:"data_load.php", // your custom script for loading
save:true // same custom script for saving
});
DataProcessor can be initialized separately from a component. You can use either the dp helper or DataProcessor constructor.
const dp1 = webix.dp({
id:"listDP", // optional, the ID can be auto-generated
master:$$("mylist"),
url:"some_script.php",
//other properties
});
const dp2 = new webix.DataProcessor({
id:"listDP", // optional, the ID can be auto-generated
url:"data.php",
master:$$("mylist"),
//other properties
});
Both dp and constructor require the same parameter - an object with at least these 2 properties:
Go to the complete list of other parameters.
DataProcessor tracks client-side data operations and sends a POST request to the server script, specified in save. With the request, DataProcessor sends the name of the operation type:
Together with the operation name, request contains the data of the edited/added/deleted record.
Request Form Data
id 7
title The Shawshank Redemption
webix_operation delete
You can change the name of the field that stores operation name with the help of the operationName setting of DataProcessor.
Webix DataProcessor can also trigger RESTful server-side requests if you use the rest proxy. It this case, for each operation type a separate request type will be sent:
To use rest proxy, add "rest->" before the path to your script:
view: "datatable",
save: "rest->/samples/server/films",
"webix_operation" is not appended to request data, since the operation type is stated by the request type.
Related sample: Datatable: Data Saving with NodeJS
You can further customize DataProcessor logic for saving data. For example, you can define some preprocessing logic for request data and define the type of request. You can customize saving logic by defining the save property as:
1. 'save' as a function. In this case, the operation name is not appended to the sent data, but passed as a parameter of the function. All parameters are:
webix.ui({
view:"datatable",
save:function(id, operation, update){
if (operation === "insert")
return webix.ajax().post(
"/server/films",
update
);
/* ...other operations */
}
});
// or for standalone dataprocessor
const dp = new webix.DataProcessor({
master:"datatable1",
url: function(id, operation, update){
if (operation === "insert")
return webix.ajax().post(
"/server/films",
update
);
/* ...other operations */
}
});
2. You can provide saving logic for each type of data operation separately by defining 'save' as an object. Each property can be either the path to the script or a function:
webix.ui({
view:"datatable",
save:{
// functions or string URLs
insert: function(id, operation, update){
return webix.ajax().post(
"/server/films",
update
);
},
update: function(id, operation, update){ /* ... */ },
delete: function(id, operation, update){ /* ... */ }
}
});
3. You can also provide a data proxy for saving. Here you also must define the save function. Its parameters are:
With the save proxy, the operation name is available as a part of the update object:
Save proxy
view:"datatable",
save:{
$proxy:true,
save:function(view, update, dp){
var id = update.data.id;
if (update.operation == "insert")
return webix.ajax().post("/samples/server/films", update.data);
// ... other operations
}
}
Or for standalone initialization:
new webix DataProcessor({
master:"datatable1",
url: {
$proxy:true,
save:function(view, update, dp){ /* ... */ }
}
});
Related sample: Datatable: Saving Data with Proxy and Url
DataProcessor has a set of methods and properties for changing the default processing pattern.
If you want to use API of the DataProcessor during its initialization, you need to define save as an object with saving urls/functions in the url property and other properties. The DataProcessor configuration will look as follows:
webix.ui({
view:"datatable",
save:{
url: "some/path", // or function, object, proxy
on:{
onAfterSave(){ /* */ }
},
operationName: "operation",
/* ...other config properties */
}
});
To use DataProcessor API at runtime, you can access the DataProcessor with the Webix dp method either by the ID of the master component:
const dp = webix.dp($$("mylist")); // returns dataprocessor object for "list" view
Or by the ID of the DataProcessor, if you have set it during standalone initialization:
const dp = webix.dp($$("mydp"));
To indicate successful data saving, the server side should return a non-empty response with the following parameters:
IDs are necessary for the inserted records only. During adding, the record is added to the UI component where it receives the temporary client-side ID, while on the server it receives another ID provided by the database.
If you return this server-side ID as a response parameter, DataProcessor will automatically change the client-side ID for the correct server-side ID. Note that you can return only the id field as the new ID, or both id and newid for old and new IDs respectively.
To indicate data saving error, the server side should return a response containing:
Note that en empty response is also considered an error and will trigger error events with the status:"error" field.
Event handling is described below.
As it was stated earlier, the new ID from response of an insert request will automatically replace the temporary client-side ID. This is part of default DataProcessor behavior, and no specific actions are required.
Additionally, you can enable data update for all fields taking part in insert and update operations. It requires the following additions to the code:
Either during explicit DataProcessor definition
new webix.DataProcessor({
updateFromResponse:true,
master:"datatable1",
url:"..."
});
Or when defining DataProcessor implicitly
view:"datatable",
save:{
url:"...",
updateFromResponse:true
}
Related sample: Datatable: Updating
It can be useful for REST-full applications or when you need to fill in client-side fields which values can be calculated only on server side.
The event system for DataProcessor helps track different changes of data saving right on the client side. Here you can:
1) Modify data before it's gone to server with the onBeforeDataSend event that receives the whole data object as a parameter:
dp.attachEvent('onBeforeDataSend', function(obj){
obj.data.StartDate = webix.i18n.dateFormatStr(obj.data.StartDate);
});
Or attach operation-specific handlers, e.g. onBeforeDelete:
webix.dp($$("grid")).attachEvent("onBeforeDelete", function(id, action){
action.operation = "update";
action.data.deleted = webix.i18n.parseFormatStr(new Date());
});
2) Track successful server-side responses with the help of onAfterSync event:
Successful server response
dp.attachEvent('onAfterSync', function(statusObj, text, data, loader){
//statusObj {status:"success", id:"12"}
var hash = data.json().data;
//hash { id:"12"}
});
Check response data for more details.
3) Track unsuccessful server-side responses with onAfterSaveError event:
Unsuccessful server response
dp.attachEvent('onAfterSaveError', function(id, status, response, details){
// id - record id
// status - response status {id:"1", status:"error"}
});
To indicate an error that happened during saving, the response data should contain "error" or "invalid" status.
You can also catch the moment when the data changes are saved to the server with the help of the waitSave method of data components. waitSave expects a function with one or several data operations and returns a promise that resolves when data saving succeeds and rejects when it fails.
For example, this is how you can add data into the component and catch the result. When there is one data operation, the promise is resolved with an object that is returned from the server:
$$("grid").waitSave(function(){
this.add({
rank:99, title:"", year:"2012", votes:"100"
});
}).then(function(obj){
// server returns a data object with the server ID
$$("grid").select(obj.id);
});
If you want to catch the result of a several-operation save, the promise will resolve with an array of objects:
$$("grid").waitSave(function(){
for (var i = 0; i < 3; i++){
this.add({
rank:99, title:"", year:"2012", votes:"100"
});
}
}).then(function(arr){
for (var i = 0; i < arr.length; i++){
$$("grid").select(arr[i].id, i);
}
});
Related sample: Datatable: Wait Saving
If you do not want to save all updates to the server, you can temporarily cancel DataProcessor. There are several options for doing this:
webix.dp($$("grid")).ignore(function(){
$$("grid").add(data);
});
dp.off();
$$("grid").add(data);
dp.on();
//initially during dp configuration
new webix.DataProcessor({
master:"datatable1",
url:"...",
autoupdate:false
});
//dynamically
webix.dp($$("datatable1")).define("autoupdate", false);
To trigger sending of a specific data update, use the save method with the item ID and the operation name as parameters:
webix.dp($$("datatable1")).save(1, "update");
You can also save all changes at once - read more in Webix Proxy Objects.
DnD operations and data item moving can be tracked by DataProcessor like any other CRUD operation provided that you switch on DataProcessor trackMove functionality.
new webix.DataProcessor({
master: tree,
url: "...",
trackMove:true
});
Related sample: Server-side Integration: Tree
Data validation is enabled by including specific rules for input field. You can read about them here. With rules specified, the validation process starts each time you try to save data to the database.
dp = new webix.DataProcessor({
rules:{
$all:webix.rules.isNotEmpty
},
url: "save.php",
master: $$("mylist")
});
You cannot send headers with DataProcessor requests as they are executed in the background. There are other ways you can do this:
1. If DataProcessor sends requests on its own, you can catch Webix onBeforeAjax request to modify any Ajax request issued from the page:
webix.attachEvent("onBeforeAjax",
function(mode, url, data, request, headers, files, promise){
headers["Content-type"] = "application/json";
}
);
2. If you use the save function or a save proxy, you can add headers there with the webix.ajax().header() method.
Related sample: Saving: Proxy and Url
By default, all data changes are first applied on the client side and only after that are sent to the server. You can explicitly send data to the server at any moment with the help of the save method. save() expects the following parameters:
save() returns a promise that resolves with the server response object and can be used to update the client side data with the server response data. Note that to avoid one more data saving, you need to wrap the client-side data operation in ignore.
webix.dp($$("list")).save(
webix.uid(),
"insert",
{ name:"New User", email:"", roles:"" }
).then(function(obj){
webix.dp($$("list")).ignore(function(){
$$("list").add(obj);
});
});
To catch an unsuccessful result of data saving, add one more handler function to then():
webix.dp($$("list")).save(
webix.uid(),
"insert",
{ name:"New User", email:"", roles:"" }
).then(function(obj){
webix.dp($$("list")).ignore(function(){
$$("list").add(obj);
});
}, function(){
webix.message("Data were not saved");
});
Related sample: Datatable: Pessimistic Data Saving
DataProcessor can also be initialized without a master component:
var serverData = new webix.DataProcessor({ url:"/server/patients" });
The benefits of this approach are these:
Pessimistic data saving with a standalone dataprocessor will be shorter in code:
serverData.save(
webix.uid(),
"insert",
{ name:"New User", email:"", roles:"" }
).then(function(obj){
$$("list").add(obj);
});
Related sample: Datatable: Pessimistic Data Saving