diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c7133b2d4145f86547721996590a415900f3671..26e188f8ede95c5c709e3229b455645da840cc28 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,5 @@
 # Changelog
 
-
-
 ## [3.70.0] - 2024-06-25
 
 ### Add Features
@@ -9,15 +7,18 @@
 - complete change of form control to a derivation of dataset [#216](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/216)
 - new dataset feature refreshOnMutation [#215](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/215)
 - new comprehensive options display [#213](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/213)
+
 ### Bug Fixes
 
 - initialize of loaded html fields [#210](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/210)
 - values from the value attribute are now displayed correctly after loading the options. [#212](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/212)
 - If a value is specified in the select, it is now also displayed with a label from the options. [#212](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/212)
+
 ### Changes
 
 - doc, little bugs and tidy
 - test adjustments and minor layout adjustments
+
 ### Code Refactoring
 
 - adjustments to the form stylesheets [#214](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/214)
diff --git a/development/issues/closed/210.mjs b/development/issues/closed/210.mjs
index 42c71cbdb8aa3b635d5725c7f23361eda2d0c63a..66f0b33f6a6947901a587a80fd5730c52aa58d07 100644
--- a/development/issues/closed/210.mjs
+++ b/development/issues/closed/210.mjs
@@ -32,80 +32,10 @@ domReady.then(() => {
                 return;
             }
             fieldSet.insertAdjacentHTML('beforeend', html);
-            
-            
-//            form.refresh();
+            // form.refresh();
             
         });
 
 
 });
 
-
-
-/**
- * Interne Daten löschen, nicht übertragen
- * Änderungen werden global geändert
- * diese Werte stehen nach dem speichern nicht mehr zur Verfügung
-
-for (const [key, value] of Object.entries(data.dataset)) {
-    for (const [k, v] of Object.entries(data.dataset[key])) {
-        if (k.indexOf(internalDataPrefix) !== -1) {
-            delete data.dataset[key][k];
-        };
-    }
-}
-
-//nicht mit den Original daten arbeiten 
-//da sich so auch die Originaldaten ändern
-let currentData = clone(data);
-
-let d = diff(currentData.dataset,lastData.dataset);
-
-/**
- * Daten für den nächsten Vergleich speichern
-
-lastData = clone(currentData);
-
-let changedKeys = [];
-for (const [key, value] of Object.entries(d)) {
-    let index = value.path[0]
-    if(changedKeys.includes(index)===false){
-        changedKeys.push(index);
-    }
-}
-
-/**
- * Daten die sich nicht geändert haben löschen
-
-let updateData = [];
-for (const [key, value] of Object.entries(currentData.dataset)) {
-    if(changedKeys.includes(key)===true){
-        updateData.push(currentData.dataset[key]);
-    }
-};
-
-
-/**
- * Zeit umformatieren für die Daten die noch
- * übertragen werden sollen
-
-for (const [key, value] of Object.entries(updateData)) {
-    let time = updateData[key]?.scheduler?.time;
-    if (time !== undefined) {
-        /**
-         * Locale Zeit '2024-03-22T11:22:33'
-
-        let d = new Date(Date.parse(time));
-        /**
-         * UTC Zeit '2024-03-22T10:22:33.000Z'
-
-        d = d.toISOString();
-        updateData[key].scheduler.time = d;
-    }
-
-}
-
-return updateData;
-
-*/
\ No newline at end of file
diff --git a/development/issues/closed/217.html b/development/issues/closed/217.html
new file mode 100644
index 0000000000000000000000000000000000000000..8b88b8bdb22e407aa8b4668533d1ccdac4f429ad
--- /dev/null
+++ b/development/issues/closed/217.html
@@ -0,0 +1,71 @@
+        <!DOCTYPE html>
+        <html lang="en">
+        <head>
+            <meta charset="UTF-8">
+            <meta name="viewport" content="width=device-width, initial-scale=1.0">
+            <title>only try to transfer the part that has been changed #217</title>
+            <script src="./217.mjs" type="module"></script>
+        </head>
+        <body>
+            <h1>only try to transfer the part that has been changed #217</h1>
+            <p></p>
+            <ul>
+                <li><a href="https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/217">Issue #217</a></li>
+                <li><a href="/">Back to overview</a></li>
+            </ul>
+            <main>
+
+                <monster-datasource-rest id="ds210"
+                                         data-monster-option-read-url="/issue-217.json"
+                                         data-monster-option-write-url="/issue-217"
+                                         data-monster-option-write-acceptedstatus="400::200"
+                                         data-monster-option-features-autoinit="true">
+                </monster-datasource-rest>
+
+                <monster-dataset data-monster-option-index="0"
+                                 data-monster-option-datasource-selector="#ds210"
+                                 data-monster-option-mapping-data="">
+                    ID:
+                    <div data-monster-replace="path:data.id"></div>
+                    <div data-monster-replace="path:data.name"></div>
+                </monster-dataset>
+
+
+                <monster-form data-monster-option-datasource-selector="#ds210"
+                              data-monster-option-mapping-data=""
+                              data-monster-option-features-mutationobserver="true"
+                >
+
+                    <monster-field-set data-monster-option-labels-title="my title">
+
+                        <label for="id">field id</label><input id="id" type="number"
+                                                               data-monster-attributes="value path:data.id"
+                                                               data-monster-bind="path:data.id">
+
+                        <label for="field1">field id</label><input id="field1"
+                                                               data-monster-attributes="value path:data.field1"
+                                                               data-monster-bind="path:data.field1">
+
+                        <label for="field2">field id</label><input id="field2"
+                                                               data-monster-attributes="value path:data.field2"
+                                                               data-monster-bind="path:data.field2">
+
+                        <label for="field3">field id</label><input id="field3"
+                                                               data-monster-attributes="value path:data.field3"
+                                                               data-monster-bind="path:data.field3">
+
+                        
+                    </monster-field-set>
+                    <monster-field-set data-monster-option-labels-title="">
+
+                        <monster-datasource-save-button data-monster-option-datasource-selector="#ds210">ok
+                        </monster-datasource-save-button>
+
+                    </monster-field-set>
+
+
+                </monster-form>
+
+            </main>
+        </body>
+        </html>
diff --git a/development/issues/closed/217.mjs b/development/issues/closed/217.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..c9737abad038f65c70bbe0accad1b6356f40cf12
--- /dev/null
+++ b/development/issues/closed/217.mjs
@@ -0,0 +1,28 @@
+/**
+ * @file development/issues/open/217.mjs
+ * @url https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/217
+ * @description only try to transfer the part that has been changed
+ * @issue 217
+ */
+
+import "../../../source/components/style/property.pcss";
+import "../../../source/components/style/color.pcss";
+import "../../../source/components/style/normalize.pcss";
+import "../../../source/components/style/typography.pcss";
+import "../../../source/components/style/form.pcss";
+
+import "../../../source/components/datatable/datasource/rest.mjs";
+import "../../../source/components/datatable/save-button.mjs";
+import "../../../source/components/form/form.mjs";
+import "../../../source/components/form/field-set.mjs";
+import "../../../source/components/form/select.mjs";
+import "../../../source/components/form/context-help.mjs";
+import "../../../source/components/form/context-error.mjs";
+import {domReady} from "../../../source/dom/ready.mjs";
+
+domReady.then(() => {
+
+
+
+});
+
diff --git a/development/mock/issue-217.js b/development/mock/issue-217.js
new file mode 100644
index 0000000000000000000000000000000000000000..d3af360ed74fe4c3da01186f59eeb8ce37996272
--- /dev/null
+++ b/development/mock/issue-217.js
@@ -0,0 +1,76 @@
+const json = 
+    `{
+              "0":  {
+                    "id": 1000,
+                    "field1": "dataset 1, value field 1",
+                    "field2": "dataset 1, value field 2",
+                    "field3": "dataset 1, value field 3"
+                },
+               "1": {
+                    "id": 1001,
+                    "field1": "dataset 2, value field 1",
+                    "field2": "dataset 2, value field 2",
+                    "field3": "dataset 2, value field 3"
+                }
+               
+            }`;
+
+
+// check if json is valid
+JSON.parse(json)
+
+const json400Error=`[
+                {
+                    "sys": {
+                        "type": "Error",
+                        "message": "Invalid request"
+                    }
+                }
+            ]`
+
+// check if json is valid
+JSON.parse(json400Error)
+
+
+const json200Error=`[
+                {
+                    "sys": {
+                        "type": "Error",
+                        "message": "Invalid request"
+                    }
+                }
+            ]`
+
+// check if json is valid
+JSON.parse(json200Error)
+
+export default [
+    {
+        url: '/issue-217.json',
+        method: 'get',
+        rawResponse: async (req, res) => {
+            res.setHeader('Content-Type', 'application/json')
+            res.statusCode = 200
+
+            setTimeout(function() {
+                res.end(json)
+            }, 10);
+        },
+    },
+
+    {
+        url: '/issue-217',
+        method: 'post',
+        rawResponse: async (req, res) => {
+            res.setHeader('Content-Type', 'application/json')
+            res.statusCode = 400
+
+            setTimeout(function() {
+                res.end(json400Error)
+            }, 10);
+        },
+    }
+
+  
+
+];
\ No newline at end of file
diff --git a/source/components/datatable/datasource/rest.mjs b/source/components/datatable/datasource/rest.mjs
index 7d8fad6bca58b37ca5a9c4c30df2aebd35256011..e24ee30c6e7492d6cf173474470b9aa7ec5f4312 100644
--- a/source/components/datatable/datasource/rest.mjs
+++ b/source/components/datatable/datasource/rest.mjs
@@ -12,25 +12,27 @@
  * SPDX-License-Identifier: AGPL-3.0
  */
 
-import { addAttributeToken } from "../../../dom/attributes.mjs";
-import { ATTRIBUTE_ERRORMESSAGE } from "../../../dom/constants.mjs";
-import { Datasource, dataSourceSymbol } from "../datasource.mjs";
-import { DatasourceStyleSheet } from "../stylesheet/datasource.mjs";
-import { instanceSymbol } from "../../../constants.mjs";
+import {diff} from "../../../data/diff.mjs";
+import {addAttributeToken} from "../../../dom/attributes.mjs";
+import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs";
+import {isArray} from "../../../types/is.mjs";
+import {Datasource, dataSourceSymbol} from "../datasource.mjs";
+import {DatasourceStyleSheet} from "../stylesheet/datasource.mjs";
+import {instanceSymbol} from "../../../constants.mjs";
 import {
-	assembleMethodSymbol,
-	registerCustomElement,
+    assembleMethodSymbol,
+    registerCustomElement,
 } from "../../../dom/customelement.mjs";
-import { RestAPI } from "../../../data/datasource/server/restapi.mjs";
-import { Formatter } from "../../../text/formatter.mjs";
-import { clone } from "../../../util/clone.mjs";
-import { validateBoolean } from "../../../types/validate.mjs";
-import { findElementWithIdUpwards } from "../../../dom/util.mjs";
-import { Observer } from "../../../types/observer.mjs";
-import { Pathfinder } from "../../../data/pathfinder.mjs";
-import { fireCustomEvent } from "../../../dom/events.mjs";
+import {RestAPI} from "../../../data/datasource/server/restapi.mjs";
+import {Formatter} from "../../../text/formatter.mjs";
+import {clone} from "../../../util/clone.mjs";
+import {validateBoolean} from "../../../types/validate.mjs";
+import {findElementWithIdUpwards} from "../../../dom/util.mjs";
+import {Observer} from "../../../types/observer.mjs";
+import {Pathfinder} from "../../../data/pathfinder.mjs";
+import {fireCustomEvent} from "../../../dom/events.mjs";
 
-export { Rest };
+export {Rest};
 
 /**
  * @private
@@ -44,7 +46,7 @@ const intersectionObserverHandlerSymbol = Symbol("intersectionObserverHandler");
  * @type {symbol}
  */
 const rawDataSymbol = Symbol.for(
-	"@schukai/monster/data/datasource/server/restapi/rawdata",
+    "@schukai/monster/data/datasource/server/restapi/rawdata",
 );
 
 /**
@@ -52,7 +54,7 @@ const rawDataSymbol = Symbol.for(
  * @type {symbol}
  */
 const intersectionObserverObserverSymbol = Symbol(
-	"intersectionObserverObserver",
+    "intersectionObserverObserver",
 );
 
 /**
@@ -81,23 +83,23 @@ const filterObserverSymbol = Symbol("filterObserver");
  * @summary A rest api datasource
  */
 class Rest extends Datasource {
-	/**
-	 * the constructor of the class
-	 */
-	constructor() {
-		super();
-		this[dataSourceSymbol] = new RestAPI();
-	}
-
-	/**
-	 * This method is called by the `instanceof` operator.
-	 * @returns {symbol}
-	 */
-	static get [instanceSymbol]() {
-		return Symbol.for("@schukai/monster/components/datasource/rest@@instance");
-	}
-
-	/**
+    /**
+     * the constructor of the class
+     */
+    constructor() {
+        super();
+        this[dataSourceSymbol] = new RestAPI();
+    }
+
+    /**
+     * This method is called by the `instanceof` operator.
+     * @returns {symbol}
+     */
+    static get [instanceSymbol]() {
+        return Symbol.for("@schukai/monster/components/datasource/rest@@instance");
+    }
+
+    /**
      * To set the options via the html tag the attribute `data-monster-options` must be used.
      * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
      *
@@ -128,405 +130,409 @@ class Rest extends Datasource {
      * @property {Object} write Write configuration
 
      */
-	get defaults() {
-		const restOptions = new RestAPI().defaults;
-
-		restOptions.read.parameters = {
-			filter: undefined,
-			oderBy: undefined,
-			page: "1",
-		};
-
-		return Object.assign({}, super.defaults, restOptions, {
-			templates: {
-				main: getTemplate(),
-			},
-
-			features: {
-				autoInit: false,
-				filter: false,
-			},
-
-			autoInit: {
-				intersectionObserver: false,
-				oneTime: true,
-			},
-
-			filter: {
-				id: undefined,
-			},
-
-			datatable: {
-				id: undefined,
-			},
-
-			response: {
-				path: {
-					message: "sys.message",
-					code: "sys.code",
-				},
-			},
-		});
-	}
-
-	/**
-	 *
-	 * @param {string} page
-	 * @param {string} query
-	 * @param {string} orderBy
-	 * @returns {Monster.Components.Datatable.Datasource.Rest}
-	 */
-	setParameters({ page, query, orderBy }) {
-		const parameters = this.getOption("read.parameters");
-		if (query !== undefined) {
-			parameters.query = `${query}`;
-			parameters.page = "1";
-		}
-
-		// after a query the page is set to 1, so if the page is not set, it is set to 1
-		if (page !== undefined) parameters.page = `${page}`;
-		if (orderBy !== undefined) parameters.order = `${orderBy}`;
-		this.setOption("read.parameters", parameters);
-		return this;
-	}
-
-	/**
-	 * @return {void}
-	 */
-	[assembleMethodSymbol]() {
-		super[assembleMethodSymbol]();
-
-		initEventHandler.call(this);
-		initAutoInit.call(this);
-	}
-
-	/**
-	 * @deprecated 2023-06-25
-	 * @returns {Promise<never>|*}
-	 */
-	reload() {
-		return this.fetch();
-	}
-
-	/**
-	 * Fetches the data from the rest api
-	 * @returns {Promise<never>|*}
-	 */
-	fetch() {
-		const opt = clone(this.getOption("read"));
-		this[dataSourceSymbol].setOption("read", opt);
-
-		let url = this.getOption("read.url");
-		const formatter = new Formatter(this.getOption("read.parameters"));
-
-		if (!url) {
-			return Promise.reject(new Error("No url defined"));
-		}
-
-		url = formatter.format(url);
-
-		this[dataSourceSymbol].setOption("read.url", url);
-
-		return new Promise((resolve, reject) => {
-			fireCustomEvent(this, "monster-datasource-fetch", {
-				datasource: this,
-			});
-
-			setTimeout(() => {
-				this[dataSourceSymbol]
-					.read()
-					.then((response) => {
-						fireCustomEvent(this, "monster-datasource-fetched", {
-							datasource: this,
-						});
-
-						resolve(response);
-					})
-					.catch((error) => {
-						fireCustomEvent(this, "monster-datasource-error", {
-							error: error,
-						});
-
-						addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
-						reject(error);
-					});
-			}, 0);
-		});
-	}
-
-	/**
-	 *
-	 * @return {CSSStyleSheet[]}
-	 */
-	static getCSSStyleSheet() {
-		return [DatasourceStyleSheet];
-	}
-
-	/**
-	 * @private
-	 * @return {string}
-	 */
-	static getTag() {
-		return "monster-datasource-rest";
-	}
-
-	/**
-	 * This method activates the intersection observer manually.
-	 * For this purpose, the option `autoInit.intersectionObserver` must be set to `false`.
-	 *
-	 * @returns {Monster.Components.Datatable.Datasource.Rest}
-	 */
-	initIntersectionObserver() {
-		initIntersectionObserver.call(this);
-		return this;
-	}
-
-	/**
-	 * @private
-	 */
-	connectedCallback() {
-		super.connectedCallback();
-
-		setTimeout(() => {
-			if (this.getOption("features.filter", false) === true) {
-				initFilter.call(this);
-			}
-		}, 0);
-	}
-
-	/**
-	 * @private
-	 */
-	disconnectedCallback() {
-		super.disconnectedCallback();
-		removeFilter.call(this);
-	}
-
-	read() {
-		return this.fetch();
-	}
-
-	/**
-	 * Fetches the data from the rest api
-	 * @returns {Promise<never>|*}
-	 */
-	write() {
-		const opt = clone(this.getOption("write"));
-		this[dataSourceSymbol].setOption("write", opt);
-
-		let url = this.getOption("write.url");
-		const formatter = new Formatter(this.getOption("write.parameters"));
-
-		if (!url) {
-			return Promise.reject(new Error("No url defined"));
-		}
-
-		url = formatter.format(url);
-
-		this[dataSourceSymbol].setOption("write.url", url);
-
-		return new Promise((resolve, reject) => {
-			fireCustomEvent(this, "monster-datasource-fetch", {
-				datasource: this,
-			});
-
-			setTimeout(() => {
-				this[dataSourceSymbol]
-					.write()
-					.then((response) => {
-						fireCustomEvent(this, "monster-datasource-fetched", {
-							datasource: this,
-						});
-
-						resolve(response);
-					})
-					.catch((error) => {
-						fireCustomEvent(this, "monster-datasource-error", {
-							error: error,
-						});
-
-						addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
-						reject(error);
-					});
-			}, 0);
-		});
-	}
+    get defaults() {
+        const restOptions = new RestAPI().defaults;
+
+        restOptions.read.parameters = {
+            filter: undefined,
+            oderBy: undefined,
+            page: "1",
+        };
+
+        return Object.assign({}, super.defaults, restOptions, {
+            templates: {
+                main: getTemplate(),
+            },
+
+            features: {
+                autoInit: false,
+                filter: false,
+            },
+
+            autoInit: {
+                intersectionObserver: false,
+                oneTime: true,
+            },
+
+            filter: {
+                id: undefined,
+            },
+
+            datatable: {
+                id: undefined,
+            },
+
+            response: {
+                path: {
+                    message: "sys.message",
+                    code: "sys.code",
+                },
+            },
+        });
+    }
+
+    /**
+     *
+     * @param {string} page
+     * @param {string} query
+     * @param {string} orderBy
+     * @returns {Monster.Components.Datatable.Datasource.Rest}
+     */
+    setParameters({page, query, orderBy}) {
+        const parameters = this.getOption("read.parameters");
+        if (query !== undefined) {
+            parameters.query = `${query}`;
+            parameters.page = "1";
+        }
+
+        // after a query the page is set to 1, so if the page is not set, it is set to 1
+        if (page !== undefined) parameters.page = `${page}`;
+        if (orderBy !== undefined) parameters.order = `${orderBy}`;
+        this.setOption("read.parameters", parameters);
+        return this;
+    }
+
+    /**
+     * @return {void}
+     */
+    [assembleMethodSymbol]() {
+        super[assembleMethodSymbol]();
+
+        initEventHandler.call(this);
+        initAutoInit.call(this);
+    }
+
+    /**
+     * @deprecated 2023-06-25
+     * @returns {Promise<never>|*}
+     */
+    reload() {
+        return this.fetch();
+    }
+
+    /**
+     * Fetches the data from the rest api
+     * @returns {Promise<never>|*}
+     */
+    fetch() {
+        const opt = clone(this.getOption("read"));
+        this[dataSourceSymbol].setOption("read", opt);
+
+        let url = this.getOption("read.url");
+        const formatter = new Formatter(this.getOption("read.parameters"));
+
+        if (!url) {
+            return Promise.reject(new Error("No url defined"));
+        }
+
+        url = formatter.format(url);
+
+        this[dataSourceSymbol].setOption("read.url", url);
+
+        return new Promise((resolve, reject) => {
+            fireCustomEvent(this, "monster-datasource-fetch", {
+                datasource: this,
+            });
+
+            setTimeout(() => {
+                this[dataSourceSymbol]
+                    .read()
+                    .then((response) => {
+                        fireCustomEvent(this, "monster-datasource-fetched", {
+                            datasource: this,
+                        });
+
+                        resolve(response);
+                    })
+                    .catch((error) => {
+                        fireCustomEvent(this, "monster-datasource-error", {
+                            error: error,
+                        });
+
+                        addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
+                        reject(error);
+                    });
+            }, 0);
+        });
+    }
+
+    /**
+     *
+     * @return {CSSStyleSheet[]}
+     */
+    static getCSSStyleSheet() {
+        return [DatasourceStyleSheet];
+    }
+
+    /**
+     * @private
+     * @return {string}
+     */
+    static getTag() {
+        return "monster-datasource-rest";
+    }
+
+    /**
+     * This method activates the intersection observer manually.
+     * For this purpose, the option `autoInit.intersectionObserver` must be set to `false`.
+     *
+     * @returns {Monster.Components.Datatable.Datasource.Rest}
+     */
+    initIntersectionObserver() {
+        initIntersectionObserver.call(this);
+        return this;
+    }
+
+    /**
+     * @private
+     */
+    connectedCallback() {
+        super.connectedCallback();
+
+        setTimeout(() => {
+            if (this.getOption("features.filter", false) === true) {
+                initFilter.call(this);
+            }
+        }, 0);
+    }
+
+    /**
+     * @private
+     */
+    disconnectedCallback() {
+        super.disconnectedCallback();
+        removeFilter.call(this);
+    }
+
+    /**
+     * @returns {Promise<never>|*}
+     */
+    read() {
+        return this.fetch();
+    }
+
+    /**
+     * Fetches the data from the rest api
+     * @returns {Promise<never>|*}
+     */
+    write() {
+        const opt = clone(this.getOption("write"));
+        this[dataSourceSymbol].setOption("write", opt);
+
+        let url = this.getOption("write.url");
+        const formatter = new Formatter(this.getOption("write.parameters"));
+
+        if (!url) {
+            return Promise.reject(new Error("No url defined"));
+        }
+
+        url = formatter.format(url);
+
+        this[dataSourceSymbol].setOption("write.url", url);
+
+        return new Promise((resolve, reject) => {
+            fireCustomEvent(this, "monster-datasource-fetch", {
+                datasource: this,
+            });
+            
+            setTimeout(() => {
+                this[dataSourceSymbol]
+                    .write()
+                    .then((response) => {
+                        fireCustomEvent(this, "monster-datasource-fetched", {
+                            datasource: this,
+                        });
+
+                        resolve(response);
+                    })
+                    .catch((error) => {
+                        fireCustomEvent(this, "monster-datasource-error", {
+                            error: error,
+                        });
+
+                        addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
+                        reject(error);
+                    });
+            }, 0);
+        });
+    }
 }
 
 /**
  * @private
  */
 function removeFilter() {
-	const filterID = this.getOption("filter.id", undefined);
-	if (!filterID) return;
+    const filterID = this.getOption("filter.id", undefined);
+    if (!filterID) return;
 
-	const filterControl = findElementWithIdUpwards(this, filterID);
+    const filterControl = findElementWithIdUpwards(this, filterID);
 
-	if (filterControl && this[filterObserverSymbol]) {
-		filterControl?.detachObserver(this[filterObserverSymbol]);
-	}
+    if (filterControl && this[filterObserverSymbol]) {
+        filterControl?.detachObserver(this[filterObserverSymbol]);
+    }
 }
 
 /**
  * @private
  */
 function initFilter() {
-	const filterID = this.getOption("filter.id", undefined);
-
-	if (!filterID)
-		throw new Error("filter feature is enabled but no filter id is defined");
-
-	const filterControl = findElementWithIdUpwards(this, filterID);
-	if (!filterControl)
-		throw new Error(
-			"filter feature is enabled but no filter control with id " +
-				filterID +
-				" is found",
-		);
-
-	this[filterObserverSymbol] = new Observer(() => {
-		const query = filterControl.getOption("query");
-		if ( query===undefined) {
-			return;
-		}
-		this.setParameters({ query: query });
-		this.fetch()
-			.then((response) => {
-				if (!(response instanceof Response)) {
-					throw new Error("Response is not an instance of Response");
-				}
-
-				if (response?.ok === true) {
-					this.dispatchEvent(new CustomEvent("reload", { bubbles: true }));
-					filterControl?.showSuccess();
-				}
-
-				if (response.bodyUsed === true) {
-					return handleIntersectionObserver.call(
-						this,
-						response[rawDataSymbol],
-						response,
-						filterControl,
-					);
-				}
-
-				response
-					.text()
-					.then((jsonAsText) => {
-						let json;
-						try {
-							json = JSON.parse(jsonAsText);
-						} catch (e) {
-							const message = e instanceof Error ? e.message : `${e}`;
-							filterControl?.showFailureMessage(message);
-							return Promise.reject(e);
-						}
-
-						return handleIntersectionObserver.call(
-							this,
-							json,
-							response,
-							filterControl,
-						);
-					})
-					.catch((e) => {
-						filterControl?.showFailureMessage(e.message);
-					});
-			})
-			.catch((e) => {
-				this.dispatchEvent(
-					new CustomEvent("error", { bubbles: true, detail: e }),
-				);
-
-				if (!(e instanceof Error)) {
-					e = new Error(e);
-				}
-
-				filterControl?.showFailureMessage(e.message);
-				return Promise.reject(e);
-			});
-	});
-
-	filterControl.attachObserver(this[filterObserverSymbol]);
+    const filterID = this.getOption("filter.id", undefined);
+
+    if (!filterID)
+        throw new Error("filter feature is enabled but no filter id is defined");
+
+    const filterControl = findElementWithIdUpwards(this, filterID);
+    if (!filterControl)
+        throw new Error(
+            "filter feature is enabled but no filter control with id " +
+            filterID +
+            " is found",
+        );
+
+    this[filterObserverSymbol] = new Observer(() => {
+        const query = filterControl.getOption("query");
+        if (query === undefined) {
+            return;
+        }
+        this.setParameters({query: query});
+        this.fetch()
+            .then((response) => {
+                if (!(response instanceof Response)) {
+                    throw new Error("Response is not an instance of Response");
+                }
+
+                if (response?.ok === true) {
+                    this.dispatchEvent(new CustomEvent("reload", {bubbles: true}));
+                    filterControl?.showSuccess();
+                }
+
+                if (response.bodyUsed === true) {
+                    return handleIntersectionObserver.call(
+                        this,
+                        response[rawDataSymbol],
+                        response,
+                        filterControl,
+                    );
+                }
+
+                response
+                    .text()
+                    .then((jsonAsText) => {
+                        let json;
+                        try {
+                            json = JSON.parse(jsonAsText);
+                        } catch (e) {
+                            const message = e instanceof Error ? e.message : `${e}`;
+                            filterControl?.showFailureMessage(message);
+                            return Promise.reject(e);
+                        }
+
+                        return handleIntersectionObserver.call(
+                            this,
+                            json,
+                            response,
+                            filterControl,
+                        );
+                    })
+                    .catch((e) => {
+                        filterControl?.showFailureMessage(e.message);
+                    });
+            })
+            .catch((e) => {
+                this.dispatchEvent(
+                    new CustomEvent("error", {bubbles: true, detail: e}),
+                );
+
+                if (!(e instanceof Error)) {
+                    e = new Error(e);
+                }
+
+                filterControl?.showFailureMessage(e.message);
+                return Promise.reject(e);
+            });
+    });
+
+    filterControl.attachObserver(this[filterObserverSymbol]);
 }
 
 function handleIntersectionObserver(json, response, filterControl) {
-	const path = new Pathfinder(json);
-
-	const codePath = this.getOption("response.path.code");
-
-	if (path.exists(codePath)) {
-		const code = `${path.getVia(codePath)}`;
-		if (code && code === "200") {
-			filterControl?.showSuccess();
-			return Promise.resolve(response);
-		}
-
-		const messagePath = this.getOption("response.path.message");
-		if (path.exists(messagePath)) {
-			const message = path.getVia(messagePath);
-			filterControl?.showFailureMessage(message);
-			return Promise.reject(new Error(message));
-		}
-
-		return Promise.reject(new Error("Response code is not 200"));
-	}
+    const path = new Pathfinder(json);
+
+    const codePath = this.getOption("response.path.code");
+
+    if (path.exists(codePath)) {
+        const code = `${path.getVia(codePath)}`;
+        if (code && code === "200") {
+            filterControl?.showSuccess();
+            return Promise.resolve(response);
+        }
+
+        const messagePath = this.getOption("response.path.message");
+        if (path.exists(messagePath)) {
+            const message = path.getVia(messagePath);
+            filterControl?.showFailureMessage(message);
+            return Promise.reject(new Error(message));
+        }
+
+        return Promise.reject(new Error("Response code is not 200"));
+    }
 }
 
 /**
  * @private
  */
 function initAutoInit() {
-	
-	const autoInit = this.getOption("features.autoInit");
-	validateBoolean(autoInit);
 
-	if (autoInit !== true) return;
+    const autoInit = this.getOption("features.autoInit");
+    validateBoolean(autoInit);
+
+    if (autoInit !== true) return;
 
-	if (this.getOption("autoInit.intersectionObserver") === true) {
-		initIntersectionObserver.call(this);
-		return;
-	}
+    if (this.getOption("autoInit.intersectionObserver") === true) {
+        initIntersectionObserver.call(this);
+        return;
+    }
 
-	setTimeout(() => {
-		this.fetch().catch(() => {});
-	}, 0);
+    setTimeout(() => {
+        this.fetch().catch(() => {
+        });
+    }, 0);
 }
 
 function initEventHandler() {
-	this[intersectionObserverHandlerSymbol] = (entries) => {
-		entries.forEach((entry) => {
-			if (entry.isIntersecting) {
-				if (entry.intersectionRatio > 0) {
-					this.fetch();
-				}
-
-				// only load once
-				if (
-					this.getOption("autoInit.oneTime") === true &&
-					this[intersectionObserverObserverSymbol] !== undefined
-				) {
-					this[intersectionObserverObserverSymbol].unobserve(this);
-				}
-			}
-		});
-	};
+    this[intersectionObserverHandlerSymbol] = (entries) => {
+        entries.forEach((entry) => {
+            if (entry.isIntersecting) {
+                if (entry.intersectionRatio > 0) {
+                    this.fetch();
+                }
+
+                // only load once
+                if (
+                    this.getOption("autoInit.oneTime") === true &&
+                    this[intersectionObserverObserverSymbol] !== undefined
+                ) {
+                    this[intersectionObserverObserverSymbol].unobserve(this);
+                }
+            }
+        });
+    };
 }
 
 function initIntersectionObserver() {
-	this.classList.add("intersection-observer");
-
-	const options = {
-		root: null,
-		rootMargin: "0px",
-		threshold: 0.1,
-	};
-
-	this[intersectionObserverObserverSymbol] = new IntersectionObserver(
-		this[intersectionObserverHandlerSymbol],
-		options,
-	);
-	this[intersectionObserverObserverSymbol].observe(this);
+    this.classList.add("intersection-observer");
+
+    const options = {
+        root: null,
+        rootMargin: "0px",
+        threshold: 0.1,
+    };
+
+    this[intersectionObserverObserverSymbol] = new IntersectionObserver(
+        this[intersectionObserverHandlerSymbol],
+        options,
+    );
+    this[intersectionObserverObserverSymbol].observe(this);
 }
 
 /**
@@ -534,8 +540,8 @@ function initIntersectionObserver() {
  * @return {string}
  */
 function getTemplate() {
-	// language=HTML
-	return `
+    // language=HTML
+    return `
         <slot></slot>`;
 }
 
diff --git a/source/components/datatable/save-button.mjs b/source/components/datatable/save-button.mjs
index 9908bc2104412c7c082a61dad1b9c9d292ad1ee9..e5490d27848a91f6632f3397bf6404086138204b 100644
--- a/source/components/datatable/save-button.mjs
+++ b/source/components/datatable/save-button.mjs
@@ -77,9 +77,6 @@ class SaveButton extends CustomElement {
 	 * @property {Object} classes The classes
 	 * @property {string} classes.bar The bar class
 	 * @property {string} classes.badge The badge class
-	 * @property {object} mapping The mapping
-	 * @property {string} mapping.data The data
-	 * @property {number} mapping.index The index
 	 * @property {Array} ignoreChanges The ignore changes (regex)
 	 * @property {Array} data The data
 	 * @return {Object}
@@ -105,11 +102,6 @@ class SaveButton extends CustomElement {
 
 			changes: "0",
 
-			mapping: {
-				data: "dataset",
-				index: 0,
-			},
-
 			ignoreChanges: [],
 
 			data: {},
diff --git a/source/components/form/form.mjs b/source/components/form/form.mjs
index c75adad72ef47e3a3d84fbdd6967502d86d6e18d..7d7f02ead3a7e4a5e91f4539fc8d3bdb1debb913 100644
--- a/source/components/form/form.mjs
+++ b/source/components/form/form.mjs
@@ -164,13 +164,6 @@ class Form extends DataSet {
 }
 
 function initDataSourceHandler() {
-    if (!this[datasourceLinkedElementSymbol]) {
-        return;
-    }
-console.log(this[datasourceLinkedElementSymbol]);
-    this[datasourceLinkedElementSymbol].setOption("write.responseCallback", (response) => {
-        console.log("response!!!", response);
-    })
 
 }
 
diff --git a/source/data/datasource/server.mjs b/source/data/datasource/server.mjs
index e062ed2bc854a1145a743a17efa3f5456812d9bf..d7dc4ca5e4be2df3f1e6dd9c218091d3348fa744 100644
--- a/source/data/datasource/server.mjs
+++ b/source/data/datasource/server.mjs
@@ -12,13 +12,21 @@
  * SPDX-License-Identifier: AGPL-3.0
  */
 
-import { internalSymbol, instanceSymbol } from "../../constants.mjs";
-import { isObject } from "../../types/is.mjs";
-import { Datasource } from "../datasource.mjs";
-import { Pathfinder } from "../pathfinder.mjs";
-import { Pipe } from "../pipe.mjs";
+import {instanceSymbol} from "../../constants.mjs";
+import {isArray, isFunction, isObject} from "../../types/is.mjs";
+import {Datasource} from "../datasource.mjs";
+import {diff} from "../diff.mjs";
+import {Pathfinder} from "../pathfinder.mjs";
+import {Pipe} from "../pipe.mjs";
 
-export { Server };
+export {Server};
+
+
+/**
+ * @private
+ * @type {symbol}
+ */
+const serverVersionSymbol = Symbol("serverVersion");
 
 /**
  * Base class for all server data sources
@@ -30,54 +38,82 @@ export { Server };
  * @summary The Server class encapsulates the access to a server datasource
  */
 class Server extends Datasource {
-	/**
-	 * This method is called by the `instanceof` operator.
-	 * @returns {symbol}
-	 */
-	static get [instanceSymbol]() {
-		return Symbol.for("@schukai/monster/data/datasource/server");
-	}
-
-	/**
-	 * This prepares the data that comes from the server.
-	 * Should not be called directly.
-	 *
-	 * @private
-	 * @param {Object} payload
-	 * @returns {Object}
-	 */
-	transformServerPayload(payload) {
-		payload = doTransform.call(this, "read", payload);
-
-		const dataPath = this.getOption("read.path");
-		if (dataPath) {
-			payload = new Pathfinder(payload).getVia(dataPath);
-		}
-
-		return payload;
-	}
-
-	/**
-	 * This prepares the data for writing and should not be called directly.
-	 *
-	 * @private
-	 * @param {Object} payload
-	 * @returns {Object}
-	 */
-	prepareServerPayload(payload) {
-		payload = doTransform.call(this, "write", payload);
-
-		const sheathingObject = this.getOption("write.sheathing.object");
-		const sheathingPath = this.getOption("write.sheathing.path");
-
-		if (sheathingObject && sheathingPath) {
-			const sub = payload;
-			payload = sheathingObject;
-			new Pathfinder(payload).setVia(sheathingPath, sub);
-		}
-
-		return payload;
-	}
+    /**
+     * This method is called by the `instanceof` operator.
+     * @returns {symbol}
+     */
+    static get [instanceSymbol]() {
+        return Symbol.for("@schukai/monster/data/datasource/server");
+    }
+
+    /**
+     * This prepares the data that comes from the server.
+     * Should not be called directly.
+     *
+     * @private
+     * @param {Object} payload
+     * @returns {Object}
+     */
+    transformServerPayload(payload) {
+        payload = doTransform.call(this, "read", payload);
+        this[serverVersionSymbol] = payload;
+
+        const dataPath = this.getOption("read.path");
+        if (dataPath) {
+            payload = new Pathfinder(payload).getVia(dataPath);
+        }
+
+        return payload;
+    }
+
+    /**
+     * This prepares the data for writing and should not be called directly.
+     *
+     * @private
+     * @param {Object} payload
+     * @returns {Object}
+     */
+    prepareServerPayload(payload) {
+        payload = doTransform.call(this, "write", payload);
+        payload = doDiff.call(this, payload);
+
+        const sheathingObject = this.getOption("write.sheathing.object");
+        const sheathingPath = this.getOption("write.sheathing.path");
+
+        if (sheathingObject && sheathingPath) {
+            const sub = payload;
+            payload = sheathingObject;
+            new Pathfinder(payload).setVia(sheathingPath, sub);
+        }
+
+        return payload;
+    }
+}
+
+/**
+ * 
+ * @param obj
+ * @returns {*}
+ */
+function doDiff(obj) {
+    if (this[serverVersionSymbol] === null || this[serverVersionSymbol] === undefined) {
+        return obj;
+    }
+
+    const callback = this.getOption("write.partial.callback");
+    if (!isFunction(callback)) {
+        return obj;
+    }
+
+    const results = diff(this[serverVersionSymbol], obj);
+    if (!results) {
+        return obj;
+    }
+
+    obj = callback(obj, results);
+    this[serverVersionSymbol] = obj;
+
+    return obj;
 }
 
 /**
@@ -87,24 +123,32 @@ class Server extends Datasource {
  * @returns {Object}
  */
 function doTransform(type, obj) {
-	const transformation = this.getOption(`${type}.mapping.transformer`);
-	if (transformation !== undefined && transformation !== null) {
-		const pipe = new Pipe(transformation);
-		const callbacks = this.getOption(`${type}.mapping.callbacks`);
-
-		if (isObject(callbacks)) {
-			for (const key in callbacks) {
-				if (
-					callbacks.hasOwnProperty(key) &&
-					typeof callbacks[key] === "function"
-				) {
-					pipe.setCallback(key, callbacks[key]);
-				}
-			}
-		}
-
-		obj = pipe.run(obj);
-	}
-
-	return obj;
+    const transformation = this.getOption(`${type}.mapping.transformer`);
+    if (transformation !== undefined && transformation !== null) {
+        const pipe = new Pipe(transformation);
+        const callbacks = this.getOption(`${type}.mapping.callbacks`);
+
+        if (isArray(callbacks)) {
+            for (const callback of callbacks) {
+                if (typeof callback === "function") {
+                    pipe.setCallback(callback);
+                }
+            }
+        }
+
+        if (isObject(callbacks)) {
+            for (const key in callbacks) {
+                if (
+                    callbacks.hasOwnProperty(key) &&
+                    typeof callbacks[key] === "function"
+                ) {
+                    pipe.setCallback(key, callbacks[key]);
+                }
+            }
+        }
+
+        obj = pipe.run(obj);
+    }
+
+    return obj;
 }
diff --git a/source/data/datasource/server/restapi.mjs b/source/data/datasource/server/restapi.mjs
index 04cab9ef51f0228d0ae391e49959472f8cec0381..d6f92235fec85b05e5b85b65657ea06b61c1a3f9 100644
--- a/source/data/datasource/server/restapi.mjs
+++ b/source/data/datasource/server/restapi.mjs
@@ -13,7 +13,8 @@
  */
 
 import {internalSymbol, instanceSymbol} from "../../../constants.mjs";
-import {isObject, isFunction} from "../../../types/is.mjs";
+import {isObject, isFunction, isArray} from "../../../types/is.mjs";
+import {diff} from "../../diff.mjs";
 import {Server} from "../server.mjs";
 import {WriteError} from "./restapi/writeerror.mjs";
 import {DataFetchError} from "./restapi/data-fetch-error.mjs";
@@ -30,6 +31,7 @@ const rawDataSymbol = Symbol.for(
     "@schukai/monster/data/datasource/server/restapi/rawdata",
 );
 
+
 /**
  * The RestAPI is a class that enables a REST API server.
  *
@@ -75,6 +77,8 @@ class RestAPI extends Server {
      * @property {Monster.Data.Datasource~exampleCallback[]} write.mapping.callback with the help of the callback, the structures can be adjusted before writing.
      * @property {Object} write.report
      * @property {String} write.report.path Path to validations
+     * @property {Object} write.partial
+     * @property {Function} write.partial.callback Callback function to be executed after the request has been completed. (obj, diffResult) => obj
      * @property {Object} write.sheathing
      * @property {Object} write.sheathing.object Object to be wrapped
      * @property {string} write.sheathing.path Path to the data
@@ -107,6 +111,10 @@ class RestAPI extends Server {
                 report: {
                     path: undefined,
                 },
+
+                partial: {
+                    callback: null,
+                }
             },
             read: {
                 init: {
@@ -135,10 +143,11 @@ class RestAPI extends Server {
         if (!init["method"]) init["method"] = "GET";
 
         let callback = this.getOption("read.responseCallback");
-        if (!callback)
+        if (!callback) {
             callback = (obj) => {
                 this.set(this.transformServerPayload.call(this, obj));
             };
+        }
 
         return fetchData.call(this, init, "read", callback);
     }
@@ -189,7 +198,7 @@ function fetchData(init, key, callback) {
         .then((resp) => {
             response = resp;
 
-            const acceptedStatus =  this.getOption(`${key}.acceptedStatus`, [200]).map(Number);
+            const acceptedStatus = this.getOption(`${key}.acceptedStatus`, [200]).map(Number);
 
             if (acceptedStatus.indexOf(resp.status) === -1) {
                 throw new DataFetchError(
diff --git a/source/data/diff.mjs b/source/data/diff.mjs
index 96bbd4398098c2472a5c4675977c0f655e116e33..99abde3badb44b4a52efd8bc1fcda700d6d2fa73 100644
--- a/source/data/diff.mjs
+++ b/source/data/diff.mjs
@@ -183,4 +183,4 @@ function getOperator(a, b) {
 	}
 
 	return operator;
-}
+}
\ No newline at end of file
diff --git a/test/cases/data/diff.mjs b/test/cases/data/diff.mjs
index 5013de024de448b158950c6332c1d50dd25cc702..222e093ef41770f980ed2961da84ffbcf49f1368 100644
--- a/test/cases/data/diff.mjs
+++ b/test/cases/data/diff.mjs
@@ -6,6 +6,43 @@ import {Queue} from "../../../source/types/queue.mjs";
 
 describe('Diff', function () {
 
+    describe('test to datasets', function () {
+
+        var obj1, obj2;
+
+        beforeEach(() => {
+            obj1 = [
+                {
+                    "id": 1,
+                    "name": "test"
+                },
+                {
+                    "id": 2,
+                    "name": "test2"
+                }
+            ]
+
+            obj2 = [
+                {
+                    "id": 1,
+                    "name": "test"
+                },
+                {
+                    "id": "3",
+                    "name": "test2"
+                }
+            ]
+
+        });
+
+        it('should return the difference between two datasets', function () {
+            let d = diff(obj1, obj2);
+            expect(JSON.stringify(d)).is.equal('[{"operator":"update","path":["1","id"],"first":{"value":2,"type":"number"},"second":{"value":"3","type":"string"}}]');
+        });
+        
+        
+    })
+    
     describe('Diff special cases', function () {
 
         var obj1, obj2;