1. 변경점

  • AngularJS에서 Angular Framework로 변경되면서 es6 문법을 사용한다.
  • Angular CLI를 이용하여 손쉽게 프로젝트 구조를 짤 수 있다.
  • $scope의 계층이 컴포넌트 별로 분리되면서 성능에 대한 최적화가 이루어졌다.
  • TypeScript를 이용하여 런타임 오류를 줄이며, 개발 시 실시간 타입체크가 가능하다
  • @Component와 같은 메타데이터를 이용하여 손쉽게 인스턴스를 생성 할 수 있다.
  • 의존성 주입을 통한 서비스 계층과 UI 계층의 분리가 더 강화되었다.

Angular의 가장 큰 변경점은 서비스 로직과 뷰의 명확한 분리, 그리고 성능의 최적화 인듯하다

2. Angular 기본 기능 사용하기

예제 코드를 이해하려면 기본적으로 TypeScript를 알아야 합니다.

뷰 만들기

셀렉터, 템플릿, 스타일 속성을 지정하여 뷰를 만들 수 있으며, 클래스를 통하여
생명주기를 관리 할 수 있고, 데이터를 바인딩하여 뷰에 전달 할 수 있다.

// 뷰 컴포넌트
@Component({
  selector: 'app-content',
  templateUrl: './content.component.html',
  styleUrls: ['./content.component.css']
})
export class ContentComponent implements OnInit {

  todoList: Array<DataType>;

  constructor(private todoListService: TodoListService) {
    this.todoListService = todoListService;
  }

  ngOnInit() {
    this.todoList = this.todoListService.getList();
  }

}

implements을 통하여 OnInit과 같은 생명주기 메서드를 사용 할 수 있다. 생성자 안에 프로바이더 인스턴스를 가져다가 사용 할 수 있다.


모듈 만들기

Angular 모듈을 만들 수 있다, 해당 모듈 안에 다른 모듈을 임포트 할 수 있으며 모듈에서 사용 할 컴포넌트를 선언 할 수 있고 , 프로바이더로서 다른 서비스를 선언하여 해당 모듈안에 선언된 컴포넌트에서 서비스 로직을 가져다 사용 할 수 있다.

// 모듈 인스턴스
@NgModule({
  declarations: [
    AppComponent,
    HeaderComponent,
    BottomComponent,
    ContentComponent,
    TodoDetailComponent,
    TodoRatingComponent
  ],
  imports: [
    BrowserModule, routing
  ],
  providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],
  bootstrap: [AppComponent]
})

export class AppModule { }

LocationStrategy와 같은 네비게이션 인스턴스를 선언하여 사용 할 수 있으며 Angular의 기본 전략은 LocationStrategy으로 설정되어 있다.


뷰에서 데이터 출력하기

컴포넌트와 인터페이스의 차이점은 컴포넌트는 상태를 가진다는 것이다. 즉 Angular에서 사용하는 컴포넌트들을 각각 상태값(클래스 멤버변수)를 가질 수 있다.
그리고 {{}}을 이용하여 해당 컴포넌트 템플릿에서 HTML 안에 직접 데이터를 바인딩 하여 사용 할 수 있다.

// content.component.html
<div *ngFor="let todo of todoList">
    <app-todo-detail [todo]="todo"></app-todo-detail>
</div>

// 뷰 컴포넌트
@Component({
  selector: 'app-content',
  templateUrl: './content.component.html',
  styleUrls: ['./content.component.css']
})

export class ContentComponent implements OnInit {

  todoList: Array<DataType>;

  constructor(private todoListService: TodoListService) {
    this.todoListService = todoListService;
  }

  ngOnInit() {
    this.todoList = this.todoListService.getList();
  }
}

위의 코드에서는 *ngFor(반복자 지시자)을 이용하여 HTML 엘리먼트를 생성하고 있으며, [todo]="todo"을 선언하여 하위 컴포넌트에 데이터를 전달 할 수 있다.

생성자의 todoListService: TodoListService 의존성 주입을 통하여 서비스 로직을 호출하고 있다


의존성 주입하기

스프링 프레임워크와 같이 의존성 주입을 통해서 뷰 컴포넌트에서 서비스 인스턴스를 사용 할 수 있다. 이를 통해서 명확한 뷰와 서비스 로직의 분리가 가능해 진다.

// 서비스 인스턴스
@Injectable({
  providedIn: 'root'
})
export class TodoListService {

  constructor() { }

  getList() {
    return data;
  }
}

// 뷰 컴포넌트 클래스의 생성자
constructor(private todoListService: TodoListService) {
    this.todoListService = todoListService;
}

providedIn을 통해서 의존성 주입의 범위를 지정 할 수 있다, root는 전역


상위에서 하위 컴포넌트로 데이터 전달하기

상위 컴포넌트에서 하위 컴포넌트로 전달하기는 위의 데이터 전달하기 편에 간략히 소개
되었던것 처럼 사용되며, 실제 전달 받은 하위 컴포넌트에서는 @Input()을 통하여 데이터를 사용 할 수 있다.

// 하위 컴포넌트로 데이터 전달
<app-todo-rating [rating]="todo.rating"></app-todo-rating>


// 하위 컴포넌트
@Component({
  selector: 'app-todo-rating',
  templateUrl: './todo-rating.component.html',
  styleUrls: ['./todo-rating.component.css']
})
export class TodoRatingComponent implements OnInit {
  @Input() rating: number;
  constructor() { }

  ngOnInit() {
  }
}

Angular는 양방향 데이터 바인딩이 가능하며, 실제로 이전의 AngularJS에서는 양방향 데이터 바인딩이 디폴트였다. 그러나 프레임워크로 업데이트 되면서 양방향 데이터 바인딩이 될 때마다 랜더링이 호출 되는 성능 이슈를 해결하기 위해서 단방향 데이터 바인딩이 기본으로 변경 되었다. 결국 상위에서 하위 컴포넌트로 데이터를 흐르게 하는것이 리액트와 마찬가지로 더 좋은 설계 방향이다


네비게이션을 통한 선택적 랜더링하기

Angular는 SPA을 기반으로 하는 프레임워크이기에, 클라이언트 렌더링을 수행 하는데,
조건에 따라 화면을 렌더링 하게 할 수 있다.

// 모듈의 프로바이더에 추가
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]

// url에 따른 랜더링 설정값이 있는 인스턴스 생성
const routeInfo: Routes = [
  {path: '', component: ContentComponent},
  {path: 'test', component: HeaderComponent}
];
export const routing = RouterModule.forRoot(routeInfo);

// 모듈의 임포트 프로퍼티에 라우터 설정 인스턴스 삽입
  imports: [
    BrowserModule, routing
  ],

// 조건에 따른 렌더링을 수행 할 컴포넌트의 html 템플릿에 추가
<a [routerLink]="['/']">Home</a>
<a [routerLink]="['/test']">header</a>
<router-outlet></router-outlet>