how make ng-model="search" have influence on leaflet directive?
T

1

1

I use leaflet-angular-directive, i successfully display objects in table and map, although i achieved filtering through searching input only affect geojson objects in table.

My aim: make filtering through searching input affect geojson objects in table and map.

My Module

   var AppMapDirectory = angular.module('DirectoryAppMap', ['ngResource', 'leaflet- directive']);

My Factory

 AppMapDirectory.factory("Directory", function($resource) {
 return $resource("json/result.json", {}, {
   get: {
       method: "GET",
       cache: true
    }
 });
 });

My Controller

   AppMapDirectory.controller("DirectoryMapList", function($scope, Directory) {
   Directory.get(function(data) {

   $scope.hf_directory = data.features;

    function onEachFeature(feature, layer) {
            layer.bindPopup("<b>Wardname:</b> " + feature.properties.name +
                "<br><b>Category:" + feature.properties.category + "");
        }

     angular.extend($scope, {
       geojson: {
           data: $scope.hf_directory,
           onEachFeature: onEachFeature
       }
    });
    });

    angular.extend($scope, {
    defaults: {
        tileLayer: "https://dnv9my2eseobd.cloudfront.net/v3/foursquare.map-ikj05elx/{z}/{x}/{y}.png",
        maxZoom: 14,
        minZoom: 3
    },
    center: {
        lat: 8.1238,
        lng: 11.8777,
        zoom: 2
    }
});
});

My Template

 <div ng-app="DirectoryAppMap" ng-controller="DirectoryMapList">

 <ul>
 <li><input ng-model="search.properties.name" placeholder="Name" ></li>
 <li><input ng-model="search.properties.category" placeholder="Category"></li>
 </ul>




<table>
<thead>
<tr>
<th>Name</th>
<th>Category</th>

</tr>
</thead>

<tbody>
<tr ng-repeat="hf in hf_directory| filter:search">
<td>{{ hf.properties.name }}</td>
<td>{{ hf.properties.category }}</td>

</tr>
</tbody>
</table>

<div leaflet id="map" center="center" defaults="defaults" geojson="geojson">

</div>
</div>

Maybe somebody could show me right direction so I know what I am doing wrong, I tried to bind search to leaflet on many different ways but without success, actually i think that it is not something that should be done on template side? But rather in options for geojson like filter? Is this the right thing to do now?

I used ng-repeat directive but then i had thousands of maps, maybe it is possible to use ng-repeat and still have only one map?

Trictrac answered 3/1, 2015 at 17:22 Comment(1)
After some searching, though i can be wrong, i think that i should somehow add geojson ass markers that can be ng-repeat, then filter search should work?Trictrac
C
3

Here's an example of how to reflect searchresults in the geojson dataset, i've commented the code througout to explain some things since it's a rather large piece and understanding works best by example i think. So here it goes:

Controller HTML:

<leaflet geojson="geojson"></leaflet>
<input ng-model="search" />
<select multiple>
    <option ng-repeat="feature in geojson.data.features">
        {{feature.properties.NAME}}
    </option>
</select>

Controller JS:

angular.module('app').controller('controller', [
    '$scope',
    '$http',
    '$filter',
    function ($scope, $http, $filter) {
        // Declare empty search model
        $scope.search = '';
        // Declare empty geojson object
        $scope.geojson = {};
        // Fetch GeoJSON dataset
        $http.get('stations.geojson').success(function (data) {
            // Assign source data to scope
            $scope.data = data;
            // Assign same data to the geojson object
            $scope.geojson.data = data;
        });
        // Start watching the search model
        $scope.$watch('search', function (newVal, oldVal) {
            // Watch gets fired on scope initialization and when empty so differentiate:
            if (newVal !== oldVal && newVal !== '') {
                // Has searchvalue, apply sourcedata, propertyname and searchstring to filter
                // and assign return value of filter to geojson 
                $scope.geojson.data = $filter('filter')($scope.data, 'NAME', newVal);
            } else {
                // Search has been initialized or emptied, assign sourcedata to geojsonobject
                $scope.geojson.data = $scope.data;
            }
        });
    }
]);

Filter JS:

angular.module('app').filter('filter', [function() {
    return function(geojson, searchProperty, searchValue) {
        // Declare empty GeoJSON object to store found matches
        var matches = {'type': 'FeatureCollection', 'features': []};
        // Loop over source features
        angular.forEach(geojson.features, function(featureObject, featureKey) {
            // Make sure that the assigned searchproperty exists
            if (featureObject.properties.hasOwnProperty(searchProperty)) {
                // Source propertyvalue as lowercase;
                var property = featureObject.properties[searchProperty].toLowerCase();
                // Search propertyvalue as lowercase;
                var search = searchValue.toLowerCase();
                // Check if searchvalue exists in sourcevalue
                if (property.indexOf(search) > -1) {
                    // Found match, push to new GeoJSON object
                    matches.features.push(featureObject);
                }
            }
        });
        // return GeoJSON object
        return matches;
    };
}]);

Hope that helps, here's a working example on Plunker: http://plnkr.co/edit/z02JyuGE0Y8EDrhOqzoQ?p=preview

After discussion in the comments about filtering on multiple properties i thought it might be handy to add that in an example, so assuming the geojson has a NAME and a LINE property:

Multiple inputs:

  <input ng-model="search.NAME" />
  <input ng-model="search.LINE" />

Change search property in scope to an object:

$scope.search = {
  'NAME': '',
  'LINE': ''
};

Modified watch function:

$scope.$watch('search', function (newVal, oldVal) {
    // Protect against firing on initialization
    if (!angular.equals(newVal, oldVal)) {
        // Create copy of the sourcedata
        var geojson = angular.copy($scope.data);
        // Loop over search object
        angular.forEach(newVal, function (value, property) {
            // Only execute if value isn't empty
            if (value !== '') {
                // Apply filter and assign return data
                geojson = $filter('filter')(geojson, property, value);
            }
        });
        // Assign filtered geojson to geojson in scope
        $scope.geojson.data = geojson;
    // On initialization
    } else {
        // Assign unfiltered source data to geojson in scope
        $scope.geojson.data = $scope.data;
    }
// Enable deep watch because we're watching an object
}, true);

Here's the updated example on Plunker: http://plnkr.co/edit/OOx5DebtKXBfYqJ2Da3a?p=preview

Charyl answered 7/1, 2015 at 11:40 Comment(5)
I have some question, i found mapbox.js it is much more easier to use, if i would like to make solution from map box available in leaflet it mean some work with library? There you have mapbox directive which has some nested directives like markers and it inherit i think ng-repeat directive so it is possible to use it within mapbox and work nice witch ng-model search, withouth any watchers and filters, your solution is great, i digest your code right know ;)Trictrac
That's very offtopic/out of context for this question. I recommend you start a new question and tag it with Mapbox as well as Leaflet so that others can help too or find it when they have the same question. Comments aren't meant for asking new questions, just for asking for clarification on the current question or answer.Charyl
If there is some expression which allow to add few properties as searchProperty? For example 'name' & 'address' ?Trictrac
Ofcourse, you could easily write another filter $filter('filter')($scope.data, newValue) to use a search object from your scope, something along the lines of $scope.search = {'name': '', 'city': ''} instead of a single string. Those could be hooked to multiple inputs in your template. The filter would get a little complexer, but it can easily be done. You could also run the current filter twice in the watch function. It's a matter of preference.Charyl
I've edited my original answer and added an example on how to use the filter on multiple properties. Hope that helps.Charyl

© 2022 - 2024 — McMap. All rights reserved.