Igor
Igor

Reputation: 1424

Invalid Geojson Object Angularjs &Leafletjs

In my project i try to synchronize filters with geojson displayed in table and on map. To achieve this i used angular and previously angular-leaflet-directive, but performance was to slow for my purposes so i decide to make my own directive for leaflet.js.

In my case i can pass data from controller to my directive, but it makes map static, when i try to pass data after filtering in order to make my map dynamic, map is not showing any markers and i get Error from leaflet, Invalid Geojson Object.

Here Fiddler with my example: http://jsfiddle.net/ior88/5ea8yxwo/4/

 $scope.FilteredGeojson = function () {

    var result;

    result = $filter('filter')($scope.data, $scope.search);

    $scope.geojson = result;
    return result;
};

If you will look into console there you will see error.

I don't get it because when i display geojson or geojson_watch in {{}} it looks the same as geojson in data, So assume the problem here is filtering? I will be really thankful to somebody who will tell me where i make errors

Upvotes: 2

Views: 1481

Answers (2)

iH8
iH8

Reputation: 28638

First off, what you are showing is not a GeoJSON object. That Leaflet's L.GeoJSON accepts just an array of features, doesn't make it a valid GeoJSON object, so you shouldn't call it a GeoJSON object. It's an array of GeoJSON feature objects. In a valid GeoJSON featurecollection object the feature array is contained like this:

{
    "type": "FeatureCollection",
    "features": [
        // The features
    ]
}

Next, you're trying to filter some complex objects in a way that doesn't work. Here is how $filter('filter') works:

var simpleArray = [{
  'name': 'Foo'
}, {
  'name': 'Bar'
}];

$filter('filter')(simpleArray, {'name': 'Foo'}); // Returns array with Foo object
$filter('filter')(simpleArray, {'name': 'Bar'}); // Returns array with Bar object
$filter('filter')(simpleArray, {'name': 'Foobar'}); // Returns empty array

Example on Plunker: http://plnkr.co/edit/I7OGfoJLwaCz0XibcTDB?p=preview

What you are trying to do with $filter('filter'):

var complexArray = [{
  'properties': {
    'name': 'Foo'
  }
}, {
  'properties': { 
     'name': 'Bar'
  }
}];

$filter('filter')(complexArray, {'name': 'Foo'}); // Returns empty array
$filter('filter')(complexArray, {'name': 'Bar'}); // Returns empty array
$filter('filter')(complexArray, {'name': 'Foobar'}); //Returns empty array

Example on Plunker: http://plnkr.co/edit/rUtseKWCeyLiewDxnDDn?p=preview

Why? Because the objects in the array do not have a property called name. They only have a property called properties, that contains an object and that does have a name property. You can't expect the filter to recursivily go searching through your object untill it finds a name property. It doesn't. It only does when you explictly tell it to do so:

$filter('filter')(complexArray, {'properties': {'name': 'Foo'}}); // Returns with Foo
$filter('filter')(complexArray, {'properties': {'name': 'Bar'}}); // Returns with Bar
$filter('filter')(complexArray, {'properties': {'name': 'Foobar'}}); // Returns empty

Example on Plunker: http://plnkr.co/edit/LpOvr7Zxw5C5A3Tt5umQ?p=preview

So you'll need to setup your logic a bit different, say you want to search for two properties, id and name In your scope you would have:

$scope.search = {
  'properties': {}
};

$scope.$watch('search', function (newVal, oldVal) {
  if (newVal !== oldVal) {
    $scope.data = $filter('filter')($scope.source, $scope.search);
  }
}, true);

And in your template:

<input ng-model="search.properties.id" placeholder="ID" />
<input ng-model="search.properties.name" placeholder="Name" />

Now everytime you use one of the inputs, the watch on the search property gets fired, which filters the source and updates the data. To reflect that change in your directive also, you've also got to put a watch on the data object in the link method of your directive. In there you can update the layer with the new data:

scope.$watch('data', function (newVal, oldVal) {
    if (newVal !== oldVal) {
        geojsonLayer.clearLayers();
        geojsonLayer.addData(scope.data);
    }
}, true);

Entire code in a working example on Plunker: http://plnkr.co/edit/CmfBdmt7BYKPmE22HLvl?p=preview

Upvotes: 3

John
John

Reputation: 30175

This error comes from here in the Leaflet code, and indicates that the GeoJSON contained a Geometry object without a valid type property. You'll need to investigate why your code is generating such an object.

Upvotes: 0

Related Questions