Front-End

[Vue.js] filter(필터) 기본 사용법 및 전역 filter 설정 방법: 검색 필터 샘플 스크립트 및 돈 콤마 찍기 스크립트

Vue.js는 필터(filter)를 사용하여 텍스트의 형식화를 적용할 수 있다. 가령, 숫자 3자리 수 마다 콤마 찍기(돈 표기법), 또는 텍스트로 입력받은 값을 날짜형식으로 포맷팅하거나, 입력받은 문자를 모두 소문자 또는 대문자로 변경하거나 첨부한 파일의 크기를 표시, 입력 받은 문자의 첫 글자만 대문자 처리 등의 필터링 기능을 구현하여 사용할 수 있다.

 

필터(filter)를 적용하는 방법 2가지

1. 콤포넌트 옵션(속성)에 로컬 필터를 정의하는 방법

콤포넌트 속성 중에 filter() 속성에 필터를 정의하여 사용한다. 

[html]

<div id="app">
  <h2>Todos:</h2>
  <input type="text"
           v-model="filterText" placeholder="숫자를 입력하세요">
  <span>입력 text : {{filterText}}</span>
  
  <br/> 
  <span>{{filterText | moneyPoint | strUnit}}</span>
</div>

[js]

new Vue({
  el: "#app",
  data : {
	arrText: ['Korea','English','Monkey','Kor','Kind'],
    filterText: '',
    arrNumbers: [1,2,3,4,5,6,7,8,9,10],
  },
  methods: {
  },
  filters: {
  	//3자리마다 콤마 찍기
    moneyPoint: function (value) {
    	return value.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
    },
    capitalize: function (value) {
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    },
    toUppercase(value) {
		return value.toUpperCase();
	},
    strUnit: function (value) {
    	return `${value} 원`;
    }
  },
})

 

2. 전역필터 설정하는 방법

콤포넌트가 아닌 모든 곳에서 filter를 사용하고자하는 경우 전역 filter를 Vue 인스턴스 생성 이전에 filter를 정의하여 사용한다. 

Vue.filter('moneyFilter', function (value) {
    return value.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
});


Vue.filter('unit', function (value) {
    return `${value} 원`;
});

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

Vue.filter('to-lowercase', function(value) {
  return value.toLowerCase();
})

 
new Vue({
  el: '#app',
  render: h => h(App)
})

 

필터체인( 필터 체이닝)

필터를 여러개의 파이프(|)를 사용하여 연결할 수 있다.  가령  아래 스니펫과 같이 2개의 필터를 사용하게되면 앞쪽부터 적용된다.

  • 기본 필터 체이닝 : {{ message | filterA | filterB }}
  • 필터에 파라미터가 추가된 경우 : {{ message | filterA(‘arg1’, arg2) }} 

[HTML]

<div id="app">
  <h2>Todos:</h2>
  <input type="text"
           v-model="filterText" placeholder="숫자를 입력하세요">
  <span>입력 text : {{filterText}}</span>
  
  <br/> 
  <span>{{filterText | moneyPoint | strUnit}}</span>
</div>

[JS]

new Vue({
  el: "#app",
  data : {
		arrText: ['Korea','English','Monkey','Kor','Kind'],
    filterText: '',
    arrNumbers: [1,2,3,4,5,6,7,8,9,10],
  },
  methods: {
  },
  filters: {
		moneyPoint: function (value) {
			return value.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
		},
    strUnit: function (value) {
    	return `${value} 원`;
    }
  },
})

[CSS]

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

[결과]


 

필터(filter)를 사용하는 방법

filter는 중괄호 보간법(mustache)과 v-bind 표현법 중에 선택하여 사용할 수 있다.

필터는 렌더링하고자 하는 문자열(변수) 뒤에(자바스크립트 표현식 마지막) 파이프(|)를 추가한 후 필터명을 지정한다.

// 중괄호 보간법(mustache)
{{ message | capitalize }}

// v-bind 표현법
<div v-bind:id="rawId | formatId"></div>

 

computed 속성(property) 내에 filter 사용방법

Vue의 filter를 사용하는 방법 외에 , computed() 프로퍼티(속성)에서 필터를 정의하여 사용할 수 도 있다.

[html]

<div id="app">
  <h2>Todos:</h2>
  <div>
    <input type="text" v-model="filterText">
    <ul>
      <li v-for="item in searchFiltered">{{item}}</li>
    </ul>
  </div>
 
</div>

[JS]

new Vue({
  el: "#app",
  data : {
	arrText: ['Korea','English','Monkey','Kor','Kind'],
	filterText: '',
    arrNumbers: [1,2,3,4,5,6,7,8,9,10],
  },
  methods: {
	myFilters() {
    	this.arrNumbers = this.arrNumbers.filter(x=> x>1);
    }  
  }, 

  computed: {
    searchFiltered() {
      return this.arrText.filter((element)=>{
        return element.match(this.filterText);
      });
    },
	getNumber: function() {
    	return this.arrNumbers.filter(function (number) {
        	return number % 2 === 0
        })
    }    
  }


})

[CSS]

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

[실행결과]

K를 입력한 결과 K로 시작하는 단어만 출력한다. 이런 방식으로 검색 필터를 만들 수 있다.


콤포넌트 속성에서 로컬필터를 만들어서 사용하거나 computed() 속성에 필터를 만들어서 사용하는 경우, 동일한 기능을 하는 필터를 매번 새롭게 생성하는 콤포넌트들에서 중복적으로 정의 후 사용해야한다면 번거롭고 귀찮을 수 있다.  이러한 문제를 해결하기 위해 Mixins를 사용하여 처리하면 해결할 수 있다.

 

Mixins

Mixins는 Vue 컴포넌트에 재사용 가능한 기능을 배포하는 유연한 방법입니다. mixin 객체는 모든 구성 요소 옵션을 포함할 수 있습니다. 컴포넌트에 mixin을 사용하면 해당 mixin의 모든 옵션이 컴포넌트의 고유 옵션에 “혼합”됩니다. dictionaryMixin.js 임의 자바스크립트 파일 하나를 생성한다.

  export const dictionaryMixin = {
    data() {
      return {
        arrText: ['Korea','English','Monkey','Kor','Kind'],
        filterText: ''
      }
    },
    computed: {
      searchFiltered() {
        return this.arrText.filter((element)=>{
          return element.match(this.filterText);
        });
      }
    }
}

컴포넌트 내 스크립트에서 import 문을 사용하여 불러온다. 기존 html에서 동일하게 사용가능하다.

<div id="app">
  <h2>Todos:</h2>
  <div>
    <input type="text" v-model="filterText">
    <ul>
      <li v-for="item in searchFiltered">{{item}}</li>
    </ul>
  </div>
 
</div>

..........

<script>
import { dictionaryMixin } from './lib/dictionaryMixin';

export default {
  mixins: [dictionaryMixin]
}
</script>

 

Global mixins

mixin은 전역으로 설정할 수 있다. 모든 인스턴스, 콤퍼넌트에 자동으로 추가됨으로 최대한 사용을 자제(?) 주의해서 사용한다.  웬만하면 로컬 컴포넌트에 추가하여 사용하는것을 권장한다.  main.js 파일 안에 vue.mixin()를 사용하여 정의

[main.js]

import Vue from 'vue';
import { Filter } from '@/test/lib/mixin/filter';
import App from './App.vue';

let app;
if (!app) {
  Vue.mixin(Filter);

  app = new Vue({
    render: h => h(App),
  }).$mount('#app');
}

[/test/lib/mixin/ 폴더안에 filter.js]

filters: {    
    // 금액 돈 표기 수치값 3자리 마다 콤마 적용
    $_filter_comaStr(value = '') {
      const rtnValue = ` ${value}`;
      return String(rtnValue).replace(/B(?=(d{3})+(?!d))/g, ',');
    },

    // 텍스트 형식의 문자열을 날짜 및 시간 포맷팅
    $_filter_strDate(value = '', format, pdate, ptime) {
      const dd = pdate || '.';
      const td = ptime || ':';
      let targetStr = String(value);
      if (targetStr) {
        switch (format) {
            case 'yyyy':
              targetStr = targetStr.substr(0, 4);
              break;
            case 'yyyyMM':
              targetStr = targetStr.substr(0, 4) + dd + targetStr.substr(4, 2);
              break;
            case 'yyyyMMdd':
              targetStr = targetStr.substr(0, 4) + dd + targetStr.substr(4, 2) + dd + targetStr.substr(6, 2);
              break;
            case 'HHmm':
              targetStr = targetStr.substr(0, 2) + td + targetStr.substr(2, 2);
              break;
            case 'HHmmss':
              targetStr = targetStr.substr(0, 2) + td + targetStr.substr(2, 2) + td + targetStr.substr(4, 2);
              break;
            default:
              targetStr = null;
              break;
        }
      }
      return targetStr;
    },

    // 파일사이즈 표시
    $_filter_bytes(bytes = 0, decimals) {
      const k = 1024;
      const dm = decimals <= 0 ? 0 : decimals || 2;
      const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      const retVal = parseFloat((bytes / (k ** i)).toFixed(dm));
      return `${retVal} ${sizes[i]}`;
    },

  },
};

export default Filter;

 

vue.js 검색 필터 만들기

입력값의 대소문자 구분을 없애기 위해 toLowerCase()적용한 검색 필터 기능 구현 샘플코드이다.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" >

</head>
<body>
<div id="app">

   <div class="panel panel-default">
                <div class="panel-heading" style="font-weight:bold">
                <span class="glyphicon glyphicon-align-justify"></span> All Resources</div>
                <div class="row">
                    <div class="search-wrapper panel-heading col-sm-12">
                        <input class="form-control" type="text" v-model="searchQuery" placeholder="Search" />
                    </div>                        
                </div>
                <div class="panel-body" style="max-height: 400px;overflow-y: scroll;">
                    <table v-if="resources.length" class="table">
                        <thead>
                            <tr>
                                <th>Resource</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="item in filteredResources">
                                <td><a v-bind:href="item.uri" target="_blank">{{item.title}}</a></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
</div>

</body>
</html>

[JS]

new Vue({
  el: '#app',
  data() {
    return {
      searchQuery:'',
    resources:[
    {title:"aaa",uri:"aaaa.com",category:"a",icon:null},
     {title:"add",uri:"aaaa.com",category:"a",icon:null},
      {title:"aff",uri:"aaaa.com",category:"a",icon:null},
    {title:"bbb",uri:"bbbb.com",category:"b",icon:null},
    {title:"bdd",uri:"bbbb.com",category:"b",icon:null},
    {title:"bsb",uri:"bbbb.com",category:"b",icon:null},
    {title:"ccc",uri:"cccc.com",category:"c",icon:null},
    {title:"ddd",uri:"dddd.com",category:"d",icon:null}
    ]
    };
  },
  computed: {
    filteredResources (){
      if(this.searchQuery){
      return this.resources.filter((item)=>{
        return item.title.startsWith(this.searchQuery.toLowerCase());
      })
      }else{
        return this.resources;
      }
    }
  }
 

})

[결과]


검색 필터 예제 2

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" >

</head>
<body>
<div id="app">
   <div class="panel panel-default">
   <div class="panel-heading">
         <strong> All Resources</strong></div>
            <div class="row">
                 <div class="search-wrapper panel-heading col-sm-12">
                     <input class="form-control" type="text" v-model="searchQuery" placeholder="Search" />
                </div>                        
            </div>
        <div class="table-responsive">
            <table v-if="resources.length" class="table">
                <thead>
                    <tr>
                         <th>Resource</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="item in resultQuery">
                        <td><a v-bind:href="item.uri" target="_blank">{{item.title}}</a></td>
                    </tr>
                </tbody>
            </table>
        </div>
   </div>
   </div>

</body>
</html>
new Vue({
  el: '#app',
  data() {
    return {
        searchQuery: null,
        resources:[
            {title:"ABE Attendance",uri:"aaaa.com",category:"a",icon:null},
            {title:"Accounting Services",uri:"aaaa.com",category:"a",icon:null},
            {title:"Administration",uri:"aaaa.com",category:"a",icon:null},
            {title:"Advanced Student Lookup",uri:"bbbb.com",category:"b",icon:null},
            {title:"Art & Sciences",uri:"bbbb.com",category:"b",icon:null},
            {title:"Auxiliares Services",uri:"bbbb.com",category:"b",icon:null},
            {title:"Basic Skills",uri:"cccc.com",category:"c",icon:null},
            {title:"Board of Trustees",uri:"dddd.com",category:"d",icon:null}
        ]
    };
  },
  computed: {
    resultQuery(){
      if(this.searchQuery){
        return this.resources.filter((item)=>{
          return this.searchQuery.toLowerCase().split(' ').every(v => item.title.toLowerCase().includes(v))
        })
      }else{
        return this.resources;
      }
    }
  }
 

})

[결과]


 

json array 중복 객체 제거방법

필터 filter(), findIndex()를 사용하여 배열의 중복되는 객체 제거하는 방법

데이터를 추가 또는 삭제시 배열에 중복으로 밀어넣은 후 중복을 제거하는 방법이 개발시 더 편할 수 있다.

팝업창에서 받아와 데이터를 추가해야하고 메인화면 뷰 상에서 추가 또는 삭제해야하는 상황이면 더더욱 그렇다.

그냥 개인적인 생각이다. 개발이 편한 방법으로 !!

const result = this.data.selectedKeymsgList.filter((item1, idx1) => 
	this.data.selectedKeymsgList.findIndex((item2, idx2) => 
    	item1.keymsgId === item2.keymsgId) === idx1);
        
this.data.selectedList = result;

findIndex() 함수는 콜백함수에 정의한 조건이 true인 항목의 index를 리턴해준다.

var result = arr.filter(function(item1, idx1){
    return arr.findIndex(function(item2, idx2){
        return item1.id == item2.id
    }) == idx2;
});

 

[REFERENCE]

 

[유용한 자료]

[Vue.js] JSFiddle 웹사이트에서 코드 작성 및 실행 결과 확인

 

[Vue.js] JSFiddle 웹사이트에서 코드 작성 및 실행 결과 확인

Vue.js 개발 환경을 PC에 설정하는 방법도 있으나, 웹사이트에서 바로 코드 작성 및 실행결과를 확인할 수 있는 사이트가 있어서 소개합니다. 개발자들이라면 누구나 아는 바로 그 jsfiddle 사이트입

playground.naragara.com

 

 

 

Leave a Reply

error: Content is protected !!