search filter + ng-repeat scope

1,565 views
Skip to first unread message

Davis Ford

unread,
Feb 13, 2013, 5:22:28 PM2/13/13
to ang...@googlegroups.com
If you have a filter like 

<input type="text" ng-model="search.$">
<table>
  <tr ng-repeat="signal in signals | filter:search">
    <td>{{signal.name}}</td>
  </tr>
</table>

Assuming a collection exists $scope.signals

This is a typical angular search filter.  The question I have is: if the user does filter by typing in the box, how do I know what items have been filtered on / off?  I can see it in UI, the DOM obviously changes, but I want to take some action on only the filtered items -- I'd prefer not to do a jQuery-like search to find them, when it seems Angular has them somewhere.

They original $scope.signals collection is unmodified, so it must make a copy of it and bind that to the table.tr.

tl;dr basically I'm looking for the repeater scope in this picture: http://docs.angularjs.org/img/tutorial/tutorial_03.png as a rollup of my own scope collection.  Is there an easy way to reference it?

Peter Bacon Darwin

unread,
Feb 14, 2013, 1:40:29 AM2/14/13
to ang...@googlegroups.com

Move the filtering out of the template and into a controller.

Pete
...from my mobile.

--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Davis Ford

unread,
Feb 14, 2013, 9:16:48 AM2/14/13
to ang...@googlegroups.com
Yea, I could do that -- I mean, I know how to solve this problem by writing my own filter function, but it just seemed like I'm re-writing behavior that angular already has.  It would be really nice to just get a reference to the filtered collection for an ng-repeat, then I wouldn't have to re-write this functionality.

Maybe something like this...

<tr ng-repeat="signal in signals | filter:search" ng-model=filtered>

then the controller's $scope.filtered would point to the collection that has been filtered.

Peter Bacon Darwin

unread,
Feb 14, 2013, 10:13:28 AM2/14/13
to ang...@googlegroups.com

You can inject filterFilter into you controller.

Pete
...from my mobile.

Davis Ford

unread,
Feb 14, 2013, 10:46:27 AM2/14/13
to ang...@googlegroups.com
Hi Pete, I'm not 100% sure I follow you.  filterFilter is the actual function that does the filtering, right?  I did inject that into my controller, but not sure what it buys me or how to use it.

I created a quick jsfiddle here: http://jsfiddle.net/zenocon/v5aSW/

If you type in the text input, it filters the ng-repeat.  The goal is to get a reference to the filtered collection.  How can I do so?

Regards,
Davis

Davis Ford

unread,
Feb 14, 2013, 11:31:20 AM2/14/13
to ang...@googlegroups.com

I'm close: http://jsfiddle.net/zenocon/v5aSW/6/ 

The $scope.data.filtered now equals the initial result of the filterFilter fn -- but there is something not right with the data binding.  For example, if I type in the text box, the table is updated with the filter results, but $scope.data.filtered is not.  

Clint Checketts

unread,
Feb 14, 2013, 11:33:10 AM2/14/13
to ang...@googlegroups.com
Here is my attempt: http://jsfiddle.net/v5aSW/9/

The filter is triggered by a watch and saves its results into a separate array that can be referenced.

    $scope.data.filteredSignals = $scope.data.signals;
    
    $scope.$watch('searchText', function(val){
        $scope.data.filteredSignals = filterFilter($scope.data.signals,val)
    });


Davis Ford

unread,
Feb 14, 2013, 11:34:42 AM2/14/13
to ang...@googlegroups.com
It appears to work with ng-change but this just seems wrong.  


If there is another, better way to do this, I'd love to hear about it. 

Davis Ford

unread,
Feb 14, 2013, 11:39:45 AM2/14/13
to ang...@googlegroups.com
Thanks Clint -- two different approaches...(I resolved it by just adding an ng-change handler) -- I think they are both valid, working.  

Peter Bacon Darwin

unread,
Feb 14, 2013, 1:55:39 PM2/14/13
to ang...@googlegroups.com
Great!


Pawel Kozlowski

unread,
Feb 14, 2013, 1:56:10 PM2/14/13
to ang...@googlegroups.com
Hi!

Yep, you are close but you have to filter twice: in a controller and in a view.
But you can use a simple trick to assign filtered results in a template as well:

ng-repeat = "signal in filtered = (data.signals | filter:data.search)"

http://jsfiddle.net/GyXyV/

Cheers,
Pawel
> --
> You received this message because you are subscribed to the Google Groups
> "AngularJS" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to angular+u...@googlegroups.com.
> To post to this group, send email to ang...@googlegroups.com.
> Visit this group at http://groups.google.com/group/angular?hl=en-US.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
Looking for bootstrap-based widget library for AngularJS?
http://angular-ui.github.com/bootstrap/

Clint Checketts

unread,
Feb 14, 2013, 2:11:28 PM2/14/13
to ang...@googlegroups.com
Nice trick Pawel! Thanks!

Davis Ford

unread,
Feb 14, 2013, 3:30:02 PM2/14/13
to ang...@googlegroups.com
That is a golden nugget of wisdom right there.  Filtering twice certainly isn't ideal.  The signals I'm dealing with are vehicle data from a CAN bus, so I'm going to be streaming data real-time and trying to visualize it in d3.js -- so, this little trick is an awesome find.  Thanks Pawel!

Jean Maynier

unread,
Feb 15, 2013, 4:35:44 AM2/15/13
to ang...@googlegroups.com
It really depends if you only need to use the filtered collection several time in the same controller (or child scopes) or if you need to use it in different parts of the app:
  • same controller: best to use    ng-repeat = "signal in filtered =  (data.signals | filter:data.search)" 
  • several controllers in the app: best to filter in a service and inject the service. It prevent from filtering several times: if you have 2 angular expressions that do the same filtering, you are not only doing the filtering twice, but  2 times n where n is the number of iteration needed to stabilize the model during $digest cycle. So if the filtering function you use is complex, using a service will ensure that you filter only once when a filter imput has changed.
Jean

Davis Ford

unread,
Feb 15, 2013, 9:27:18 AM2/15/13
to ang...@googlegroups.com
Yep, I do have it in a service -- not in the fiddle for brevity, but I will share the data between controllers, and  the data and the API to get it is wrapped up in a service.
Reply all
Reply to author
Forward
0 new messages