angularjs filter

I think it’s best to understand what we even want to learn. To do that, we need to understand what filters really are and how we use them. For me, there are four types of filters. Yes, four, but there of course can be other variants. Let’s rattle through them:

Filter 1: Static (single) use filter

Filter 1 just filters a single piece of Model data (not a loop or anything fancy) and spits it out into the View for us. This could be something like a date:

<p>{{ 1400956671914 | date: 'dd-MM-yyyy' }}</p>

When rendered, the DOM would look like this:

<p>24-05-2014</p>

So how do we create this, or something similar?

Let’s take my full name for example, if I wanted to quickly filter it and make it uppercase, how would we do it?

Angular has a .filter() method for each Module, which means we can write our own custom filters. Let’s look at a stripped down filter:

app.filter('', function () {
  return function () {
    return;
  };
});

As you can see, we can name our filter and we return a function. What the heck do these do?

The returned function gets invoked each time Angular calls the filter, which means two-way binding for our filters. The user makes a change, the filter runs again and updates as necessary. The name of our filter is how we can reference it inside Angular bindings.

Let’s fill it in with some data:

app.filter('makeUppercase', function () {
  return function (item) {
    return item.toUpperCase();
  };
});

So what do these mean? I’ll annotate:

// filter method, creating `makeUppercase` a globally
// available filter in our `app` module
app.filter('makeUppercase', function () {
  // function that's invoked each time Angular runs $digest()
  // pass in `item` which is the single Object we'll manipulate
  return function (item) {
    // return the current `item`, but call `toUpperCase()` on it
    return item.toUpperCase();
  };
});

As an example app:

var app = angular.module('app', []);

app.filter('makeUppercase', function () {
  return function (item) {
      return item.toUpperCase();
  };
});

app.controller('PersonCtrl', function () {
  this.username = 'Todd Motto';
});

Then we declare it in the HTML:

ng-app="app">
ng-controller="PersonCtrl as person">

{{ person.username | makeUppercase }}

</div>

And that’s it, jsFiddle link and output:

http://jsfiddle.net/toddmotto/xz39g/embedded/result,js,html

Filter 2: Filters for repeats

Filters are really handy for iterating over data and without much more work, we can do exactly that.

The syntax is quite similar when filtering a repeat, let’s take some example data:

app.controller('PersonCtrl', function () {
  this.friends = [{
    name: 'Andrew'        
  }, {
    name: 'Will'
  }, {
    name: 'Mark'
  }, {
    name: 'Alice'
  }, {
    name: 'Todd'
  }];
});

We can setup a normal ng-repeat on it:

<ul>
  <li ng-repeat="friend in person.friends">
    {{ friend }}
  </li>
</ul>

Add a filter called startsWithA, where we only want to show names in the Array beginning with A:

<ul>
  <li ng-repeat="friend in person.friends | startsWithA">
    {{ friend }}
  </li>
</ul>

Let’s create a new filter:

app.filter('startsWithA', function () {
  return function (items) {
    var filtered = [];
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      if (/a/i.test(item.name.substring(0, 1))) {
        filtered.push(item);
      }
    }
    return filtered;
  };
});

There are two different things happening here! First, item previously is now items, which is our Array passed in from the ng-repeat. The second thing is that we need to return a new Array. Annotated:

app.filter('startsWithA', function () {
  // function to invoke by Angular each time
  // Angular passes in the `items` which is our Array
  return function (items) {
    // Create a new Array
    var filtered = [];
    // loop through existing Array
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      // check if the individual Array element begins with `a` or not
      if (/a/i.test(item.name.substring(0, 1))) {
        // push it into the Array if it does!
        filtered.push(item);
      }
    }
    // boom, return the Array after iteration's complete
    return filtered;
  };
});

ES5 version using Array.prototype.filter for a super clean filter:

app.filter('startsWithA', function () {
  return function (items) {
    return items.filter(function (item) {
      return /a/i.test(item.name.substring(0, 1));
    });
  };
});

And that’s it, jsFiddle link and output:

http://jsfiddle.net/toddmotto/GDmN7/embedded/result,js,html

Filter 3: Filters for repeats with arguments

Pretty much the same as the above, but we can pass arguments into the functions from other Models. Let’s create an example that instead of “filtering by letter A”, we can let the user decide, so they can type their own example:

<input type="text" ng-model="letter">
<ul>
  <li ng-repeat="friend in person.friends | startsWithLetter:letter">
    {{ friend }}
  </li>
</ul>

Here I’m passing the filter the letter Model value from ng-model="letter". How does that wire up inside a custom filter?

app.filter('startsWithLetter', function () {
  return function (items, letter) {
    var filtered = [];
    var letterMatch = new RegExp(letter, 'i');
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      if (letterMatch.test(item.name.substring(0, 1))) {
        filtered.push(item);
      }
    }
    return filtered;
  };
});

The most important thing to remember here is how we’re passing in arguments! Notice letter now exists inside the return function (items, letter) {};? This corresponds directly to the :letter part. Which means we can pass in as many arguments as we need (for example):

<input type="text" ng-model="letter">
<ul>
  <li ng-repeat="friend in person.friends | startsWithLetter:letter:number:somethingElse:anotherThing">
    {{ friend }}
  </li>
</ul>

We’d then get something like this:

app.filter('startsWithLetter', function () {
  return function (items, letter, number, somethingElse, anotherThing) {
    // do a crazy loop
  };
});

And that’s it, jsFiddle link and output:

http://jsfiddle.net/toddmotto/53Xuk/embedded/result,js,html

Filter 4: Controller/$scope filter

This one’s a bit of a cheat, and I would only use it if you really have to use it. We take advantage of the :argsyntax and pass a $scope function into Angular’s filter Object!

The difference with these type of filters is that the functions declared are the ones passed into the filter function, so we’re technically writing a function that gets passed into our return function. We don’t get Array access, just the individual element. Important to remember.

Let’s create another function that filters by letter w instead. First let’s define the function in the Controller:

app.controller('PersonCtrl', function () {
  // here's our filter, just a simple function
  this.startsWithW = function (item) {
    // note, that inside a Controller, we don't return
    // a function as this acts as the returned function!
    return /w/i.test(item.name.substring(0, 1));
  };
  this.friends = [{
    name: 'Andrew'        
  }, {
    name: 'Will'
  }, {
    name: 'Mark'
  }, {
    name: 'Alice'
  }, {
    name: 'Todd'
  }];
});

Then the repeat:

ng-controller="PersonCtrl as person">
  • ng-repeat="friend in person.friends | filter:person.startsWithW"> {{ friend }}

These functions are obviously scoped and not reusable elsewhere. If it makes sense then use this setup, else don’t…

The official doc: The filter function should be a pure function, which means that it should be stateless and idempotent. Angular relies on these properties and executes the filter only when the inputs to the function change.

Be careful of infinite loop being triigered

FROM HERE

angularjs filter on array

Use property in input’s ng model

Filter is used for selecting a subset of a give array. The requirements for a filter are an array to be filtered and the predicate based on which the array need to be filtered. The predicate could be as simple as a string and let’s try filtering using a string at first.

<div class="container" style="margin-top:100px;">
    <div class="row">
        <div class="span12" ng-controller="MediaCtrl">
            <input type="text" ng-model="searchTerm">
            <table class="table">
                <thead>
                    <tr>
<th><a href="" ng-click="setSortExpression('artistName')" >Artist Name</a></th>
<th><a href="" ng-click="setSortExpression('trackName')">Track</a></th>
<th><a href="" ng-click="setSortExpression('primaryGenreName')">Genre</a></th>
<th><a href="" ng-click="setSortExpression('trackPrice')" >Price</a></th>                       
                    </tr>
                </thead>
                <tbody>
<tr ng-repeat="r in result.results | filter:searchTerm  | orderBy:sortExpression">
    <td>{{r.artistName}}</td>
    <td>{{r.trackName}}</td>
    <td>{{r.primaryGenreName}}</td>
    <td>{{r.trackPrice}}</td>
</tr>
                </tbody>
            </table>


        </div>
    </div>
</div>

Giving a full blown filtering to our application is as easy as introduing a new model (searchTerm here) and applying the filter to the array model passing the model value as argument. The drawback (or advantage) of this method is it matches the records based on comparing the search term with each and every property of the objects in the array. If we need to fine tune the filtering process we can pass an object instead of a simple string.

<div class="container" style="margin-top:100px;">
    <div class="row">
        <div class="span12" ng-controller="MediaCtrl">
            <input type="text" ng-model="searchTerm.$">
            <table class="table">
                <thead>
                    <tr>
<th><a href="" ng-click="setSortExpression('artistName')" >Artist Name</a>
    <br><input type="text" ng-model="searchTerm.artistName">
</th>
<th><a href="" ng-click="setSortExpression('trackName')">Track</a>
    <br><input type="text" ng-model="searchTerm.trackName"></th>
<th><a href="" ng-click="setSortExpression('primaryGenreName')">Genre</a>
    <br><input type="text" ng-model="searchTerm.primaryGenreName"></th>
<th><a href="" ng-click="setSortExpression('trackPrice')" >Price</a>
    <br><input type="text" ng-model="searchTerm.trackPrice"></th>                       
                    </tr>
                </thead>
                <tbody>
<tr ng-repeat="r in result.results | filter:searchTerm  | orderBy:sortExpression">
    <td>{{r.artistName}}</td>
    <td>{{r.trackName}}</td>
    <td>{{r.primaryGenreName}}</td>
    <td>{{r.trackPrice}}</td>
</tr>
                </tbody>
            </table>


        </div>
    </div>
</div>

Now the search tern is an object with properties matching those on the listed columns and the list is filtered based on the values inside this object. Dollar ($) symbol has a special meaning of match all the properties and it is used for searching across all of the properties.

Use function

Another way to do this is to use a function:

<div ng-repeat="product in products | filter: myFilter">

$scope.myFilter = function (item) { 
    return item === 'red' || item === 'blue'; 
};

Use object structure in filter expression

If you want to filter on a grandchild (or deeper) of the given object, you can continue to build out your object hierarchy. For example, if you want to filter on ‘thing.properties.title’, you can do the following:

<div ng-repeat="thing in things | filter: { properties: { title: title_filter } }">

You can also filter on multiple properties of an object just by adding them to your filter object:

<div ng-repeat="thing in things | filter: { properties: { title: title_filter, id: id_filter } }">

Be careful with angular filter

If you want select specific value in field, you can’t use filter.

Example:

app.controller('FooCtrl', function($scope) {
   $scope.products = [
       { id: 1, name: 'test', color: 'lightblue' },
       { id: 2, name: 'bob', color: 'blue' }
       /*... etc... */
   ];
});

<div ng-repeat="product in products | filter: { color: 'blue' }"> 

This will select both, because use something like substr
That means you want select product where “color” contains string “blue” and not where “color” is “blue”.

<div ng-repeat="product in products | filter: { color: 'blue' }:true">

will work on only exact matches (the ‘true’ at the end is the comparator argument: link

from here

Add Ordering to Annotated Servlet 3 Filter Classes

If you’re like me you really like the new Servlet 3.0 spec that allows for annotated servlet classes. This approach along with the new ServletContainerInitializer interface potentially allows for code-based application configuration and deployment without an application deployment descriptor (web.xml) file.

One thing lacking in the new spec’s annotations, is the ordering of the filter chain. This, IMO, is REALLY important. It allows the developer to ensure encoding filters or other types of “must happen first” filters are ahead of other filters in the chain. While the documentation states when using annotated filter classes the order is undetermined, my tests have shown the order is the order in which they appear in the class path. If all your annotated filter classes are in one package and named according to order (AFilter.class, BFilter.class, CFilter.class), then there is no problem. But this is unlikely. Also, libraries often come with non-annotated filter classes which must be programmatically included in the filter chain, or added via the web.xml file.

I have found I can annotate my classes – have them anywhere on the class path – and STILL achieve ordering by specifying only the class names in the web.xml file. The following is an example of how to order two annotated Servlet 3 filters that are on the class path:

<filter-mapping>
    <filter-name>ZFilter</filter-name>
</filter-mapping>
<filter-mapping>
    <filter-name>AFilter</filter-name>
</filter-mapping>

In my tests – this properly orders the filter chain so ZFilter is before AFilter. If there was another annotated filter class on the class path and NOT part of this mapping, it would be AFTER the filters in this mapping. E.g., ZFilter,AFilter, SomeOtherFilter. Removing these mappings returns the order to class path ordering: AFilter,SomeOtherFilter, ZFilter.

This approach allows one to embrace the new servlet spec – and have minimal configuration in the web.xml. Theweb.xml would also be used to set up non-Servlet 3 filters (E.g., Filters provided by libraries).

If you are pragmatically adding filters to the context in a ServletContainerInitializer then the order you add the filters is maintained – and the isMatchAfter parameter is honored.

context.addFilter(“SomeFilter”,SomeFilter.class)
        .addMappingForUrlPatterns(null, true, “/*”);

I have found I can use a combination of all three approaches, but understanding the order of operations is important:

  1. Ordering of web.xml definitions are processed first.
  2. Other annotated filters NOT in the web.xml will be NEXT in the chain.
  3. Filters added via the ServletContext addFilter() method are processed last, AND the value ofisMatchAfter is honored. So you can add a filter using this method, and place it FIRST or NEXT in the filter chain. 

Other thoughts

Check the spec section 8.2 and add the bits you need to your web.xml or web-fragment.xml, depending on your packaging. Note these are

In a web.xml you can filters and listeners by name:

<absolute-ordering>
  <name>FirstFilter</name>
  <name>NextFilter</name>
</absolute-ordering>

In a web-fragment.xml you can filters and listeners before or after others as specified by name or generically with the “others” tag. For example, to try to order your JAR first, use the following in the web-fragment.xml

<order>
  <before>
    <others/>
  </before>
</order>

Note that the web-fragment.xml orders for the JAR, and filters or listeners within the same JAR are arbitrarily ordered, unless specified in the application’s web.xml.

FROM HERE

JFileChooser notes

We get file

by using getSelectedFile() method, which return the File object.

The open/close button

can be disabled by using setControlButtonsAreShown(false) method.

File filter

can be add using: setFileFilter(new Xlsfilter());

Xlsfilter:

class Xlsfilter extends FileFilter
{
    public boolean accept(File f) {
        return f.isDirectory() || f.getName().toLowerCase().endsWith(".xls") || f.getName().toLowerCase().endsWith(".xlsx");
    }

    public String getDescription() {
        return "Xls files";
    }
}

PropertyChangeListener

we can hide the accept/cancel buttons by calling chooser.setControlButtonsAreShown(false) when detect any selecting change on files/directories:

fileChooser.addPropertyChangeListener(new PropertyChangeListener()
        {
            public void propertyChange(PropertyChangeEvent evt)
            {
                if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(evt.getPropertyName()))
                {
                    File file = (File) evt.getNewValue();

                    if (file != null && file.isFile() && file.getName().contains("xls"))
                    {
                        startProcessButton.setEnabled(true);

                    }
                    else if (file != null)
                    {
                        startProcessButton.setEnabled(false);
                    }
                }

                fileChooser.repaint();
            }
        });

f

 

filter 和 aop

现在AOP的设计开发理念在软件开发中用的越来越广泛,在我们开发的软件中也广泛进行了使用。而最常用的就是filter和interceptor。
Filter

该过滤器的方法是创建一个类XXXFilter实现此接口,并在该类中的doFilter方法中声明过滤规则,然后在配置文件web.xml中声明他所过滤的路径
<filter>
<filter-name>XXXFilter</filter-name>
<filter-class>
com.web.util.XXXFilter
</filter-class>
</filter>

<filter-mapping>
<filter-name>XXXFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>

Interceptor

该过滤器的方法也是创建一个类XXXInterceptor实现此接口,在该类中intercept方法写过滤规则,不过它过滤路径的方法和Filter不同,它与strut.xml结合使用(其他开发框架各自有自己的切入点),

创建一个strus.xml的子配置文件struts-l99-default.xml,它继承与struts2的struts-default,此配置文件是其他子配置文件的父类,只要是继承与该文件的配置文件所声明的路径都会被它过滤 如下
<package name=”XXX-default” namespace=”/” extends=”struts-default”>

<interceptors>
<interceptor name=”authentication” />

<interceptor-stack name=”user”>
<interceptor-ref name=”defaultStack” />
<interceptor-ref name=”authentication” />
</interceptor-stack>

<interceptor-stack name=”user-submit”>
<interceptor-ref name=”user” />
<interceptor-ref name=”token” />
</interceptor-stack>

 

<interceptor-stack name=”guest”>
<interceptor-ref name=”defaultStack” />
</interceptor-stack>

 

<interceptor-stack name=”guest-submit”>
<interceptor-ref name=”defaultStack” />
<interceptor-ref name=”token” />
</interceptor-stack>

 

</interceptors>
<default-interceptor-ref name=”user” />

</package>
比较一,filter基于回调函数,我们需要实现的filter接口中doFilter方法就是回调函数,而interceptor则基于java本身的反射机制,这是两者最本质的区别。
比较二,filter是依赖于servlet容器的,即只能在servlet容器中执行,很显然没有servlet容器就无法来回调doFilter方法。而interceptor与servlet容器无关。
比较三,Filter的过滤范围比Interceptor大,Filter除了过滤请求外通过通配符可以保护页面,图片,文件等等,而Interceptor只能过滤请求。
比较四,Filter的过滤例外一般是在加载的时候在init方法声明,而Interceptor可以通过在xml声明是guest请求还是user请求来辨别是否过滤。

JSP Servlet Filter

Basic

Servlet Filters are the latest components that are added in Servlet 2.3 specifications. These filters are used basically for intercepting and modifying requests and response from server.  Consider a scenario where you want to check session from the every users request and if it is valid then only you want to let the user access the page. You can acheive this by checking sessions on all the servlet pages (or JSP pages) which users queries or you can do this by using Filter.

import java.io.IOException;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class LogFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        //Get the IP address of client machine.
        String ipAddress = request.getRemoteAddr();
        //Log the IP address and current timestamp.
        System.out.println("IP "+ipAddress + ", Time "
                            + new Date().toString());
        chain.doFilter(req, res);
    }
    public void init(FilterConfig config) throws ServletException {
        //Get init parameter
        String testParam = config.getInitParameter("test-param");
        //Print the init parameter
        System.out.println("Test Param: " + testParam);
    }
    public void destroy() {
        //add code to release any resource
    }
}
in Web.xml file:
<filter>
    <filter-name>LogFilter</filter-name>
    <filter-class>
        net.viralpatel.servlet.filters.LogFilter
    </filter-class>
    <init-param>
        <param-name>test-param</param-name>
        <param-value>This parameter is for testing.</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>LogFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

process sequence

Any processing you want to occur before the target resource is invoked must be prior to the chain doFilter() call. Any processing you want to occur after the completion of the target resource must be after the chain doFilter() call. This can include directly setting headers on the response.

filter-cycle