iVantage / angular-ivh-treeview

A treeview for AngularJS with filtering and checkbox support.
http://ivantage.github.io/angular-ivh-treeview/
MIT License
239 stars 89 forks source link

Unexpected behavior with search filter #34

Closed wcomnisky closed 9 years ago

wcomnisky commented 9 years ago

Hi @jtrussell!

I found a strange behavior in the search filter.

Using this as example: http://jsbin.com/rigepe/1

In the search field, type: true

All items will be hidden, except Mustachio. And if you mark it as checked, all items will be displayed.

Now, clear the search field and type: false

All items are displayed.

But you type some inexistent word (considering both key and value from the list - as value for the search), like: xyz

All items will be hidden as expected.

I think this is related to the filter function in AngularJS, checking all keys and values in our list.

Can you confirm this?

Maybe before sending to the Angular filter, we could clean our collection, removing unwanted keys/values..

Is there a way to extend the filter function in the ivh-treeview?

Thanks! :beers:

jtrussell commented 9 years ago

You are correct, we're just leveraging Angular's filterFilter. It's pretty powerful though, for example you can give it a function rather than just a string:

In not-view land:

$scope.myFilterFn = function(node) {
  if( ... ) {
    // Show it!
    return true;
  }
  // Hide it!
  return false;
};

In view land:

<div ivh-treeview="myTreeData" ivh-treeview-filter="myFilterFn"></div>

Does that answer your question?

wcomnisky commented 9 years ago

It's OK, but how can I get the search value in my custom search function?

My HTML looks like below, and maybe is important to say that I'm importing this template with ng-include:

<div class="form-group" ng-class="{'has-error': MessageForm.stores.$invalid}">
    <label for="stores" class="col-sm-2 control-label">Stores</label>
    <div id="storesControls" class="col-sm-10">
            <input type="text" ng-model="bagSearch" class="form-control" placeholder="Type here to filter" />
            <div
                ivh-treeview="bag"
                ivh-treeview-filter="myFilterFn"
                ivh-treeview-expand-to-depth="-1"
                ivh-treeview-default-selected-state="false"
                class="storesBag"></div>
    </div>
</div>

In my function, I tried to read the $scope.bagSearch, but returns undefined.

So I changed the function call in the HTML to:

...
ivh-treeview-filter="myFilterFn(bagSearch)"
...

and with this I was able to read the bagSearch content, but lost the node value...

(PS: just for future reference, please could you correct your function name to myFilterFn, as referenced in the HTML? :wink:)

jtrussell commented 9 years ago

Thanks for pointing out the typo - fixed!

There are going to be lots of options for getting the filter string into your function. What's best is going to be largely dependent on your setup, where the filter function is defined, and how reusable you want the function to be. If the function happens to live in the same controller that the filter string is initialized in then you can do something like this. If you want to set up your filter elsewhere you might build it as a higher order function that takes a scope or a getter as a parameter and returns the filter function.

myFilterFuncFactory = function($scope, filterAttr) {
  return function(node) {
    // E.g.
    var filterStr = $scope[filterAttr];

    if( ... ) {
      return true;
    }
    return false;
  };
};
wcomnisky commented 9 years ago

Thanks for your help! Sorry about my lack of knowledge to get this working.

jtrussell commented 9 years ago

I hope everything worked out. Just FYI when #35 gets fixed that'll definitely be the optimal solution!