0

I'm trying to get these dynamic filters working and its almost there I think. Looks like the model isn't being passed back to the watch function. I would've expected it to work with the first set of filters at least but it doesn't.

What I'm trying to achieve is that when the user selects an option from the select list and sets a value in the input box the data is filtered. The user can optionally add another set of filters by clicking the "add fields" button. If there user completes the second set of filters then the data is filtered further.

This is what I've got so far. If there's only one filter showing then shouldn't it just work?

This is the code that creates the user defined filters.

<div data-ng-repeat="filter in filters">
  <select ng-model="filter.id">
    <option value="age">Age</option>
    <option value="customerId">CustomerID</option>
    <option value="productId">ProductID</option>
    <option value="name">Name</option>
  </select>
  <input type="text" ng-model="data.search[filter.id]">
  <button class="remove" ng-show="$last" ng-click="removeFilter()">-</button>

Add fields

I think I'm almost there, got a better understanding of hierarchical scope. I've referred to a few tutorial and examples but I'm not quite there yet. I think my issue with this is that I'm not communicating the models properly. Still a little bit lost with this. Any further tips/suggestions would be great. I'm wondering if I should move some of he code from the controller in my directive into the resultsCtrl controller. Really not sure.

This fiddle gave me the idea to use filter.id within my template ng-repeat

This plnkr was helpful.

I'm getting somewhere now. This plnkr shows it working, the last thing I want to do with it is when you remove a filter it automatically updates the search object to remove the relevant filter.

Any suggestions on how to do this?

2 Answers 2

3

You are breaking the golden rule of "always have a dot in ng-model".

Why? because objects have inheritance and primitives do not.

ng-model="filterType"

is being defined inside a child scope created by ng-repeat. Because it is a primitive the parent scope in controller can not see it. However if it was a property of an object that was available at parent level, the reference would be shared between parent and child.

Once you fix that bug you will run into a bug where scope.search is not an object either so your $watch function will throw an exception also. In main controller can set:

$scope.search ={};

Do some reading up on how hierarchical scopes work in angular. There is plenty to be found in web searches and angular docs

Sign up to request clarification or add additional context in comments.

2 Comments

I've done a bit of research and I see why I would need the the dot in the model. I'm now using filter.id as the mode within the ng-repeat. My watch isn't seeing any changes and I'm watching for filter.id. Any chance you take another look and give me another pointer? :)
filter.id isn't a scope variable, it is a property of each filter object in the filters array. I suggest you use events for this like ng-change
1

I eventually got this solved :)

directive:

angular.module('dynamicFiltersDirective', [])
.directive('dynamicFilters', function() {
  return {
    restrict: 'AE',  
    scope: {
             filtersArray: '=',
             searchObject: '='
    },

    link: function(scope) {

      scope.addFilter = function() {
        var newItemNo = scope.filtersArray.length+1;
        scope.filtersArray.push({'id':'filter'+newItemNo});
      };

      scope.removeFilter = function(option) {
        var lastItem = scope.filtersArray.length-1;
        scope.filtersArray.splice(lastItem);
        delete scope.searchObject[option];
      };    

      scope.updateFilters = function (model) {
        scope.searchObject[model];
      }

    },
    templateUrl: 'filtertemplate.html'
  }
});

controller:

angular.module('app', ['dynamicFiltersDirective']).controller('resultsCtrl', function($scope){

$scope.filters = [{id: 'filter1'}];
$scope.search = {};

    $scope.persons = [{
      name: 'Jim',
        age: 21,
      customerId: 1,
      productId: 4
  },{
      name: 'Frank',
        age: 20,
      customerId: 2,
      productId: 4
  },{
      name: 'Bob',
        age: 20,
      customerId: 3,
      productId: 5
  },{
      name: 'Bill',
        age: 20,
      customerId: 3,
      productId: 5
  }];
});

template:

<div data-ng-repeat="filter in filtersArray">
  <select ng-model="filter.id">
    <option value="age">Age</option>
    <option value="customerId">CustomerID</option>
    <option value="productId">ProductID</option>
    <option value="name">Name</option>
  </select>
  <input type="text" ng-model="searchObject[filter.id]" ng-change="updateFilters(searchObject[filter.id])">
  <button class="remove" ng-show="$last" ng-click="removeFilter(filter.id)">-</button>
</div>
<button class="addfields" ng-click="addFilter()">Add fields</button>

<div id="filtersDisplay">
  {{ filters }}
</div>   

index.html

<div ng-controller="resultsCtrl">
 <dynamic-filters filters-array="filters" search-object="search">    </dynamic-filters>
 <div ng-repeat="person in persons | filter: search">
   {{person.name}}
</div>

Here's my example plnkr

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.