MicrosoftDocs / azure-docs

Open source documentation of Microsoft Azure
https://docs.microsoft.com/azure
Creative Commons Attribution 4.0 International
10.24k stars 21.41k forks source link

Azure maps API - DataSource class - remove() method - Cannot read property '_setDataSource' of undefined #39664

Closed kakarotto67 closed 5 years ago

kakarotto67 commented 5 years ago

The Problem

I display some shapes on the Azure Map using atlas.min.js (v2) API.

At some point I need to remove specified shape from the datasource. Accoring to this documentation page I have to use remove() method of the DataSource class.

The explanation for that method:

Removes a shape from the data source. If a string is passed in, it is assumed to be an id. If a number is passed in, removes the shape at that index.

The Usage I don't know the shape index so I simply pass the shape id like this:

// Get the shape from the container of shapes
var finishedMissileShape = finishedMissiles[missile.missileId];

// Retrieve shape id using getId() method
var finishedMissileShapeId = finishedMissileShape.getId();

// Use remove() method to remove shape by id from DataSource
// I convert id to string using toString() method since remove() expects string if you wan't to lookup by shape id but not index in the container
finishedMissilesDatasource.remove(finishedMissileShapeId.toString());

And then I get a crash:

Cannot read property '_setDataSource' of undefined at ia._removeFromSources (atlas.min.js:2538) at ia.remove (atlas.min.js:2538)

My temporary solution Couldn't find github for Azure Maps API, so I had to manually download the file via known url and added the fix to _removeFromSources method.

Was:

DataSource.prototype._removeFromSources = function (i) {
            var oldShape;
            if (typeof i === "number") {
                // omitted for brevity
            }
            else {
                oldShape = this.shapes[this.shapesMap.get(i)];
                oldShape._setDataSource(null);
                // omitted for brevity
            }
            // omitted for brevity
        };

Changed to:

DataSource.prototype._removeFromSources = function (i) {
            var oldShape;
            if (typeof i === "number") {
                // omitted for brevity
            }
            else {
                oldShape = this.shapes[this.shapesMap.get(parseInt(i))];
                oldShape._setDataSource(null);
                // omitted for brevity
            }
            // omitted for brevity
        };

So I added parseInt to this line: oldShape = this.shapes[this.shapesMap.get(parseInt(i))];

Otherwise oldShape is undefined. This is rather a hack than a fix, so I expect that this is going to be fixed in future versions of maps api.

Alberto-Vega commented 5 years ago

@kakarotto67 Thanks for the feedback! We are currently investigating and will update you shortly.

rbrundritt commented 5 years ago

Currently the id must be a string as documented on the feature and shape classes here: https://docs.microsoft.com/en-us/javascript/api/azure-maps-control/atlas.data.feature?view=azure-maps-typescript-latest#id

https://docs.microsoft.com/en-us/javascript/api/azure-maps-control/atlas.shape?view=azure-maps-typescript-latest#shape-atlas-data-geometry--string--any-

Note that id's in a lot of data sets are not numbers. Currently we only allow strings, but may add support for numbers as an alternative. At that point we would likely introduce a removeById function.

In the meantime, if for some reason your id's must be numbers, you can add the following code to your app to add a remove by id function that handles this.

atlas.source.DataSource.prototype.removeById = function (id) {
    var s = this.getShapes();
    for (var i = 0, len = s.length; i < len; i++) {
        if (s[i].getId() === id) {
            //Remove by index.
            this.remove(i);
            break;
        }
    }
};
kakarotto67 commented 5 years ago

I see, thanks.

rbrundritt commented 5 years ago

Made an improvement to this function so it also supports arrays of ids.

atlas.source.DataSource.prototype.removeById = function (id) {
    var s = this.getShapes();
    if(Array.isArray(id){
        //id is an array of numbers or strings.
        for (var i = 0, len = s.length; i < len; i++) {
            if (id.indexof(s[i].getId()) > -1) {
                //Remove by index.
                this.remove(i);
                break;
            }
        }
    } else {
        //id is a number or string.
        for (var i = 0, len = s.length; i < len; i++) {
            if (s[i].getId() === id) {
                //Remove by index.
                this.remove(i);
                break;
            }
        }
    }
};