Wildhoney / Leaflet.FreeDraw

:earth_asia: FreeDraw allows the free-hand drawing of shapes on your Leaflet.js map layer – providing an intuitive and familiar UX for creating geospatial boundaries similar to Zoopla and others. Included out-of-the-box is the concaving of polygons, polygon merging and simplifying, as well as the ability to add edges and modify existing shapes.
https://freedraw.herokuapp.com/
MIT License
544 stars 103 forks source link

Uncaught TypeError: Can't call method on undefined #146

Closed stereobooster closed 4 years ago

stereobooster commented 5 years ago
leaflet-freedraw.web.js:1 Uncaught TypeError: Can't call method on undefined
    at requireObjectCoercible (leaflet-freedraw.web.js:1)
    at toObject (leaflet-freedraw.web.js:1)
    at Function.arrayFrom (leaflet-freedraw.web.js:1)
    at updateFor (leaflet-freedraw.web.js:1)
    at e.value (leaflet-freedraw.web.js:1)
    at NewClass.remove (leaflet-src.js:3793)
    at Map.componentWillUnmount (Map.js:270)
    at callComponentWillUnmountWithTimer (react-dom.development.js:17169)
    at HTMLUnknownElement.callCallback (react-dom.development.js:149)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:199)

As far as I can tell it comes from this line:

https://github.com/Wildhoney/Leaflet.FreeDraw/blob/master/src/helpers/Layer.js#L13

const latLngs = Array.from(polygons.get(map)).map(polygon => {

It seems that polygons.get(map) resolved to undefined and Array.from throws error.

For comparison this is what native function gives (Chrome):

Array.from(undefined)
VM349:1 Uncaught TypeError: Cannot convert undefined or null to object
    at Function.from (<anonymous>)
    at <anonymous>:1:7
btafel commented 4 years ago

Hi, was this issue ever fixed? Thanks

Wildhoney commented 4 years ago

I wasn't able to reproduce it on my end.

We could change it to polygons.get(map) ?? [] to avoid the error, but I'd like to know under which circumstances polygons.get(map) can become undefined?

btafel commented 4 years ago

I wasn't able to reproduce it on my end.

We could change it to polygons.get(map) ?? [] to avoid the error, but I'd like to know under which circumstances polygons.get(map) can become undefined?

I actually fixed it that way in my local environment. It would happen when I navigate out of the screen where I have the Map component.

Wildhoney commented 4 years ago

And the ?? [] doesn't cause any adverse effects? I can make that change.

Wildhoney commented 4 years ago

Made the fix in v2.13.3 – I had to use || [] as the Babel transpiler is quite old in this package, but in this case it should have the same affect 👍 Thanks guys.

btafel commented 4 years ago

sorry to bother again @Wildhoney ! I found one more like this one.... (looks like this is the last one :))

This is the error I get:

TypeError: Cannot read property 'call' of undefined
    at t.fire (leaflet-freedraw.web.js:8214)
    at A_ (leaflet-freedraw.web.js:15299)
    at t.value (leaflet-freedraw.web.js:40530)
    at t.value (Freedraw.js:112)
    at t.n.componentDidUpdate (MapLayer.js:55)
    at us (react-dom.production.min.js:5163)

And as far as I could see, it seems to come from here:

export const modeFor = (map, mode, options) => {

    // Update the mode.
    map[modesKey] = mode;

    // Fire the updated mode.
    map[instanceKey].fire('mode', { mode });

    // Disable the map if the `CREATE` mode is a default flag.
    mode & CREATE ? map.dragging.disable() : map.dragging.enable();

    Array.from(polygons.get(map)).forEach(polygon => {

        polygon[edgesKey].forEach(edge => {

            // Modify the edge class names based on whether edit mode is enabled.
            mode & EDIT ? DomUtil.removeClass(edge._icon, 'disabled') : DomUtil.addClass(edge._icon, 'disabled');

        });

    });

    // Apply the conditional class names to the map container.
    classesFor(map, mode);

    // Fire the event for having manipulated the polygons if the `hasManipulated` is `true` and the
    // `notifyAfterEditExit` option is equal to `true`, and then reset the `notifyDeferredKey`.
    options.notifyAfterEditExit && map[notifyDeferredKey]();
    map[notifyDeferredKey] = () => {};

    return mode;
};

While calling map[instanceKey].fire('mode', { mode });

I fixed it by modifying the dist file leaflet-freedraw.web.js and adding this var u=o[s];u.fn && u.fn.call(u.ctx||this,r)} validating if u.fn exsists, but I couldn't find those lines in the source code.

Any ideas?

UPDATE: NVM found the error :) I was missing the onModeChange={() => {}}... had to debug the library to figure it out and it was in front of my eyes 🤷‍♂️. Thanks!!