Search code examples
javascriptangularjsleafletangular-leaflet-directive

TypeError: points.map is not a function at addressPointstoMarkers using AngularJS Leaflet Directive


I am trying to load and cluster markers from a geojson file using AngularJS leaflet directive. However, I am getting an TypeError: points.map is not a function at addressPointstoMarkers. Below is my code:

  <html ng-app="myapp">
  <head>
    <meta name="viewport" content="width-device, initial-scale=1.0">
    <script src="js/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.0/angular-route.js"></script>
    <script type="text/javascript" src="js/leaflet.js"></script>
    <script type="text/javascript" src="js/angular-leaflet-directive.min.js"></script>
    <script src="js/leaflet.markercluster.js"></script>
    <link rel="stylesheet" href="css/leaflet.css" />
    <link rel="stylesheet" href="css/MarkerCluster.css" />
    <link rel="stylesheet" href="css/MarkerCluster.Default.css" />
    <script>
        var app = angular.module("myapp", ["leaflet-directive"]);
        app.controller("AlabamaController", [ "$scope", '$http', function($scope, $http) {

            var addressPointstoMarkers = function(points){
                return points.map(function(ap) {
                    return {
                        layer: 'Alabama',
                        lat: ap[0],
                        lng: ap[1]
                        };
                    });
                };

            angular.extend($scope, {
                center: {
                    lat: 30.126597156,
                    lng: -90.5958157696,
                    zoom: 5
                },
                events: {
                    map: {
                        enable: ['moveend', 'popupopen'],
                        logic: 'emit'
                        }
                },
                layers: {
                    baselayers: {
                        osm: {
                        name: 'OpenStreetMap',
                        url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                        type: 'xyz'
                        }
                    },
                    overlays:{
                        alabama: {
                            name: "Alabama",
                            type: "markercluster",
                            visible: true
                        }
                }
            }
            });

            $http.get("data/alabama.geojson").success(function(data){
                $scope.markers = addressPointstoMarkers(data);
            });
        }]);

        </script>
        <title>Alabama</title>
  </head>
  <body>
    <div ng-controller="AlabamaController">
        <leaflet lf-center="center" markers="markers" layers="layers" event-broadcast="events" width="100%" height="750px"></leaflet>    
    </div

  </body>
</html>

Here is a snippet of the data in the geojson file:

[{"type":"Feature","properties":{"Name":"Drummond Co Inc","Address":"1000 Urban Center Dr Ste 300","City":"Birmingham","State":"AL","Phone":"(205) 945-6300","County":"Jefferson","Latitude":"33.48360731","Longitude":"-86.70488291","BusinessDescription":"Coal & Other Minerals & Ores - Wholesale","SIC":"5052001","SICDescription":"Coal & Other Minerals & Ores - Wholesale","NAICS":"423520","NAICSDescription":"Coal and Other Mineral and Ore Merchant Wholesalers","Website":"www.drummondco.com"},"geometry":{"type":"Point","coordinates":[-86.70488291,33.48360731]}},


Solution

  • The error you're getting is because you're calling the map method on the points object which isn't an array. The map method is only available on objects of type Array. You can check this by logging the data object your console: console.log(data). Doing that, you'll see that data holds the response object of your $http method. The GeoJSON featurecollection object you're expecting is assigned to the data member of the response object. You'll need to change your $http success method:

    $http.get("data/alabama.geojson").success(function(response){
        $scope.markers = addressPointstoMarkers(response.data);
    });
    

    Now data holds the actual GeoJSON featurecollection object. The array with features you need is stored under the features member of that object so you'll need to call map on that:

    var addressPointstoMarkers = function(points){
        return points.features.map(...)
    }
    

    The method you've put in the map method is incorrect also. So it still won't work. It's expecting a flat object/array but it's getting a GeoJSON feature where the coordinates you need are stored under point.geometry.coordinates. So you'll need to change the method accordingly:

    function(ap) {
        return {
            layer: 'Alabama',
            lat: ap.geometry.coordinates[1],
            lng: ap.geometry.coordinates[0]
        };
    }
    

    Now it should work as expected but i'de strongly urge you not to fix it this way. I suspect you've copy/pasted this from an example which uses a normal array of object for storing the coordinates. But you're working with a GeoJSON featurecollection for which the angular leaflet directive has perfectly good separate solution. Just assign your GeoJSON featurecollection to a member in $scope:

    $http.get("data/alabama.geojson").success(function(response){
        $scope.geojson = addressPointstoMarkers(response.data);
    });
    

    And pass it straight to the GeoJSON directive of angular leaflet and you're good to go:

    <leaflet geojson="geojson" lf-center="center" markers="markers" layers="layers" event-broadcast="events" width="100%" height="750px"></leaflet>
    

    Simple as that :) Here's is a full example from the repository (there are more under the basic tab):