본문 바로가기
프로그래밍/Angular

앵귤러 기초(Angular basic) 17.getter, setter(게터, 세터)

by 신나요 2022. 1. 26.

앵귤러 애플리케이션을 만들때 자주 쓰이는 getter, setter에 대해 알아보겠습니다.

그리고 getter, setter를 활용한 필터 기능을 만들어 보도록 하겠습니다.

 

이번 포스트에선 아래의 내용을 다루고 있습니다.

  1. 타입스크립트에서 속성을 정의하는 두 가지 방법
  2. 앵귤러에서 getter, setter 사용하기
  3. 테이블 필터링 처리 만들기

 


타입스크립트에서 속성을 정의하는 두 가지 방법

자바스크립트와 TypeScript에서는 클래스에 속성(프로퍼티)을 정의하는 두 가지 방법이 있습니다.

번째는 지금까지 해왔던 것처럼 프로퍼티에 대해 간단히 변수를 선언 할 있습니다.

우리는 변수를 통해서 직접 값을 가져오거나 값을 변경 할 있습니다.

 

번째는 프로퍼티를 정의하는 또 다른 방법은 자바스크립트 getter 및 setter를 사용하는 것입니다.

getter와 setter를 만들 때, 우리는 getter와 setter에 의해 관리되는 값을 저장하기 위해 backing variable이라고 불리는 프라이빗 변수(위 예의 _score)를 정의해야 합니다.

private 키워드를 사용하여 이 백업 변수가 private 변수임과 동시에 getter와 setter에 의해서만 관리되어야 함을 나타냅니다.

이 변수를 private로 인식하는 데 도움이 되도록 관례적으로 앞에 밑줄( _ )을 붙입니다.

 

여기서 기억할 점은 프로퍼티에 대해 단순한 변수 대신 getter와 setter를 사용함으로써 우리는 get 또는 set을 할때 필요한 작업을 처리할 수 있는 코드를 작성할 수 있다는 것입니다.

 

getter setter 관리되는 값을 참조 할때도 기존의 방식과 같습니다.

위의 코드는 95score를 설정하고, 설정한 값을 가져와서 콘솔에 기록합니다.

처리를 할때 getter setter 한번씩 호출 될 것 입니다.


앵귤러에서 getter, setter 사용하기

getter, setter 알아봤으니 앵귤러에서 사용해 보도록 하겠습니다.

아래 화면은 아직 필터를 입력해도 필터의 내용에 따라 테이블의 내용이 변경되고 있지 않습니다.

필터의 Input값은 filterText 양방향 바인딩 되어있고, 다시 필터값을 h4 출력만 하고 있네요.

getter, setter 이용하면 filterText 값이 바뀌는 순간 필터링 처리를 있을 같습니다.

그럼 필터 값을 입력함과 동시에 영화 이름을 필터링하도록 바꿔보겠습니다.

 

영화 이름 필터링 코딩 계획은 이렇습니다.

1.filterText  getter, setter 바꿔준다.

2.set 처리시 입력받은 문자열로 필터링된 영화 정보 배열을 만든다.

3.필터링된 영화 정보 배열을 테이블에 연동시킨다.

 

하나씩 적용해 보도록 하겠습니다.

 getter, setter 만들기

filterText변수를 삭제하고 대신 게터와 세터를 구축합니다.

먼저, 우리는 getter와 setter에 의해 관리되는 값을 보유하기 위해 private 백업 변수 _filterText 를 선언하였습니다.

 

getter는 get keyword로 시작하고,  getter의 본문은 속성 값을 반환하기 전에 처리하는 코드를 포함할 수 있습니다.

그런 다음 getter는 처리된 값을 반환합니다.

get에서 filterText를 처리할 필요가 없기 때문에, backing 변수의 값을 반환하겠습니다.

 

setter set 키워드로 시작합니다.

세터는 연결된 프로퍼티에 값이 할당될 때마다 실행되므로, 영화 리스트를 필터링하는 등 속성이 변경되었을 때 세터의 본체를 사용하여 작업을 수행할 수 있습니다.

지금은 매개변수로 할당된 값(v)을 private 백업 변수 _filterText로 넣어주겠습니다.

나중에 필터 처리도 이곳에서 넣을 생각입니다.

값이 변경 됐을때 제대로 작동하는지 확인하기 위해서 로그를 출력해 봅시다.

filterText의 값이 할당될 때, setter가 호출되어 로그 출력이 제대로 이뤄지는 걸 확인했습니다.

 

테이블 필터링 처리 만들기

이제 필터 처리를 넣어봅시다.

먼저 필요한 필터 결과값을 담을 배열이 필요합니다.

필터 값을 담을 filterdMovies 선언하였습니다.

기존 movies배열을 이용하지 않는 이유는 movies배열을 필터링 해버리면 원래 데이터가 손실되고 데이터 소스(데이터베이스 )에서 다시 가져오지 않으면 데이터를 복구할 방법이 없기 때문입니다.

 

그리고 filterdMovies배열을 템플릿에서 테이블을 출력할 수 있도록 바인딩 해 놓았습니다.

이제 filterdMovies프로퍼티를 통해 테이블이 그려지겠네요.

 

setter수정입니다.

setter에서는 필터링 처리를 하는 perfomefilter 호출한 필터 배열 값을 filterMovies배열에 넣어주도록 처리 하였습니다.

 

마지막으로 perfomeFilter메서드를 만들겠습니다.

perfomeFilter메서드는 filterBy라는 매개변수를 받고, 값으로 배열의 값을 필터 movie타입의 배열을 리턴하는 역할을 합니다.

filterBy 비교할 대상은 영화명(movie.name)인데 비교전에 모두 소문자로 바뀐 비교하였습니다.

배열의 filter메서드를 이용하여 필터 처리를 하였습니다.

filter메서드의 매개변수로서 필터 기준을 판단하는 함수를 전달하여야 합니다.

화살표 함수로 필터 기준의 판단하는 함수를 전달하였습니다.

화살표 함수에서는 movie객체의 name프로퍼티를 소문자로 바꾼 filterBy스트링이 포함되었다면 true 리턴하게 됩니다.

화살표 함수를 쓰는 열의 filter메서드에서는 movies배열을 루프를 돌며 true 돌아온 객체의 값만 배열로 리턴 해줍니다.

 

컴포넌트의 전체 소스는 아래와 같습니다.

import { Component, OnInit } from "@angular/core";
import { movie } from "./movie.model";

@Component({
    selector: 'app-movies',
    templateUrl: './movie-list.component.html',
    styleUrls: ['./movie-list.component.scss']
})
export class MovieListComponent implements OnInit{
    subTitle: string = '영화리스트';
    imgWidth: number = 55;
    imgMargin: number = 2;
    isImgDisplayed: boolean = false; 

    private _filterText = '';
    get filterText(): string {
        return this._filterText;
    }
    set filterText(v : string) {
        this._filterText = v;
        this.filteredMovies = this.performFilter(v);
    }
    
    filteredMovies: movie[] = [];
    movies: movie[] = [
        {
            "movieId": 1,
            "name": "matrix4",
            "director": "Lana Wachowski",
            "releaseDate": "2022-01-10",
            "actor": "Keanu Reeves",
            "rate": 4,
            "price":2.4,
            "imageUrl": "assets/images/Matrix4.jpeg",
        },
        {
            "movieId": 2,
            "name": "spider-man: No Way Home",
            "director": "Jon Watts",
            "releaseDate": "2022-01-17",
            "actor": "tom holland",
            "rate": 3,
            "price":9.42,
            "imageUrl": "assets/images/spiderman.jpg",
        }
    ];
    
    public ngOnInit(): void {
        console.log('앵귤러 라이프사이클: ngOnInit()');
    }

    public toggleImg(): void {
        this.isImgDisplayed = !this.isImgDisplayed;
    }

    public performFilter(filterBy: string): movie[] {
        filterBy = filterBy.toLocaleLowerCase();
        return this.movies.filter((movie: movie)=>{
            return movie.name.toLocaleLowerCase().includes(filterBy);
        });
    }

}

템플릿 소스입니다.

<div class="card">
  <div class="card-header">{{subTitle}}</div>
  <div class="card-body">
    <div class="row">
      <div class="col-md-2">필터:</div>
      <div class="col-md-4">
        <input [(ngModel)]="filterText" type="text" />
      </div>
    </div>
    <div class="row">
      <div class="col-md-6">
        <h4>필터 : {{filterText}}</h4>
      </div>
    </div>
    <div class="table-responsive">
      <table class="table" *ngIf="movies.length">
        <thead>
          <tr>
            <th>
              <button (click)="toggleImg()" class="btn-primary">
                {{ isImgDisplayed ? "이미지숨기기" : "이미지보이기" }}
              </button>
            </th>
            <th>영화</th>
            <th>감독</th>
            <th>개봉일</th>
            <th>주연</th>
            <th>평점</th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let movie of filteredMovies">
            <td>
              <img *ngIf="isImgDisplayed"
                  [src]="movie.imageUrl" 
                  [title]="movie.name | uppercase"
                  [style.width.px]="imgWidth"
                  [style.margin.px]="imgMargin"
                  >
            </td>
            <td>{{ movie.name | convert:'-':' '}}</td>
            <!-- 1. 대문자 -->
            <td>{{ movie.director | uppercase }}</td> 
            <!-- 2. 날자 포멧 -->
            <td>{{ movie.releaseDate | date:'MMM d, y' }}</td>
            <!-- 3. 소문자 -->
            <td>{{ movie.actor | lowercase }}</td>
            <!-- 4. 소숫점 한자리 까지 -->
            <td>{{ movie.rate | number: '1.1'}}
        </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</div>

 

이제 모두 끝났습니다.

브라우저에서 결과를 확인 해 보겠습니다.

 

 

필터가 작동하네요.🎉

이것으로 getter, setter 대해 알아보았고 filter기능도 구현해 보았습니다.

다음 포스트는 중첩된 컴포넌트에 대해 알아보도록 하겠습니다.

댓글