문제상황


앵귤러2 에서 일반적으로 자식 컴포넌트가 부모 컴포넌트에게 데이터를 전달하는 방법은 Output 과 EventEmitter 를 이용한 방법을, 부모 컴포넌트가 자식 컴포넌트에게 데이터를 전달하는 방법은 자식컴포넌트 선택자에 단지 속성으로 변수를 넘긴 후 Input 을 사용하여 받는다. 즉 뷰템플릿이 데이터 전송의 매체가 되는 셈.


하지만 문제가 복잡해져 서로 거리가 먼 컴포넌트 간의 통신을 해야하는 경우가 생김.

마치 나와 큰아빠와 큰아버지와 사촌동생 간에 동시에 데이터를 공유해야 하는 상황이라면?





1. 매개자 역할의 서비스 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
 
@Injectable()
export class DataService {
  private subject = new Subject<any>();
 
  constructor() { }
 
  sendData(data){
    this.subject.next(data);
    console.log("sendData() data : " , data);
  }
 
  getData(){
    return this.subject.asObservable();
  }
}
 
cs


rxjs 의 Subject 객체는 Observable 인 동시에 Observer. 한 컴포넌트에서 서비스의 sendData() 를 호출하여 데이터를 Subject 의 next 메서드를 통해서 데이터 스트림에 밀어넣는다.


다른 getData() 메서드는 데이터를 받을 컴포넌트에서 호출하여 데이터스트림에서 Observable 객체를 받은 후, 데이터 전송이 완료되었을 때 구독(subscribe) 할 것이다.




2. 데이터를 보낼 컴포넌트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import { Component, OnInit, OnDestroy } from '@angular/core';
import { PostService } from '../../services/post/post.service';
import { DataService } from '../../services/data.service';
 
import { Post } from '../../models/post';
import { ActivatedRoute, Params } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
 
@Component({
  selector: 'app-post',
  templateUrl: './post.component.html',
  styleUrls: ['./post.component.css']
})
export class PostComponent implements OnInit, OnDestroy {
  private subscription: Subscription;
  post: Post;
  postNo: number;
 
  constructor(private activatedRouter: ActivatedRoute, private postService: PostService, private dataService: DataService) {
    this.subscription = activatedRouter.params.subscribe((params: Params) => {
      this.postNo = params['postNo'];
      this.postService.getPost(this.postNo)
      .subscribe(
        (post) => {
          this.post = post;
          dataService.sendData(this.post);
        },
        (error) => {
          console.log(error);
        }
      );
    });
  }
 
  ngOnInit() {
    
  }
 
  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
 
cs


좀 복잡해 보이지만 핵심은 단지 위에서 생성한 service 의 sendData() 를 호출하는 것. 참고로 subscription 객체는 구독했던 객체를 파괴하기 위해 사용. ngOnDestroy() 라이프사이클에서 저장했던 subscription 을 unsubscribe 해주면 된다.


DataService 를 주입받고, 보내고자 하는 데이터를 dataService.sendData() 로 호출하여 넘겨준다.




3. 데이터를 받을 컴포넌트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { Component, OnInit, OnDestroy } from '@angular/core';
import { DataService } from '../../services/data.service';
 
import { Subscription } from 'rxjs/Subscription';
 
@Component({
  selector: 'app-banner',
  templateUrl: './banner.component.html',
  styleUrls: ['./banner.component.css']
})
export class BannerComponent implements OnInit, OnDestroy {
  title = 'Blog';
  regDate = '';
  categoryName = '';
 
  subscription: Subscription;
 
  constructor(private dataService: DataService) {
    console.log("banner 컴포넌트 생성!");
    
    this.subscription = dataService.getData().subscribe(data => {
      console.log("banner subscription : " , data);
      this.title = data.title;
      this.regDate = data.regTime;
      this.categoryName = data.categoryId;
    })
 
  }
 
  ngOnInit() {
  }
 
  ngOnDestroy(){
    this.subscription.unsubscribe();
  }
 
}
 
cs


데이터를 수신할 컴포넌트에서도 마찬가지로 Subscription 객체를 이용해 구독한 객체를 파괴시켜주어야 하며, DataService 를 주입받고, 이 DataService 의 getData() 메서드를 호출하여 Observable 객체를 받는다. 이를 subscribe 메서드를 사용하여 데이터가 전달되면 수행할 작업을 진행하면 된다.




블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

문제상황


개인용 포폴로 새로운 웹사이트를 구축하기 시작하였습니다.

스택은 Angular2 + Node.js + Express + Mysql 일명 짝퉁 MEAN 스택이죠.

일단 AWS EC2 프리티어를 사용중에 있기 때문에 EC2 인스턴스 1개를 가지고 여러개의 서비스를 포트폴리오로 보여주고자 하였음.


그래서 EC2 서버에 nginx 리버스 프록시 서버를 올려서 특정 path 으로 들어오면 각각의 서비스를 보여주는 식으로.


예를 들면 

abc.com/aaa => 8080포트로 포워딩하여 aaa 라는 이름의 JSP 서비스로 연결!

abc.com/bbb => 3000포트로 포워딩하여 bbb 라는 이름의 node 서비스로 연결!

abc.com/ccc => 등등...


하지만 abc.com/bbb 에서 node 웹서버가 리스닝하는 3000포트로 날려주고, 노드서버는 앵귤러 페이지를 첫페이지로 뿌려줘야 하는데 문제가 생겼습니다.

앵귤러 프로젝트의 메인인 index.html은 나오지만, (기본 자식컴포넌트인) <app-root></app-root> 내용이 비어있는 것.


문제는 번들링된 파일들의 경로 문제였음.

아마도 리눅스 파일시스템 자원에 접근하는 경로가 기본적으로 /blog를 포함하지 않기 때문인 것.




1. base-href 와 deploy-url 에 대한 고민



위에 보면 <base href="/"> 태그가 존재함.

이부분은 아마 앵귤러 가상 url 라우팅에서 기본경로로 잡는 부분을 지정해주는 것 같음.


앵귤러 프로젝트를 빌드할 때


ng build -prod --base-href /test


로 빌드하면 위의 <base href="/test"> 로 빌드가 됨.


반면 deploy-url 은 정적 자원경로 앞에 prefix 형식으로 경로를 추가해 주는 것.





2. ng build -prod --base-href /blog --deploy-url /blog




ng build -prod --base-href /blog --deploy-url /blog 로 빌드한 경우 base href 속성과 정적 자원에 대한 경로 모두 /blog 가 붙으며, 정상적으로 모든 파일이 로드됨.





3. ng build -prod --base-href /blog



ng build -prod --base-href /blog 로 빌드한 경우 base href 속성이 /blog로 채워지지만, 정적 자원들은 그렇지 않아 번들링된 파일들이 로드되지 않음.





4. ng build -prod --deploy-url /blog



ng build -prod --deploy-url /blog 로 빌드한 경우 base href 의 속성은 채워지지 않았지만 정적 자원에 대한 경로는 제대로 잡힘. 현재 상황에서는 --deploy-url 옵션만 주는 것이 맞는 방법으로 보임.


하지만!


자세히 보니 url 에서 /blog 경로가 자동으로 제거된 것이 보임.

브라우저 특성이 아니라 자동으로 /blog 경로가 제거되며, 따라서 새로고침시에 기본경로로 접속하게 되어버림.


즉, base-href 옵션은 앵귤러 컴포넌트 라우팅에 사용할 기본 경로를 잡아주는 것임을 알 수 있다.


제대로 사용하기 위해서는 결국 ng build -prod --base-href /blog --deploy-url /blog 로 빌드해야 함





5. 또 다른 방법 APP_BASE_HREF 모듈 사용


위에서 나타난 url 상의 path 자동제거 현상을 잡아주는 모듈이 있음


import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { APP_BASE_HREF } from '@angular/common';

import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { HomeComponent } from './components/home/home.component';


@NgModule({
declarations: [
AppComponent,
HomeComponent
],
imports: [
BrowserModule,
RouterModule.forRoot([
{
path: 'home',
component: HomeComponent
}
])
],
providers: [{provide: APP_BASE_HREF, useValue: '/blog'}],
bootstrap: [AppComponent]
})


export class AppModule { }



3번 라인에서 APP_BASE_HREF 모듈을 가져오고, providers 에 userValue 값으로 원하는 경로를 설정.


이제 ng build -prod --deploy-url 옵션만 주어도 url 에서 경로가 지워지지 않는다.

(하지만 index.html 의 base href 속성은 왜 /blog 가 아닌 / 일까...)





블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,