Select to view content in your preferred language

Possible to call applyEdits without causing the layer to redraw?

887
2
Jump to solution
11-25-2021 07:33 PM
ewagstaff
Occasional Contributor

Hello all,

I am working on a custom web application using ArcGIS 4.19. We are dealing with some large data sets, often 20,000 features, and we occasionally want to be able to apply edits or delete them in a batch process. 

I'm using the applyEdits() function from the FeatureLayer, however because of the large size of these requests, passing all 20,000 features at once causes the API to time out and fail. To get around this, I've been able to take the request and chunk them up, making calls to applyEdits() with 500 features at a time. 

However, this strategy ends up being incredibly slow, mostly because ArcGIS attempted to redraw the layer on map after each call to applyEdits() -- one applyEdits() call results in the map performing 4 or 5 .pbf queries after completion. Normally, that's great behavior and keeps the map properly updated. But in my case, it's just slowing things down and I'd rather refresh the data once all the calls are complete.

Is there any way to tell ArcGIS to not refresh the map with this call? Nothing I could see in the documentation. I could switch to the REST implementation but I'd like to keep the JS API version if possible.

You can see the requests I'm talking about if you watch the network tab when updating features in ArcGIS' applyEdits example: https://developers.arcgis.com/javascript/latest/sample-code/editing-applyedits/

Let me know if you know of any possible work around here.

0 Kudos
1 Solution

Accepted Solutions
JeffreyWilkerson
Frequent Contributor

You could try to use "esri/request" for the changes. I don't think it updates the map automatically after an update.

Below is a class that I've used that separates out the deletes, adds, and updates. I wanted to perform any deletes first and make sure they were done before I did any adds or updates, that's why I'm using Promises in it, but you could send a JSON string will of your adds, deletes, and updates at the same time. The JSON was created before calling this class. 

require([
    "esri/Map",
    "esri/request"
], function (Map, esriRequest) {
...

function modifyRecords(jsonAdds, jsonUpdates, jsonDeletes, urlIn, sTable, deferred) {
    try {

        let urlDelete = urlIn + "/deleteFeatures";
        let urlAddUp = urlIn + "/applyEdits";

        // If deletes exist, perform them first
        let defDeletes = new Deferred();
        if (jsonDeletes.length > 0) {
            var postOptDelete = {};
            postOptDelete["method"] = "post";
            postOptDelete["responseType"] = "json";
            postOptDelete["query"] = { f: "json", objectIds: jsonDeletes };

            esriRequest(urlDelete, postOptDelete
            ).then(function (results) {
                if (results.data && results.data.deleteResults && results.data.deleteResults.length > 0) {
                    console.log("Delete Results: ", results.data.deleteResults);
                }
                else {
                    console.log("No deletes processed for " + sTable);
                }
                defDeletes.resolve(results);
            })
                .catch(function (error) {
                    console.error("ModifyRecords - Deletes: " + error);
                    defDeletes.reject(error);
                })

        }
        else {
            defDeletes.resolve("Empty");
            console.log("No deletes processed for " + sTable);
        }
        all(defDeletes).then(function (results) {
            let defAdds = new Deferred();
            if (jsonAdds.length > 0) {
                var postOptAdd = {};
                postOptAdd["method"] = "post";
                postOptAdd["responseType"] = "json";
                postOptAdd["query"] = { f: "json", "adds": JSON.stringify(jsonAdds), "updates": "", "deletes": "" };

                esriRequest(urlAddUp, postOptAdd
                ).then(function (results) {
                    if (results.data && results.data.addResults && results.data.addResults.length > 0) {
                        console.log("Add Results: ", results.data.addResults);

                    }
                    else {
                        console.log("No additions processed for " + sTable);
                    }
                    defAdds.resolve(results);
                })
                    .catch(function (error) {
                        console.error("ModifyRecords - Adds: " + error);
                        defAdds.reject(error);
                    })
            }
            else {
                defAdds.resolve("Empty");
                console.log("No additions processed for " + sTable);
            }

            all(defAdds).then(function (results) {

                if (jsonUpdates.length > 0) {
                    var postOptUpdate = {};
                    postOptUpdate["method"] = "post";
                    postOptUpdate["responseType"] = "json";
                    postOptUpdate["query"] = { f: "json", "adds": "", "updates": JSON.stringify(jsonUpdates), "deletes": "" };

                    esriRequest(urlAddUp, postOptUpdate
                    ).then(function (results) {
                        console.log(results);
                        if (results.data && results.data.updateResults && results.data.updateResults.length > 0) {
                            console.log("Update Results: ", results.data.updateResults); var objectIds = [];
                        }
                        else {
                            console.log("No updates processed for " + sTable);
                        }

                    })
                        .catch(function (error) {
                            console.error("ModifyRecords - Adds: " + error);
                            defAdds.reject(error);
                        })

                }
                else {
                    console.log("No updates processed for " + sTable);
                }
                deferred.resolve(results);
                return deferred.promise
            })
        })
    }
    catch (e) {
        console.log(e.message);
        deferred.reject(e.message);
        return deferred.promise;
    }
}

 

View solution in original post

0 Kudos
2 Replies
JeffreyWilkerson
Frequent Contributor

You could try to use "esri/request" for the changes. I don't think it updates the map automatically after an update.

Below is a class that I've used that separates out the deletes, adds, and updates. I wanted to perform any deletes first and make sure they were done before I did any adds or updates, that's why I'm using Promises in it, but you could send a JSON string will of your adds, deletes, and updates at the same time. The JSON was created before calling this class. 

require([
    "esri/Map",
    "esri/request"
], function (Map, esriRequest) {
...

function modifyRecords(jsonAdds, jsonUpdates, jsonDeletes, urlIn, sTable, deferred) {
    try {

        let urlDelete = urlIn + "/deleteFeatures";
        let urlAddUp = urlIn + "/applyEdits";

        // If deletes exist, perform them first
        let defDeletes = new Deferred();
        if (jsonDeletes.length > 0) {
            var postOptDelete = {};
            postOptDelete["method"] = "post";
            postOptDelete["responseType"] = "json";
            postOptDelete["query"] = { f: "json", objectIds: jsonDeletes };

            esriRequest(urlDelete, postOptDelete
            ).then(function (results) {
                if (results.data && results.data.deleteResults && results.data.deleteResults.length > 0) {
                    console.log("Delete Results: ", results.data.deleteResults);
                }
                else {
                    console.log("No deletes processed for " + sTable);
                }
                defDeletes.resolve(results);
            })
                .catch(function (error) {
                    console.error("ModifyRecords - Deletes: " + error);
                    defDeletes.reject(error);
                })

        }
        else {
            defDeletes.resolve("Empty");
            console.log("No deletes processed for " + sTable);
        }
        all(defDeletes).then(function (results) {
            let defAdds = new Deferred();
            if (jsonAdds.length > 0) {
                var postOptAdd = {};
                postOptAdd["method"] = "post";
                postOptAdd["responseType"] = "json";
                postOptAdd["query"] = { f: "json", "adds": JSON.stringify(jsonAdds), "updates": "", "deletes": "" };

                esriRequest(urlAddUp, postOptAdd
                ).then(function (results) {
                    if (results.data && results.data.addResults && results.data.addResults.length > 0) {
                        console.log("Add Results: ", results.data.addResults);

                    }
                    else {
                        console.log("No additions processed for " + sTable);
                    }
                    defAdds.resolve(results);
                })
                    .catch(function (error) {
                        console.error("ModifyRecords - Adds: " + error);
                        defAdds.reject(error);
                    })
            }
            else {
                defAdds.resolve("Empty");
                console.log("No additions processed for " + sTable);
            }

            all(defAdds).then(function (results) {

                if (jsonUpdates.length > 0) {
                    var postOptUpdate = {};
                    postOptUpdate["method"] = "post";
                    postOptUpdate["responseType"] = "json";
                    postOptUpdate["query"] = { f: "json", "adds": "", "updates": JSON.stringify(jsonUpdates), "deletes": "" };

                    esriRequest(urlAddUp, postOptUpdate
                    ).then(function (results) {
                        console.log(results);
                        if (results.data && results.data.updateResults && results.data.updateResults.length > 0) {
                            console.log("Update Results: ", results.data.updateResults); var objectIds = [];
                        }
                        else {
                            console.log("No updates processed for " + sTable);
                        }

                    })
                        .catch(function (error) {
                            console.error("ModifyRecords - Adds: " + error);
                            defAdds.reject(error);
                        })

                }
                else {
                    console.log("No updates processed for " + sTable);
                }
                deferred.resolve(results);
                return deferred.promise
            })
        })
    }
    catch (e) {
        console.log(e.message);
        deferred.reject(e.message);
        return deferred.promise;
    }
}

 

0 Kudos
ewagstaff
Occasional Contributor

This is fantastic, I didn't know this module existed. It does indeed update the layer without redrawing. Thanks so much!

0 Kudos