From 4a5b70f1636eebdd388b46ab8f24fa6c72faf03a Mon Sep 17 00:00:00 2001 From: Nicolas Guilhaudin Date: Sat, 7 Apr 2018 20:03:10 +0200 Subject: [PATCH 1/4] add and update several features in FeatureLayer --- .../Layers/FeatureLayer/FeatureManagerSpec.js | 48 +++++++++++++++++++ spec/Tasks/FindSpec.js | 2 - spec/Tasks/IdentifyImageSpec.js | 2 - spec/Tasks/QuerySpec.js | 1 - src/Layers/FeatureLayer/FeatureManager.js | 42 ++++++++++++++++ src/Services/FeatureLayerService.js | 28 +++++++++++ 6 files changed, 118 insertions(+), 5 deletions(-) diff --git a/spec/Layers/FeatureLayer/FeatureManagerSpec.js b/spec/Layers/FeatureLayer/FeatureManagerSpec.js index b6d39dc02..14a111866 100644 --- a/spec/Layers/FeatureLayer/FeatureManagerSpec.js +++ b/spec/Layers/FeatureLayer/FeatureManagerSpec.js @@ -756,6 +756,54 @@ describe('L.esri.FeatureManager', function () { server.respond(); }); + it('should wrap the updateFeatures method on the underlying service and refresh', function (done) { + server.respondWith('POST', 'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/updateFeatures', JSON.stringify({ + 'updateResults': [{ + 'objectId': 1, + 'success': true + }, { + 'objectId': 2, + 'success': true + }] + })); + + layer.updateFeatures({ + type: 'FeatureCollecton', + features: [{ + type: 'Point', + id: 1, + properties: { + foo: 'bar' + }, + geometry: { + type: 'Point', + coordinates: [45, -121] + } + }, { + type: 'Point', + id: 2, + properties: { + foo: 'bar' + }, + geometry: { + type: 'Point', + coordinates: [45, -121] + } + }] + }, function (error, response) { + expect(response).to.deep.equal([{ + 'objectId': 1, + 'success': true + }, { + 'objectId': 2, + 'success': true + }]); + done(); + }); + + server.respond(); + }); + it('should wrap the removeFeature method on the underlying service', function (done) { server.respondWith('POST', 'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/deleteFeatures', JSON.stringify({ 'deleteResults': [{ diff --git a/spec/Tasks/FindSpec.js b/spec/Tasks/FindSpec.js index d6a70c220..2cf8234eb 100644 --- a/spec/Tasks/FindSpec.js +++ b/spec/Tasks/FindSpec.js @@ -240,8 +240,6 @@ describe('L.esri.Find', function () { done(); }); - console.log(request.url); - expect(request).to.be.an.instanceof(XMLHttpRequest); server.respond(); diff --git a/spec/Tasks/IdentifyImageSpec.js b/spec/Tasks/IdentifyImageSpec.js index acb61ec7b..25f42adcf 100644 --- a/spec/Tasks/IdentifyImageSpec.js +++ b/spec/Tasks/IdentifyImageSpec.js @@ -404,8 +404,6 @@ describe('L.esri.IdentifyImage', function () { task.returnGeometry(true).returnCatalogItems(true); task.run(function (error, results, raw) { - console.log(JSON.stringify(results)); - console.log(JSON.stringify(sampleResultsWithCatalogItems)); expect(results).to.deep.equal(sampleResultsWithCatalogItems); expect(raw).to.deep.equal(sampleResponseWithCatalogItems); done(); diff --git a/spec/Tasks/QuerySpec.js b/spec/Tasks/QuerySpec.js index 1b212988a..c2b8b50b9 100644 --- a/spec/Tasks/QuerySpec.js +++ b/spec/Tasks/QuerySpec.js @@ -919,7 +919,6 @@ describe('L.esri.Query', function () { done(); }); - console.log(request); expect(request.requestBody).to.contain('foo=bar'); server.respond(); }); diff --git a/src/Layers/FeatureLayer/FeatureManager.js b/src/Layers/FeatureLayer/FeatureManager.js index a266f4656..b34071739 100644 --- a/src/Layers/FeatureLayer/FeatureManager.js +++ b/src/Layers/FeatureLayer/FeatureManager.js @@ -507,6 +507,31 @@ export var FeatureManager = VirtualGrid.extend({ }, this)); }, + addFeatures: function (featureCollection, callback, context) { + this._getMetadata(Util.bind(function (error, metadata) { + if (error) { + if (callback) { callback.call(this, error, null); } + return; + } + + this.service.addFeatures(featureCollection, Util.bind(function (error, response) { + if (!error) { + for (var i = featureCollection.features.length - 1; i >= 0; i--) { + // assign ID from result to appropriate objectid field from service metadata + featureCollection.features[i].properties[metadata.objectIdField] = response[i].objectId; + // we also need to update the geojson id for createLayers() to function + featureCollection.features[i].id = response[i].objectId; + } + this.createLayers(featureCollection.features); + } + + if (callback) { + callback.call(context, error, response); + } + }, this)); + }, this)); + }, + updateFeature: function (feature, callback, context) { this.service.updateFeature(feature, function (error, response) { if (!error) { @@ -520,6 +545,23 @@ export var FeatureManager = VirtualGrid.extend({ }, this); }, + updateFeatures: function (featureCollection, callback, context) { + this.service.updateFeatures(featureCollection, function (error, response) { + if (!error) { + var ids = []; + for (var i = featureCollection.features.length - 1; i >= 0; i--) { + ids.push(featureCollection.features[i].id); + } + this.removeLayers(ids, true); + this.createLayers(featureCollection.features); + } + + if (callback) { + callback.call(context, error, response); + } + }, this); + }, + deleteFeature: function (id, callback, context) { this.service.deleteFeature(id, function (error, response) { if (!error && response.objectId) { diff --git a/src/Services/FeatureLayerService.js b/src/Services/FeatureLayerService.js index 1c2b13539..5e080b750 100644 --- a/src/Services/FeatureLayerService.js +++ b/src/Services/FeatureLayerService.js @@ -27,6 +27,21 @@ export var FeatureLayerService = Service.extend({ }, context); }, + addFeatures: function (featureCollection, callback, context) { + for (var i = featureCollection.features.length - 1; i >= 0; i--) { + delete featureCollection.features[i].id; + } + var features = geojsonToArcGIS(featureCollection); + return this.post('addFeatures', { + features: features + }, function (error, response) { + var result = (response && response.addResults) ? response.addResults : undefined; + if (callback) { + callback.call(context, error || response.addResults[0].error, result); + } + }, context); + }, + updateFeature: function (feature, callback, context) { feature = geojsonToArcGIS(feature, this.options.idAttribute); @@ -40,6 +55,19 @@ export var FeatureLayerService = Service.extend({ }, context); }, + updateFeatures: function (featureCollection, callback, context) { + var features = geojsonToArcGIS(featureCollection, this.options.idAttribute); + + return this.post('updateFeatures', { + features: features + }, function (error, response) { + var result = (response && response.updateResults) ? response.updateResults : undefined; + if (callback) { + callback.call(context, error || response.updateResults[0].error, result); + } + }, context); + }, + deleteFeature: function (id, callback, context) { return this.post('deleteFeatures', { objectIds: id From 314d87afc30f593ab49b300eb2f3236a69281aa2 Mon Sep 17 00:00:00 2001 From: Nicolas Guilhaudin Date: Mon, 9 Apr 2018 20:58:16 +0200 Subject: [PATCH 2/4] merge FL operation addFeature/addFeatures, updateFeature/updateFeatures, deleteFeature/updateFeatures --- src/Layers/FeatureLayer/FeatureManager.js | 77 +++++++---------------- src/Services/FeatureLayerService.js | 62 +++++++----------- 2 files changed, 44 insertions(+), 95 deletions(-) diff --git a/src/Layers/FeatureLayer/FeatureManager.js b/src/Layers/FeatureLayer/FeatureManager.js index b34071739..15ef5b7a8 100644 --- a/src/Layers/FeatureLayer/FeatureManager.js +++ b/src/Layers/FeatureLayer/FeatureManager.js @@ -484,45 +484,27 @@ export var FeatureManager = VirtualGrid.extend({ }, addFeature: function (feature, callback, context) { - this._getMetadata(Util.bind(function (error, metadata) { - if (error) { - if (callback) { callback.call(this, error, null); } - return; - } - - this.service.addFeature(feature, Util.bind(function (error, response) { - if (!error) { - // assign ID from result to appropriate objectid field from service metadata - feature.properties[metadata.objectIdField] = response.objectId; - - // we also need to update the geojson id for createLayers() to function - feature.id = response.objectId; - this.createLayers([feature]); - } - - if (callback) { - callback.call(context, error, response); - } - }, this)); - }, this)); + this.addFeatures(feature, callback, context); }, - addFeatures: function (featureCollection, callback, context) { + addFeatures: function (features, callback, context) { this._getMetadata(Util.bind(function (error, metadata) { if (error) { if (callback) { callback.call(this, error, null); } return; } + // GeoJSON featureCollection or simple feature + var featuresArray = features.features ? features.features : [features]; - this.service.addFeatures(featureCollection, Util.bind(function (error, response) { + this.service.addFeatures(features, Util.bind(function (error, response) { if (!error) { - for (var i = featureCollection.features.length - 1; i >= 0; i--) { + for (var i = featuresArray.length - 1; i >= 0; i--) { // assign ID from result to appropriate objectid field from service metadata - featureCollection.features[i].properties[metadata.objectIdField] = response[i].objectId; + featuresArray[i].properties[metadata.objectIdField] = featuresArray.length > 1 ? response[i].objectId : response.objectId; // we also need to update the geojson id for createLayers() to function - featureCollection.features[i].id = response[i].objectId; + featuresArray[i].id = featuresArray.length > 1 ? response[i].objectId : response.objectId; } - this.createLayers(featureCollection.features); + this.createLayers(featuresArray); } if (callback) { @@ -533,27 +515,18 @@ export var FeatureManager = VirtualGrid.extend({ }, updateFeature: function (feature, callback, context) { - this.service.updateFeature(feature, function (error, response) { - if (!error) { - this.removeLayers([feature.id], true); - this.createLayers([feature]); - } - - if (callback) { - callback.call(context, error, response); - } - }, this); + this.updateFeatures(feature, callback, context); }, - updateFeatures: function (featureCollection, callback, context) { - this.service.updateFeatures(featureCollection, function (error, response) { + updateFeatures: function (features, callback, context) { + // GeoJSON featureCollection or simple feature + var featuresArray = features.features ? features.features : [features]; + this.service.updateFeatures(features, function (error, response) { if (!error) { - var ids = []; - for (var i = featureCollection.features.length - 1; i >= 0; i--) { - ids.push(featureCollection.features[i].id); + for (var i = featuresArray.length - 1; i >= 0; i--) { + this.removeLayers([featuresArray[i].id], true); } - this.removeLayers(ids, true); - this.createLayers(featureCollection.features); + this.createLayers(featuresArray); } if (callback) { @@ -563,21 +536,15 @@ export var FeatureManager = VirtualGrid.extend({ }, deleteFeature: function (id, callback, context) { - this.service.deleteFeature(id, function (error, response) { - if (!error && response.objectId) { - this.removeLayers([response.objectId], true); - } - if (callback) { - callback.call(context, error, response); - } - }, this); + this.deleteFeatures(id, callback, context); }, deleteFeatures: function (ids, callback, context) { return this.service.deleteFeatures(ids, function (error, response) { - if (!error && response.length > 0) { - for (var i = 0; i < response.length; i++) { - this.removeLayers([response[i].objectId], true); + var responseArray = response.length ? response : [response]; + if (!error && responseArray.length > 0) { + for (var i = responseArray.length - 1; i >= 0; i--) { + this.removeLayers([responseArray[i].objectId], true); } } if (callback) { diff --git a/src/Services/FeatureLayerService.js b/src/Services/FeatureLayerService.js index 5e080b750..07355a221 100644 --- a/src/Services/FeatureLayerService.js +++ b/src/Services/FeatureLayerService.js @@ -13,29 +13,22 @@ export var FeatureLayerService = Service.extend({ }, addFeature: function (feature, callback, context) { - delete feature.id; - - feature = geojsonToArcGIS(feature); - - return this.post('addFeatures', { - features: [feature] - }, function (error, response) { - var result = (response && response.addResults) ? response.addResults[0] : undefined; - if (callback) { - callback.call(context, error || response.addResults[0].error, result); - } - }, context); + this.addFeatures(feature, callback, context); }, - addFeatures: function (featureCollection, callback, context) { - for (var i = featureCollection.features.length - 1; i >= 0; i--) { - delete featureCollection.features[i].id; + addFeatures: function (features, callback, context) { + var featuresArray = features.features ? features.features : [features]; + for (var i = featuresArray.length - 1; i >= 0; i--) { + delete featuresArray[i].id; } - var features = geojsonToArcGIS(featureCollection); + features = geojsonToArcGIS(features); + features = featuresArray.length > 1 ? features : [features]; return this.post('addFeatures', { features: features }, function (error, response) { - var result = (response && response.addResults) ? response.addResults : undefined; + // For compatibility reason with former addFeature function, + // we return the object in the array and not the array itself + var result = (response && response.addResults) ? response.addResults.length > 1 ? response.addResults : response.addResults[0] : undefined; if (callback) { callback.call(context, error || response.addResults[0].error, result); } @@ -43,25 +36,20 @@ export var FeatureLayerService = Service.extend({ }, updateFeature: function (feature, callback, context) { - feature = geojsonToArcGIS(feature, this.options.idAttribute); - - return this.post('updateFeatures', { - features: [feature] - }, function (error, response) { - var result = (response && response.updateResults) ? response.updateResults[0] : undefined; - if (callback) { - callback.call(context, error || response.updateResults[0].error, result); - } - }, context); + this.updateFeatures(feature, callback, context); }, - updateFeatures: function (featureCollection, callback, context) { - var features = geojsonToArcGIS(featureCollection, this.options.idAttribute); + updateFeatures: function (features, callback, context) { + var featuresArray = features.features ? features.features : [features]; + features = geojsonToArcGIS(features, this.options.idAttribute); + features = featuresArray.length > 1 ? features : [features]; return this.post('updateFeatures', { features: features }, function (error, response) { - var result = (response && response.updateResults) ? response.updateResults : undefined; + // For compatibility reason with former updateFeature function, + // we return the object in the array and not the array itself + var result = (response && response.updateResults) ? response.updateResults.length > 1 ? response.updateResults : response.updateResults[0] : undefined; if (callback) { callback.call(context, error || response.updateResults[0].error, result); } @@ -69,22 +57,16 @@ export var FeatureLayerService = Service.extend({ }, deleteFeature: function (id, callback, context) { - return this.post('deleteFeatures', { - objectIds: id - }, function (error, response) { - var result = (response && response.deleteResults) ? response.deleteResults[0] : undefined; - if (callback) { - callback.call(context, error || response.deleteResults[0].error, result); - } - }, context); + this.deleteFeatures(id, callback, context); }, deleteFeatures: function (ids, callback, context) { return this.post('deleteFeatures', { objectIds: ids }, function (error, response) { - // pass back the entire array - var result = (response && response.deleteResults) ? response.deleteResults : undefined; + // For compatibility reason with former deleteFeature function, + // we return the object in the array and not the array itself + var result = (response && response.deleteResults) ? response.deleteResults.length > 1 ? response.deleteResults : response.deleteResults[0] : undefined; if (callback) { callback.call(context, error || response.deleteResults[0].error, result); } From 872de3537ad55bf00de4dfd35187cc6fe269fe67 Mon Sep 17 00:00:00 2001 From: john gravois Date: Mon, 23 Apr 2018 16:22:30 -0700 Subject: [PATCH 3/4] ensure FeatureCollection matches spec --- spec/Layers/FeatureLayer/FeatureManagerSpec.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/Layers/FeatureLayer/FeatureManagerSpec.js b/spec/Layers/FeatureLayer/FeatureManagerSpec.js index 14a111866..faedac3c5 100644 --- a/spec/Layers/FeatureLayer/FeatureManagerSpec.js +++ b/spec/Layers/FeatureLayer/FeatureManagerSpec.js @@ -759,43 +759,43 @@ describe('L.esri.FeatureManager', function () { it('should wrap the updateFeatures method on the underlying service and refresh', function (done) { server.respondWith('POST', 'http://gis.example.com/mock/arcgis/rest/services/MockService/MockFeatureServer/0/updateFeatures', JSON.stringify({ 'updateResults': [{ - 'objectId': 1, + 'objectid': 1, 'success': true }, { - 'objectId': 2, + 'objectid': 2, 'success': true }] })); layer.updateFeatures({ - type: 'FeatureCollecton', + type: 'FeatureCollection', features: [{ - type: 'Point', + type: 'Feature', id: 1, properties: { foo: 'bar' }, geometry: { type: 'Point', - coordinates: [45, -121] + coordinates: [-121, 45] } }, { - type: 'Point', + type: 'Feature', id: 2, properties: { foo: 'bar' }, geometry: { type: 'Point', - coordinates: [45, -121] + coordinates: [-121, 45] } }] }, function (error, response) { expect(response).to.deep.equal([{ - 'objectId': 1, + 'objectid': 1, 'success': true }, { - 'objectId': 2, + 'objectid': 2, 'success': true }]); done(); From b1d560febee17c1893d26e8f950505dd172117ae Mon Sep 17 00:00:00 2001 From: john gravois Date: Mon, 23 Apr 2018 16:23:12 -0700 Subject: [PATCH 4/4] introspect metadata response to determine ID field --- src/Layers/FeatureLayer/FeatureManager.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Layers/FeatureLayer/FeatureManager.js b/src/Layers/FeatureLayer/FeatureManager.js index 15ef5b7a8..8ad2cc85d 100644 --- a/src/Layers/FeatureLayer/FeatureManager.js +++ b/src/Layers/FeatureLayer/FeatureManager.js @@ -82,6 +82,10 @@ export var FeatureManager = VirtualGrid.extend({ this.service.options.isModern = true; } + if (metadata.objectIdField) { + this.service.options.idAttribute = metadata.objectIdField; + } + // add copyright text listed in service metadata if (!this.options.attribution && map.attributionControl && metadata.copyrightText) { this.options.attribution = metadata.copyrightText;