AngularJS 리스트 필터

많은 데이터를 반복해서 표시하는데 할 때 유용한 것이 “리스트(list)“이고, 이 리스트의 항목을 나중에 조작할 수 있는 것이 “리스트 필터"이다. 이 두 가지를 결합하여 데이터 나열하는 방법에 대해 설명한다.

리스트 반복 처리

데이터를 취급하는 Web 페이지의 경우, 같은 형식의 다량의 데이터를 테이블 등의 형태로 표시하는 경우가 많다.

이런 경우는 어떤 “같은 표시를 반복 실행한다"라는 구조를 갖고 있다. 즉, 데이터를 “이런 형태로 작성해 간다"라는 것만 지정하면 이후에는 데이터를 전달하면 그 하나 하나를 반복하는 같은 형식으로 출력해 주는 구조이다.

AngularJS에는 “리스트"이라는 것이 있다. 이것은 배열 등의 형태로 정리한 것 중에서 순서대로 값을 꺼내 처리해 가는 구조이다. 이것은 HTML에 속성을 추가하는 것만으로 간단하게 사용할 수 있다.

그러면 예제을 만들면서 설명해 보겠다. 우선 스크립트를 작성하여,script.js라는 파일명으로 저장한다.

var myapp = angular.module('myapp',[]);
var helo = myapp.controller('HeloController',
    function(){
        this.count = 0;
        this.data = [
            {id:0,name:'no data',price:0,get:false},
            {id:1,name:'Android phone',price:7800,get:true},
            {id:2,name:'New iPhone',price:549020,get:false},
            {id:3,name:'windows phone',price:38765,get:true}
        ];
    }
);

여기에서는 HeloController라는 컨트롤러(이전까지 사용했던 예제)에 “data"라는 변수에 id, name, price, get 같은 항목의 데이터를 배열로 정리되어 있다. 이 데이터를 목록으로 형태 표시하려고 한다.

ng-repeat 동작

다음으로는 HTML 을 작성한다. 예제는 아래와 같다.

<!DOCTYPE html>
<html>
<head>
    <title>AngularJS Sample</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
    <script src="script.js"></script>
    <style>
    body { color:gray; }
    h1 { font-size:18pt; font-weight:bold; }
    span.label { display:inline-block;width:50px; color:red; }
    input { width:100px; }
    .msg { font-size:14pt; font-weight:bold;color:gray; }
    th { color:#eee; background-color:#999; padding: 5px 10px;}
    td { color:#333; background-color:#ddd; padding: 5px 10px;}
    </style>
</head>
<body ng-app="myapp" ng-init="num=0">
    <h1>데이터 표시</h1>
    <div ng-controller="HeloController as ctl">

    <table>
    <tr><th>ID</th><th>NAME</th><th>PRICE</th><th>GET?</th></tr>
    <tr ng-repeat="obj in ctl.data">
        <td>{{obj.id}}</td>
        <td>{{obj.name}}</td>
        <td>{{obj.price | currency:"₩"}}</td>
        <td>{{obj.get}}</td>
    </tr>
    </table>
     
    </div>
</body>
</html>

이렇게 작성하여 브라우저에 표시해 본다. data의 데이터가 테이블로 표시된다.

여기에서는 테이블을 사용하여 데이터를 표시하고 있다. 이 부분이다.

<table >
  <tr><th>...생략...</th></tr>
  <tr ng-repeat="obj in ctl.data">
    <td>{{obj.id}}</td>
    <td>{{obj.name}}</td>
    <td>{{obj.price | currency:"₩"}}</td>
    <td>{{obj.get }}</td>
  </tr>
</table>

<table>에는 특별한 것은 없다. 태크안에는 <tr> 태그에 있다. 여기에서 리스트에 의한 반복의 속성 (디렉티브)가 작성되어 있다. 이것은 다음과 같이 작성한다.

ng-repeat="변수 in 배열"

ng-repeat는 준비되어 있는 배열에서 값을 꺼내 변수로 설정하고, 이 ng-repeat가 적혀있는 태그를 출력한다. 즉, 배열에 저장되어 있는 값의 수만큼 ng-repeat가 작성되어 있는 태그가 반복 출력된다. <tr> 태그 내에 <td> 태그를 보면,

<td>{{obj.id}}</td>

이와 같이, 배열에서 얻는 변수 obj 객체의 속성을 지정하여 출력시키고 있다. 객체를 배열에 정리해두면, 이런 식으로 객체 내에 값도 자유롭게 다룰 수 있다.

리스트 필터

여러 데이터를 반복 표시하는 것은 리스트에서 간단히 할 수 있는 것을 알 수 있었다. 이 리스트는 단순히 배열의 내용을 순서대로 표시만 할 수 있는 것은 아니다. 표시할 때에 여러가지 데이터를 조작할 수 있다.

예를 들어, 앞전에 예제에서 <tr> 태그 부분을 다음과 같이 바꾸어 본다.

<tr ng-repeat = "obj in ctl.data
    | orderBy : '-price' ">

이렇게 하면 데이터의 price 값이 큰 것부터 순서대로 정렬하여 표시한다.

여기에서는 obj in ctl.data 다음에 | 기호를 붙이고, 거기에 orderBy : '-price'라는 것이 설정하였다. 이것은 목록에 적용할 필터인 “리스트 필터"이다. 먼저 텍스트를 표시할 때 사용하는 “필터"에 대해 설명했는데, 리스트 필터는 그것에 리스트 버전이라고 할 수 있다. 리스트에 표시되는 항목과 순서 등을 조작 할 수 있는 것이다.

그럼 반복 표시에 사용할 수 있는 필터에 대해 설명한다.

정렬 순서 지정

orderBy : 항목 이름

앞에 예제에서 사용한 것이다. 이것은 지정된 항목을 사용하여 배열을 정렬한다. 콜론 뒤에 항목 이름을 지정한다. 이 때, 이름 앞에 마이너스 기호(-)를 붙이면 역순으로 정렬한다. 예를 들어, price라고 지정하면 price가 작은 것부터 순서대로 되지만 -price라고 큰 순서로 나열된다.

최대 항목 수를 지정

limitTo: 정수

배열의 항목 수를 지정한다. 예를 들어, limitTo:5라고 지정하면 앞에서 5개를 꺼낸다. 또한 limitTo:-5와 같이 마이너스 기호를 붙여서 지정하면, 마지막 5개를 꺼낼 수 있다.

값 비교

filter: 패턴

정규식 패턴을 사용하여 특정 항목만을 추출하는데 사용하는 것이다. 이것은 텍스트 필터도 사용 했었다. 리스트의 경우는 리스트의 항목이 패턴과 일치하는 것만을 꺼내어 처리할 수 있다. 예를 들어, filter:'ok'라고 지정하면 값이 'ok'항목만 표시된다.

커스텀 리스트 필터

기본적으로 제공되는 리스트 필터는 그리 많지는 않다. 그래도 정규 표현식을 사용할 수 있으므로 “패턴을 쓰면 대략적인 가능하다"라고 생각할 있다. 다만, 정규 표현식의 패턴을 이것 저것 지정한다고 하면, 그렇게 사용하기 쉽다고만은 할 수는 없다.

또한 간단한 값이 아닌 복잡한 구조의 객체를 배열에 정리해 경우는 객체에 따라 필요한 값을 꺼내어 확인하는 것과 같은 필터가 필요하다.

이러한 경우 필터를 추가하여 사용하는 옵션도 있다. 텍스트 필터뿐만 아니라, 리스트 필터도 직접 만들 수 있다. 이는 다음과 같이 만든다.

컨트롤러.filter(이름, 함수);

텍스트 필터와 같다. 그러나 준비하는 함수는 조금 다르다. 이는 다음과 같다.

function() {
  return function(인수) {
    ...... 인수의 배열을 조작한다 ......
    return 배열;
  }
}

함수에는 추가로 return하도록 되어 있다. 이 return되는 함수가 필터를 해서 실행되는 처리이다.

이 필터용 함수는 인수를 1개 준비된다. 이는 데이터의 배열이 전달된다. 이 배열을 바탕으로 새로운 배열을 만들고, 그것을 return하면 그 배열을 바탕으로 ng-repeat 반복이 실행되게 되는 것이다. 즉, 어떻게 새로운 배열을 만들 것인가를 생각해서 함수를 만들면 된다는 것이다.

목록 필터 생성

그러면 간단한 리스트 필터를 만들어서, 그 필터를 이용한 예제 스크립트에서 만들어 보자. script.js를 아래와 같이 작성하여 저장한다.

var myapp = angular.module('myapp',[]);
var helo = myapp.controller('HeloController',
    function() {
        this.count = 0;
        this.data = [
            { id:0, name:'no data',price:0,get:false },
            { id:1, name:'Android phone', price:7800, get:true },
            { id:2, name:'New iPhone', price:549020, get:true },
            { id:3, name:'windows phone', price:38765, get:true },
            { id:4, name:'firefox phone', price:14370, get:true },
            { id:5, name:'blackberry phone', price:-123, get:false },
        ];
        this.getData = function() {
            return this.data[this.count].id + ': ' + 
                this.data[this.count].name + ', ' + 
                this.data[this.count].price + '.';
        };
    }
);
 
//get을 체크하여, true인 경우만 반환한다.
helo.filter('getRepeat', 
    function() {
        return function(items) {
            var res = [];
            angular.forEach(items,function(item) {
                if (item.get)
                    res.push(item);
            });
            return res;
        };
    }
);

이번에는 HeloCotroller 컨트롤러에 getRepeat라는 리스트 필터를 작성하였다. 필터에 return되는 함수 부분을 보면 다음과 같이 되어 있다.

function (items) {
  var res = [];
  angular.forEach (items, function (item) {
    if (item.get)
        res.push (item);
  });
  return res;
};

여기에서는 인수로 전달된 items에서, get 메소드가 true의 것만을 배열에 정리하여 반환한다. 배열의 반복 처리를 실시하는데, angular 객체의 forEach 라는 것을 사용하고 있다.

angular.forEach(배열, 함수);

이 forEach는 첫번째 인수의 배열에서 순서대로 요소를 얻어내고, 두번째 인수의 함수를 실행하고 있다. 얻어온 요소는 함수에 인수로 전달된다. 함수에는 이 인수를 사용하여 배열의 모든 요소에 대해 처리할 수 있도록 되어 있는 것이다.

커스텀 필터 이용

그럼, 만든 필터 “getRepeat"를 사용해 보자. HTML 파일을 아래와 같이 작성한다.

<!DOCTYPE html>
<html>
<head>
    <title>AngularJS Sample</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
    <script src="script.js"></script>
    <style>
    body { color:gray; }
    h1 { font-size:18pt; font-weight:bold; }
    span.label { display:inline-block;width:50px; color:red; }
    input { width:100px; }
    .msg { font-size:14pt; font-weight:bold;color:gray; }
    th { color:#eee; background-color:#999; padding: 5px 10px;}
    td { color:#333; background-color:#ddd; padding: 5px 10px;}
    </style>
</head>
<body ng-app="myapp" ng-init="num=0">
    <h1>데이터 표시</h1>
    <p>텍스트를 입력해 주세요.</p>
    <div ng-controller="HeloController as ctl">
     
    <div class="input">
        <span class="label">검색:</span>
        <input type="text" ng-model="fstr">
    </div>
    <p class="msg">{{ctl.getData()} }</p>
    <hr/>
    
    <table>
    <tr><th>ID</th><th>NAME</th><th>PRICE</th><th>GET?</th></tr>
    <tr ng-repeat="obj in ctl.data | filter:fstr | orderBy : '-price' | getRepeat">
        <td>{{obj.id}}</td>
        <td>{{obj.name}}</td>
        <td>{{obj.price | currency:"₩"}}</td>
        <td>{{obj.get}}</td>
    </tr>
    </table>
     
    </div>
</body>
</html>

이번에는 getRepeat 필터 외에 텍스트를 사용하여 검색하는 필터도 추가되어 있다. HTML 파일을 열면 “GET?“의 값이 true의 데이터만 테이블에 표시된다. 이것이 getRepeat 필터에 의한 처리이다.

표시를 확인한 후에 “검색"필드에 뭔가 텍스트를 입력해 본다. 그러면, 그 텍스트를 포함하는 항목만 표시된다. 이것은 filter 필터를 이용한 처리이다. filter를 사용하면 간단히 데이터를 검색할 수 있다.

<tr> 태그의 ng-repeat 부분을 살펴 보면, 이렇게 작성되어 있다.

ng-repeat="obj in ctl.data | filter:fstr | orderBy : '-price' | getRepeat"
  • obj in ctl.data : ctl.data의 배열 순서로 값을 꺼내 obj에 대입을 반복한다.
  • filter:fstr : 텍스트에 fstr 포함 여부 확인한다.
  • orderBy : ‘-price’ : price 값이 큰 순으로 정렬한다.
  • getRepeat : get 값이 true 것만 표시한다.

이런 식으로 4개의 값을 정리하고 있다. 첫번째 obj in ctl.data로 반복 처리를 하고, 그 3가지 리스트 필터로 배열의 내용을 조작하고 있다. 이것으로 “검색”, “정렬”, “getRepeat” 모두가 포함된다.

리스트 필터도 텍스트 필터와 같이 만들어 보면 의외로 쉽게 만들 수 있다. 리스트와 리스트 필터는 데이터의 표시를 하는 경우에는 필수 기능이라고 할 수 있다. 꼭 여기에 이해하도록 하자.




최종 수정 : 2017-12-27