본문 바로가기

Tech/Angular

[Angular] 양방향 바인딩 (2-way binding)

반응형

이미지 출처 : Pixabay

지난번에 구성한 레이아웃에 이어 Departments 페이지에 대한 레이아웃도 비슷하게 구성하고 진행하겠습니다.

우선 departments.component.ts 파일에 Departments 리스트를 다음과 같이 import 해 줍니다.

//departments.component.ts
import { Component, OnInit } from '@angular/core';
import { Department } from './department';
import { DEPARTMENTS } from './departmentList';

@Component({
  selector: 'app-departments',
  templateUrl: './departments.component.html',
  styleUrls: ['./departments.component.css']
})
export class DepartmentsComponent implements OnInit {
  departments: Department[] = DEPARTMENTS;
  selectedDepartment: Department;

  constructor() { }

  ngOnInit() {
  }

  onSelect(department: Department): void {
    this.selectedDepartment = department;
  }

}

css 파일에 다음과 같이 div-left와 div-right 속성을 추가합니다.

/* departments.component.css */
div.left {
  width: 50%;
  float: left;
  box-sizing: border-box;
  padding: 5px 5px 5px 5px;
}

div.right {
  width: 50%;
  float: right;
  box-sizing: border-box;
  padding: 5px 5px 5px 5px;
}

그리고 departments.component.html 파일을 다음과 같이 수정합니다.

<!-- departments.component.html -->
<h2>Departments</h2>
<div class="left">
  <div class="list-group" *ngFor="let department of departments" (click)="onSelect(department)">
    <a class="list-group-item list-group-item-action">{{department.id}} | {{department.name}}</a>
  </div>
</div>
<div class="right" *ngIf="selectedDepartment">
  <h2>{{selectedDepartment.name}}'s Detail</h2>
  <form>
    <div class="form-group row">
      <label for="id" class="col-sm-2 col-form-label">ID</label>
      <div class="col-sm-9">
        <input type="text" readonly class="form-control-plaintext" id="id" #id value="{{selectedDepartment.id}}">
      </div>
    </div>
    <div class="form-group row">
      <label for="name" class="col-sm-2 col-form-label">Department</label>
      <div class="col-sm-9">
        <input type="text" class="form-control" id="name" #name value="{{selectedDepartment.name}}">
      </div>
    </div>
    <div align="right">
      <button type="submit" class="btn btn-primary">Submit</button>
    </div>
  </form>
</div>

여기까지 진행했다면 다음과 같은 화면을 볼 수 있습니다.

localhost:4200/departments

이렇게 작성된 화면에서 데이터는 단방향으로 바인딩됩니다.

Reference : https://angular.io/tutorial/toh-pt3#show-the-herodetailcomponent

 

Angular

 

angular.io

이때까지 데이터를 웹 페이지 상에 전시할 때에는 interpolation 바인딩을 사용하였습니다.

<input type="text" class="form-control" id="deptID" #id value="{{selectedDepartment.name}}">

이렇게 하면 컴포넌트의 상태를 그대로 DOM에 반영하게 됩니다.

 

위를 대괄호를 사용한 프로퍼티 바인딩 방식으로 변경하면 다음과 같습니다.

<input type="text" class="form-control" id="deptID" #name [value]="selectedDepartment.name">

 

그리고 마지막으로 프로퍼티 바인딩과 소괄호를 사용한 (onClick)= .. 과 같은 이벤트 바인딩을 동시에 사용하면 양방향 바인딩이 가능해집니다.

이 때 ngModel 지시자를 사용하면 되는데, 프로퍼티 바인딩때 사용하는 대괄호 안에 이벤트 바인딩시 사용하는 소괄호를 넣으면 됩니다.

이를 Angular 공식 사이트에서는 'Banana in the box'라고 설명합니다.

banana = (), box = [], banana in the box = [()] ㅋㅋㅋ

<input [(ngModel)]="selectedDepartment.name" class="form-control" id="name">

이렇게 넣으면 동작하지 않는데, 그 이유는 다름아닌 저 input이 form group 안에 위치해 있기 때문입니다.

이것때문에 한시간 정도를 날려먹었는데, 조금만 생각해보면 당연한 것임을 깨달았습니다..

결과적으로 departments.component.html을 다음과 같이 수정해줍니다. (form group을 삭제합니다.)

<!-- departments.component.html -->
<h2>Departments</h2>
<div class="left">
  <div class="list-group" *ngFor="let department of departments" (click)="onSelect(department)">
    <a class="list-group-item list-group-item-action">{{department.id}} | {{department.name}}</a>
  </div>
</div>
<div class="right" *ngIf="selectedDepartment">
  <h2>{{selectedDepartment.name}}'s Detail</h2>
    <div class="form-group row">
      <label for="id" class="col-sm-2 col-form-label">ID</label>
      <div class="col-sm-9">
        <input type="text" readonly class="form-control-plaintext" id="id" #id value="{{selectedDepartment.id}}">
      </div>
    </div>
    <div class="form-group row">
      <label for="name" class="col-sm-2 col-form-label">Department</label>
      <div class="col-sm-9">
        <input [(ngModel)]="selectedDepartment.name" class="form-control" id="name">
      </div>
    </div>
</div>

그러면 다음과 같이 동작합니다 : (IT Department의 이름을 IT에서 IT Ops로 수정하였습니다.)

IT > IT Ops

여기서 수정된 부분은 .ts 파일을 수정한 것과 같이 실시간으로 적용됩니다.

localhost:4200/employees

 

반응형