angular 5 빌드 후에 docker nginx 서버에 적용하기

angular 빌드하기

$ ng build

빌드후에 /dist/퐬더에 생성된 파일을 nginx 서버가 적용 된 곳에 파일을 복사합니다.

localhost/까지는 잘 접속이 되는 것을 확인할 수 있습니다. 그러나, angular 의 RoutingModule을 사용한 주소 뒤에 localhost/some/some2/ 와 같은 주소는 접속이 되지 않습니다.

이를 해결하기 위해서는 아래와 같이 nginx/conf.d/default.conf 파일을 수정해 주어야 합니다.

일단 저는 nginx/1.13.5버전을 사용하고 docker 를 통해서 실행해 놓은 상태입니다.

docker exec -it some-nginx /bin/bash

명령어를 통해서 docker 내부에 접속을 한후에 vim 으로 설정을 변경합니다.

: vim이 실행이 되지않을때에는 apt-get update를 진행후 apt-get install vim를 통해 설치를 하기 바랍니다.

/etc/nginx/conf.d/default.conf 파일을 수정 합니다.

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri$args $uri$args/ $uri $uri/ /index.html =404;
    }
...

이대로 접속이 되면 만세!

반응형

Angular 라우팅 적용하기

  • @angular/core = “^5.0.1”

라우팅 기능을 통해서 페이지 이동을 구현하려고 하는데 생각보다 잘 안되서 무니서로 정리해 놓으려고 합니다.
Reference 문서를 살펴보면 가능은 하겠지만, 문서를 보면서 실수한 점에 대해서 기록

install routing module

$ ng generate module app-routing --flat --module=app

설치옵션

–flat : /src/app/ 폴더에 component 를 만들 때처럼 폴더를 생성하지 않고 파일을 생성합니다.
–module=app : AppModule 에 자동으로 import 합니다.

app.module.ts에 자동으로 imports:항목에 추가가 되므로, 따로 app.module 을 설정하지 않아도 되는 장점이 있습니다. 앵귤러는 설정때문에 왔다갔다 하는게 너무 많아요.

app.component.html파일

<div class="container">
  <router-outlet></router-outlet>
</div>

<router-outlet></router-outlet>이 라우팅이 적용되는 위치 입니다. 저는 router-outlet 을 html에 입력을 하지 않아서 적용이 되지 않았습니다.
이 거 찾는데 한시간 걸림. 왜 안되는지!!! 슬프다.

app-routing.module.ts파일

import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';

import { SalesComponent} from './sales/sales.component';
import { NotfoundpageComponent } from './notfoundpage/notfoundpage.component';

const routes: Routes = [
  {path: 'sales/:id', component: SalesComponent},
  { path: '', redirectTo: '', pathMatch: 'full'},
  { path: '**', component: NotfoundpageComponent }
]

@NgModule({
  imports: [ RouterModule.forRoot(routes)],
  exports: [ RouterModule]
})
export class AppRoutingModule {
  constructor() {}
}
반응형

의속성 주입(Dependency Injection)

의속성 주입(Dependency Injection)은 Angular에서 가장 강력한 기능 중에 하나 입니다.

Angular 1.x 에서의 의존주입은 몇가지 제한 사항이 있었습니다.

내부캐시(Internal cache) : 종손성은 싱글톤 입니다. 라이프 사이클당 한번만 생성
네임스페이스 출동(Namespace collision) : 오직 한가지 유형만을 가질 수 있습니다.
단단한 결합(Tightly coupled) : Angular 1.x 프레임워크에 내장되어 있습니다.

의존성 삽입을 설명하기 위해 다음 예제를 사용합니다.
차를 만드는 클래스를 생성하겠습니다.
일반적인 방법으로 아래와 같습니다.

class Car {
  constructor() {
    this.engine = new Engine();
    this.tyres = Tyres.getInstance();
  }
}

이 방법은 괜찮습니다. 하지만, 우리는 엔진 생성자와 싱글 톤 타이어에서 엔진을 얻을 수 있습니다.
만약 우리가 MockEngine 을 생성자로 대체해서 코드를 테스트해야 한다면 새로운 코드를 작성해야 합니다.
테스트 할 수 잇는 코드를 만들면 우연히 재사용 가능한 코드를 빌드하게 됩니다. 이 코드르 더 재사용 가능하게 만드는 한가지 방법은 TypeScript 생성자를 사용하여 형식과 값을 전달하는 것입니다.
다음은 그 예입니다.

class Car {
  constructor(engine, tires) {
    this.engine = engine;
    this.tyres = tyres;
  }
}

우리는 생성자로부터 의존성 생성을 제거하고 모든 필요한 종속성을 기대학 위해 생성자 함수를 확장했습니다. 이제 코드의 구현을 하드 코딩하지 않았습니다.
우리는 생성자에 옮겼습니다.
새차를 만드려면 다음과 같이 실행하면 됩니다.

var car = new Car(
  new Engine(),
  new Tyres()
);

코드를 테스트 할 필요가 있다면 모의 의존성을 보낼 수 있습니다. 예를 들면 다음과 같습니다.

var car = new Car(
  new MockEngine(),
  new MockTyres()
);

이제, 이것이 의존성 주입입니다.
Angular2 에서의 의존성 주입은 다음과 같이 구성이 됩니다.

인젝터(Injector) : API 를 노출하는 객체입니다.
공급자(Provider) : 인젝터에게 종속성의 인스턴스를 만드는 방법을 알려줍니다.
종속성(Dependency) : 객체를 생성해야 하는 유형

Angular2 에서는 동일한 객체를 만드려면 다음과 같이 정의합니다.

import { Injector } from 'angular2/core';

var injector = Injector.resolveAndCreate([
  Car,
  Engine,
  Tyres
]);

var car = injector.get(Car);

Angular2 에서 import하는 Injector는 Injector.resolveAndCreate()를 생성하는데 도움을 주는 API 를 확장하는 팩토리 함수이며 이는 제공자의 목록을 가져옵니다.

TypeScript 에서는 다음과 같이 Car 클래스를 정의합니다.

class Car {
  constructor(engine: Engine, tires: Tires, doors: Doors) {
    ...
  }
}

이 방법으로 의존성 주입을 생성함으로 이름 충돌 문제를 제거 할 수 있습니다.이 구조화 된 형식은 Angular 1.x 의 모든 문제를 제거 합니다.

반응형

메타데이터, 데이터 바인딩, 서비스

메타데이터 클래스를 처리하는 방법을 Angular에게 알려줍니다. app.component.ts파일에서 클래스를 만들었습니다.
데코레이터(Decorator)는 함수(function)이며, 데코레이터는 무엇을 할지 클래스에 알려줍니다.

@Component({
  selector: 'my-component',
  templateUrl: 'app/app.component.html',
  directives: [HighlightDirective]
})
export class MyComponent {
    public name: String;
    public today: Date;

    constructor() {
        this.name = 'Angular 2 Rocks !';
        this.today = new Date();       
    }
    sayMyName() {
        alert (this.name);
    }
}

여기서 @Component는 데코레이터 입니다. 이 함수에서는 클래스를 구성하는 매개변수를 전달합니다. 데코레이터에 전달하는 파라미터들은 다음과 같습니다.

selector : Angular 에서 바인딩할수 있는 CSS 선택
templateUrl : 템플릿 파일의 위치
directives : 템플릿에 바인딩 할 수 있는 디렉티브 배열
providers : 서비스를 의해 의존관계 주입자들(dependency injection providers)의 배열

데이터 바인딩 방법

데이터바인딩을 사용하면 템플릿의 데이터 구성요소에 바인딩 할 수 있습니다. 데이터 바인딩 형식에는 다음 네가지가 있습니다.

  1. DOM에 다가
  2. DOM에서 직접
  3. 1,2 번 둘다
  4. 속성 및 이벤트 바인딩을 사용하여 속성과 이벤트 바인딩을 결합한 양방향 데이터 바인딩 ngModel

단방향 바인딩

다음 코드를 한번 봅시다

<h1>{{today | date:"fullDate"}}</h1>

<div>
    <button (click)="sayMyName()" myHighlight>Do Something Special</button>
</div>

app.component.html파일 안에서 {{today}}app.component.ts 파일의 today 프로퍼티를 단방향 바인딩을 통해 바인딩하고 있습니다. sayMyName() 함수는 click 이벤트 핸들러에 바인딩 됩니다.

양방향 바인딩

양방향 바인딩을 시연하려면 app.component.html 파일에 <div> 태그를 포함하도록 변경하세요.

<div>
    <input [(ngModel)]="task">
</div>
<div>
    {{task}}
</div>

app.component.ts 파일에서는 아래와 같이 비슷하게 변경해 줍니다.

export class MyComponent {
    public name: String;
    public today: Date;
    public task: string;

    constructor() {
        this.name = 'Angular 2 Rocks !';
        this.today = new Date();
        this.task = '';
    }
    sayMyName() {
        alert (this.name);
    }
}

여기서는 task 프로퍼티에 바인딩했습니다. 사용자가 입력 할 때 입력 내용이 페이지에 나타납니다.

서비스 만들기

Angular2의 서비스는 정의 된 함수가 있는 클래스를 말합니다.무엇이든 서비스가 될 수 있습니다.
JS 파일에 저장된 작업 목록을 읽는 서비스를 작성해 보겠습니다.

/app폴더에 task.service.ts라는 파일을 만들고 다음 파일 추가해 보겠습니다.

import {Injectable} from 'angular2/core';

@Injectable()

export class TaskService {
}

Angular Injectable함수를 포함하고 이 함수를 @Injectable() 데코레이터에 적용했습니다.
TypeScript는 @Injectable 데코레이터를 보고 Angular가 이 서비스에 다른 종속성 주입을 하는데 필요한 메타 데이터를 방출합니다.

작업을 위한 모델을 만들어 보겠습니다.
/app폴더에 tasks.ts라는 새 파일을 만듭니다. 이 파일에서 우리는 다음과 같이 작업을 위한 모델을 생성할 것입니다.

export class Task {
  id: number;
  name: string;
}

JavaScript 배열을 사용하여 새 파일을 만듭니다. 이 파일은 sample.tasks.ts로 다음 내용을 추가 합니다.

import {Task} from './tasks';
export var TASKS: Task[] = [
    {"id": 11, "name": "Buy Bread"},
    {"id": 12, "name": "Buy Milk"},
    {"id": 13, "name": "Buy Soap"}
];

모델을 이 파일에 포함시켰고 이 모델을 가진 배열을 ㅁ나들었습니다. 이 배열은 다음과 같이 TASKS로 내보내집니다.

task.service.ts파일에서 우리는 이 클래스를 포함하고 GET 메소드를 생성할 것입니다. 서비스 파일의 내용을 다음 코드로 바꿉니다.

import {TASKS} from './sample.tasks';
import {Injectable} from 'angular2/core';

@Injectable()

export class TaskService {
  getTasks() {
    return TASKS;
  }
}

모델로 서비스와 데이터를 생성했습니다. 이제 템플릿과 구성 요소를 수정해야 합니다. app.component.ts 파일을 다음과 일치하도록 수정하세요.

import {Component} from 'angular2/core';
import {HighlightDirective} from './highlight.directive';
import {TaskService} from './task.service';
import {Task} from './tasks';

@Component({
  selector: 'my-component',
  templateUrl: 'app/app.component.html',
  directives: [HighlightDirective],
  providers: [TaskService]

})
export class MyComponent {
    public name: String;
    public today: Date;
    public task: String;
    public taskList: Task[];



    constructor(private _taskService: TaskService) {
        this.name = 'Angular 2 Rocks !';
        this.today = new Date();       
        this.task = '';
        this.taskList = this._taskService.getTasks();

    }
    sayMyName() {
        alert (this.name);
    }
}

service 와 tasks 를 포함 시켰습니다.

import {TaskService} from './task.service';
import {Task} from './tasks';

service 를 가능하게 하려면 공급자가 가능해야 합니다. 그래서 @Component 데코레이터에 다음 코드를 넣었습니다.

providers: [TaskService]

service 가 컴포넌트에 노출이 됩니다. taskList를 포함할 배열을 생성하고 Task 유형으로 만듭니다.

export class MyComponent {
    public name: String;
    public today: Date;
    public task: String;
    public taskList: Task[];

    constructor(private _taskService: TaskService) {
        this.name = 'Angular 2 Rocks !';
        this.today = new Date();       
        this.task = '';
        this.taskList = this._taskService.getTasks();

    }
    sayMyName() {
        alert (this.name);
    }
}

생성자에 service에 연결하여 개인 변수에 할당하는 정의가 포함되어 있습니다. 밑줄은 데이터가 외부로 전달되고 있음을 빠르게 확인 할 수 있도록 하기위해 사용됩니다.
this._taskSerivce.getTasks()메소드를 사용하면 서비스 파일에 작업을 가져올 수 있습니다.

app.component.html파일에 다음을추가합니다.

<div>
    <ul>
        <li *ngFor="#item of taskList">{{item.name}}</li>
    </ul>
</div>

*ngFor 다이렉티브를 사용하면 taskList배열을 신속하게 반복할 수 있습니다.

반응형

Angular2 컴포넌트, 디렉티브, 템플릿

이전 코드를 복제하기

Angular2 시작하기에서 Hello World 를 완료했습니다.

이전의 코드를 확장해서 구성요소, 모듈, 템플릿 작업을 해보도록 하겠습니다.

ng2-todolist 폴더를 만들고, 기존에 있던 코드들을 복사합니다.

 # cp -R ng2-helloworld ng2-todolist

package.json파일안에 "name"을 변경합니다.

"name": "ng2-todolist", 

index.html파일안에 title을 변경합니다.

<title>Angular 2 - My Todo List</title>

컴포넌트의 재사용

컴퐤넌트는 페이지에서 다른 요소를 만들고 정의하는 방법입니다. Angular 1에서는 디렉티브, 컨트롤러를 사용하여 컴포넌트 안에서 디렉티브을 찾도록 기능을 구현해야 했습니다.

app/app.component.ts파일을 수정해 보겠습니다.

import {Component} from 'angular2/core'

@Component({
  selector: 'my-component',
  template: '<div><button (click)="sayMyName()">Do Something Special</button></div>'
})
export class MyComponent {
    public name: String;
    constructor() {
        this.name = 'Angular 2 Rocks !';
    }
    sayMyName() {
        alert (this.name);
    }
}

class AppComponent 이름을 MyComponent 로 변경 하였기 때문에 index.html,main.ts 파일안의 내용을 변경해야 합니다.

<my-component>Loading...</my-component>

main.ts 파일 안에 다음으로 수정합니다.

import {bootstrap}    from 'angular2/platform/browser'
import {MyComponent} from './app.component'

bootstrap(MyComponent)

서버를 실행 시켜 봅니다. 버튼과 버튼을 눌렀을 경우에 경고창이 나오는 것을 확인할 수 있을것입니다.

 # npm start

Imgur

디렉티브 사용하기

app폴더에 highlight.directive.ts파일을 만들고 다음 내용을 추가 합니다.

import {Directive, ElementRef} from 'angular2/core';
@Directive({
    selector: '[myHighLight]'
})
export class HighlightDirective {
    constructor(el: ElementRef) {
       el.nativeElement.style.backgroundColor = 'orange';
    }
}

Directive : @directive 데코레이터를 위해 사용
ElementRef : DOM element 에 엑세스 할 수 있도록 허용합니다.

highlight.directive.ts파일을 다음과 같이 변경합니다.

import {Directive, ElementRef} from 'angular2/core';
@Directive({
    selector: '[myHighlight]',
     host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()'
  }
})
export class HighlightDirective {
    private _el:HTMLElement;
    constructor(el: ElementRef) { this._el = el.nativeElement; }
    onMouseEnter() { this._highlight("yellow"); }
    onMouseLeave() { this._highlight(null); }
    private _highlight(color: string) {
        this._el.style.backgroundColor = color;
    }
}

host : MouseEnter, MouseLeave에서 CSS 변경을 수행하기 위해 호출할 두가지 메소드가 포함되어 있습니다.

템플릿의 위력

Angular는 템플릿을 사용해서 컴포넌트 안에서 클라이언트가 보는 것을 관리합니다. 템플릿에는 보여지기 위한 HTML 코드가 포함되어 있습니다. <script> 태그는 제외 한 대부분 모든 HTML 태그들을 템플릿에서 사용할 수 있습니다.
<html>,<body>,<base>와 같은 태그들을 사용할수는 있지만 실제로 템플릿에는 실제로 적용되지 않고 무시됩니다.
컴포넌트에 템플릿을 추가 하려면 템플릿 테그를 제거하고 templateUrl이라는 테그를 사용합니다.

templateUrl : 템플릿의 경로를 말합니다.

import {Component} from 'angular2/core'
import {HighlightDirective} from './highlight.directive';

@Component({
  selector: 'my-component',
  templateUrl: 'app/app.component.html',
  directives: [HighlightDirective]
})
export class MyComponent {
    public name: String;
    constructor() {
        this.name = 'Angular 2 Rocks !';
    }
    sayMyName() {
        alert (this.name);
    }
}

npm start를 사용하고 있다면 백그라운드에서 코드변경이 자동으로 브라우저에 적용되는 것을 확인할 수 있습니다.

간단히 날짜를 적용해 보겠습니다.
public today:Date 을 추가하고 new Date()를 추가해 봅니다.

app.component.ts부분을 아래와 같이 수정해 봅니다.

export class MyComponent {
    public name: String;
    public today: Date;

    constructor() {
        this.name = 'Angular 2 Rocks !';
        this.today = new Date();       
    }
    sayMyName() {
        alert (this.name);
    }
}

이제 app.component.html파일을 만들고 날짜가 표기 되도록 만들어 봅니다.

<h1>{{today | date:"fullDate"}}</h1>
| 표시
| 표시는 앵귤러1의 필터를 대체하는 파이프입니다. 필터처럼 템플릿 출력 형식을 지정하는데 도움이 됩니다.
반응형

+ Recent posts