반응형

STS 메뉴 -> Help ->  Eclipse Marketplace -> "Angular" 로 검색


Angular IDE CI 가 제일 위에 있다. 이놈은 라이센스가 있는놈이다. 무료평가 시기 45일 지나면 못쓴다.  그래서 이놈은 패스

아래 AngularJS Eclipse 1.2.0 요놈은 AngularJS 라서 패스.

조금더 내리다 보면 Angular Eclipse 1.3.0 이 있다. 요놈으로 설치 해볼려고 한다.


Angular Eclipse 1.3.0 2018-12-07 지금 이건 설치 비추한다. 

여러가기 버그가 존재하고. 

https://github.com/angelozerr/angular-eclipse/issues/107 해결이 안된다. 

설치 해보고 싶으면 Angular IDE CI 요놈으로다가 무료기간 동안만 써보시길 바란다.


Angular Eclipse is a set of plugins which provide support for Angular:


타입스크립트 지원, Angular cli 통합 터미털, Angular@ 문법을 에디터에서 지원한다고 한다.

위자드와 라운처도는 파일 자동생성이나 빌드 관련 툴 같은데 나중에 써봐야겠다.


TypeScript Debugging support 는  Oxgen 버전 이상이어야 지원된다고 하는거 같은데 일단 체크 하고 다음 으로 진행 했다.


라이센스 동의후 완료 하면 창이 닫히면서 설치 진행된다.


중간에 보안관련해서 설치 진행 할꺼냐고 묻는다. Install Anyway 로 해서 진행 했다.


STS 재시작 하라고 나온다. Restart Now 로 재시작 한다.


머가 바꿨는지 보면 일단 오른쪽 상단에 Perspective 를 눌러보면 다음과 같이 Angular가 딱하니 있다.


Angular Perspective 로 변경해서 작업 하자.


기본 화면 구조는 같아보이고 하단에 터미널이 눈에 띈다.  CLI 관련 처리를 위해서 기본으로 나온거 같아보인다.


하면서 전부 캡쳐 해놓은거 캡쳐 프로그램 오류로 캡쳐 이미지 전부 없어졌다.   

아래는 맨마지막  Angular Perspective 로 변경 후 이미지를 다시 캡쳐한것이다.

sts angular perspectivests angular perspective view



https://angular.io/guide/language-service 에 있듯이 아래 3개 중에 하나로 하는걸 강추 한다.

Visual Studio code로 해볼 예정이다.

  • Visual Studio Code 

  • WebStorm

  • Sublime Text



반응형
반응형

spring integration

https://github.com/spring-projects/spring-integration-samples/blob/master/basic/tcp-client-server/src/main/resources/META-INF/spring/integration/tcpClientServerDemo-context.xml


https://gitlab.com/kjkjjang/echo-server-client/blob/master/src/main/resources/META-INF/spring/integration/serverConfig.xml


angular + spring boot

https://chariotsolutions.com/blog/post/angular-2-spring-boot-jwt-cors_part1/

https://github.com/oktadeveloper/spring-boot-angular-example


angular + sts

https://grokonez.com/tool/setup-angular-ide-spring-tool-suite

라이센스를 잘 읽어봐서 설치해야된다. ( 특정 기간이 지난후 유료로 변하는것도 많다.)


spring boot + swing 

https://github.com/DanielMichalski/spring-boot-swing-reservations


spring boot rest service

https://spring.io/guides/tutorials/bookmarks/


spring boot rest api + tdd

https://github.com/pivotal-chicago/spring-boot-rest-api-tdd


spring boot + tdd

https://jojoldu.tistory.com/33


java8 optional

http://asfirstalways.tistory.com/354


spring boot + datatable server

https://www.opencodez.com/java/datatable-with-spring-boot.htm


Spring Boot + Angular 6 example | Spring Data JPA + REST + MySQL CRUD example

https://grokonez.com/spring-framework/spring-data/spring-boot-angular-6-example-spring-data-jpa-rest-mysql-crud-example


angular test-driven development

https://www.pluralsight.com/guides/introduction-to-angular-test-driven-development


angular cli

http://web-front-end.tistory.com/64


angualr datatable

https://blog.angular-university.io/angular-material-data-table/

http://l-lin.github.io/angular-datatables/#/getting-started


angular sweetalert

https://www.npmjs.com/package/ng2-sweetalert2


java xml parser

http://lee-mandu.tistory.com/377


websocket 

http://blog.naver.com/PostView.nhn?blogId=moonv11&logNo=220658500567&parentCategoryNo=&categoryNo=15&viewDate=&isShowPopularPosts=true&from=search


querydsl

https://lng1982.tistory.com/285

http://adrenal.tistory.com/25


jpa 

https://jojoldu.tistory.com/165


spring tdd

http://thswave.github.io/java/2015/03/02/spring-mvc-test.html





반응형
반응형


제너레이터시 필요 옵션

https://angular.io/cli/generate에 보면 알수 있다.

ng g c pages/home -t -s --spec=false --flat

CREATE src/app/pages/home.component.ts (250 bytes) 


테스트 코드 생성 안함 옵션 : --spec=false

인라인템플릿으로 생성 : -t 

인라인스타일으로 생성 : -s

해당 콤포넌트 명으로 폴더를 맹글지 않고 해당 폴더에 바로 생성 : --flat


별명 있는놈들은 다 중요해보이지만. 실제 자주 사용할려면 필수로 전부 알아야 될것같다.


반응형
반응형

Error: Unexpected value 'CodeTypeComponent' declared by the module 'AppModule'. Please add a @Pipe/@Directive/@Component annotation


콤포넌트 내에서 다른 클래스 선언시 @Component 아래에다 클래스 선언시 오류난다.

@Component 정의 이전에 필요 클래스를 선언해야된다.



class Person {

  id: number;

  firstName: string;

  lastName: string;

}

@Component({

  selector: 'app-code-type',

  templateUrl: './code-type.component.html',

  styleUrls: ['./code-type.component.css']

})



위에 Person 클래스를 저렇게 @Component 위에 정의를 해야 동작된다.


반응형
반응형

ng build 나 serve 하면

기존 outDir 경로에 무언가를 하는것 같다. 

해당 폴더를 강제로 삭제해도 지워지지도 않고 

 operation not permitted 메세지만 줄기차게 나온다.

이것저것 해봤으나 안된다.

컴퓨터 재부팅후 폴더 삭제가 가능 했다.


EPERM: operation not permitted, lstat 'D:\workspace\sts\ar-cms-client\dist\assets\images\flags\16'

Error: EPERM: operation not permitted, lstat 'D:\workspace\sts\ar-cms-client\dist\assets\images\flags\16'

    at Object.fs.lstatSync (fs.js:961:11)

    at Object.lstatSync (D:\workspace\sts\ar-cms-client\node_modules\graceful-fs\polyfills.js:297:22)

    at rimrafSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:237:18)

    at options.readdirSync.forEach.f (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:291:39)

    at Array.forEach (<anonymous>)

    at rmkidsSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:291:26)

    at rmdirSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:281:7)

    at fixWinEPERMSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:167:5)

    at rimrafSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:260:26)

    at options.readdirSync.forEach.f (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:291:39)

    at Array.forEach (<anonymous>)

    at rmkidsSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:291:26)

    at rmdirSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:281:7)

    at fixWinEPERMSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:167:5)

    at rimrafSync (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:260:26)

    at options.readdirSync.forEach.f (D:\workspace\sts\ar-cms-client\node_modules\fs-extra\lib\remove\rimraf.js:291:39)

반응형
반응형


ngx-bootstrap 설치

npm install ngx-bootstrap --save


npm WARN ajv-keywords@3.2.0 requires a peer of ajv@^6.0.0 but none is installed. You must install peer depende

ncies yourself.

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):

npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","

arch":"any"} (current: {"os":"win32","arch":"x64"})


+ ngx-bootstrap@2.0.5

added 68 packages in 26.092s

=====================================================================================

ng2-charts 설치

npm install ng2-charts --save


npm WARN ajv-keywords@3.2.0 requires a peer of ajv@^6.0.0 but none is installed. You must install peer dependencies yourself.

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):

npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (cur

rent: {"os":"win32","arch":"x64"})


+ ng2-charts@1.6.0

added 72 packages in 17.546s

=====================================================================================

chart.js 설치

npm install chart.js --save


npm WARN ajv-keywords@3.2.0 requires a peer of ajv@^6.0.0 but none is installed. You must install peer dependenci

es yourself.

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):

npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arc

h":"any"} (current: {"os":"win32","arch":"x64"})


+ chart.js@2.7.2

added 67 packages and updated 1 package in 17.462s

=====================================================================================

 jvectormap 설치

 npm i jvectormap


pm WARN deprecated jvectormap@2.0.4: jvectormap is not maintened since Aug 2015. You can use jvectormap-next or

jqvmap instead.

npm WARN ajv-keywords@3.2.0 requires a peer of ajv@^6.0.0 but none is installed. You must install peer dependenci

es yourself.

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):

npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arc

h":"any"} (current: {"os":"win32","arch":"x64"})


+ jvectormap@2.0.4

added 69 packages in 17.386s

=====================================================================================

jquery-slimscroll 설치

npm i jquery-slimscroll


npm WARN ajv-keywords@3.2.0 requires a peer of ajv@^6.0.0 but none is installed. You must install peer dependenci

es yourself.

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):

npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arc

h":"any"} (current: {"os":"win32","arch":"x64"})


+ jquery-slimscroll@1.3.8

added 68 packages in 13.269s

=====================================================================================

Many TsLint Foirmatting lssues Detected.

A hight number of formatting issues have been detected in project-name. Showing these can make more serious issues harder to see.


Show 356 formatting issues.

Disable checking of formatting issues for this project.


STS에서 알림창으로 TsLint  형식이 다른걸 표시 하겠냐 묻는다.

356개나 있다. 

=====================================================================================

STS 에서 문법 검사 해주는 내용.

Multiple markers at this line

- " should be '

- 3 changed lines

홀따옵표로 대부분 쓴다.


declare var jQuery:any;

missing whitespace

공백이 필요한 부분엔 정확히 넣어야 된다.
declare var jQuery: any;


Exceeds maximum line length of 140

3 quick fixes available:

 Remove rule 'max-line-length' from tslint.json

 Jump to rule configuration

 Disable TSLint validation for this project

 소스 라인당 140 줄이라네요. 일단 500으로 변경


var pageWrapper = jQuery('#page-wrapper');

Identifier 'pageWrapper' is never reassigned; use 'const' instead of 'var'.

재할당 되지 않는건 var 대신 const 를 사용해야 된다군요.


Missing semicolon

끝에 세미콜론도 체크해주네요.


import { HttpModule } from '@angular/http';


imports: [

    BrowserModule,

    FormsModule,

    HttpModule,

    DashboardsModule,

    LayoutsModule,

    AppviewsModule,

    RouterModule.forRoot(ROUTES)

  ],


HttpModule is deprecated: use

HttpModule이 deprecated 됬다는데 사용했다네.;


import { HttpClientModule } from '@angular/common/http';

imports: [

    BrowserModule,

    FormsModule,

    HttpClientModule,

    DashboardsModule,

    LayoutsModule,

    AppviewsModule,

    RouterModule.forRoot(ROUTES)

  ],


HttpModule HttpClientModule


=====================================================================================

 <canvas baseChart height="114"

                            [datasets]="lineChartData"

                            [labels]="lineChartLabels"

                            [options]="lineChartOptions"

                            [chartType]="lineChartType"

                            [colors]="lineChartColors">

                    </canvas>

Identifier 'lineChartOptions' is not defined. The component declaration, template variable declarations, and element references do not contain such a member

차트관련 라이브러리나 angular의 버전이 달라 발생하는 문제 같은데 아직 확인 중이다.






 

반응형
반응형


Failed: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.


 TestBed.configureTestingModule({

      providers: [

          {provide: APP_BASE_HREF, useValue : '/' }

      ]

    }).compileComponents();


providers에 APP_BASE_HREF 추가하면 된다.


Error: StaticInjectorError(DynamicTestModule)[MessagesComponent -> MessageService]: 

  StaticInjectorError(Platform: core)[MessagesComponent -> MessageService]: 

    NullInjectorError: No provider for MessageService!


TestBed.configureTestingModule({

      providers: [

         MessageService

      ]

    }).compileComponents();


MessageService를 찾아서 providers에 추가해주면 된다.


Failed: Template parse errors:

Can't bind to 'routerLink' since it isn't a known property of 'a'. ("<h3>Top Heroes</h3>

<div class="grid grid-pad">

    <a *ngFor="let hero of heroes" class="col-1-4" [ERROR ->]routerLink="/detail/{{hero.id}}">

        <div class="module hero">

            <h4>{{hero.name}}</h4"): ng:///DynamicTestModule/DashboardComponent.html@2:51


TestBed.configureTestingModule({

      imports: [

        RouterTestingModule

      ],

      declarations: [ DashboardComponent ]

    })

RouterTestingModule 를 찾아서 import 해준다.



반응형
반응형

Directive는 DOM 요소의 모양이나 동작을 변경합니다.

앵귤라에는 세가지 종류의 디렉티브가 있다.


  • Components  -  템플릿이 있는 디렉티브
  • 구조적 디렉티브 - DOM요소들을 추가, 제거 하여 DOM 레이아웃을 변경합니다.
  • 속성 디렉티브 - 요소, 구성 요소 또는 다른 디렉티브의 모양 또는 동작을 변경합니다.

콤포넌트 디렉티브는 가장일반적인 방법 이다.
구조적 디렉티브는 뷰의 구조를 변경할때 쓰인다.
속성 디렉티브는 요소의 속성으로 사용됩니다.


<p appHighlight>Highlight me!</p>


CLI명령을 사용해여 디렉티브 생성

ng generate directive highlight


디렉티브 정의는 앵귤라의 모듈 정의와 같게 정의 하면 된다.


hightlight.directive.ts

import { Directive } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { constructor() { } }


Directive를 import하고 @Directive 데코레이터를 사용해서 정의한다.

디렉티브의 설정에 selector은 CSS 속성 선택자를 사용한다.


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

디렉티브의 생성자에 ElementRef 주입 하고, 네이티브요소 속성을 통해 DOM 요소에 직접 액세스 할수 있다.


@angular/core 에 HostListener를 import 해서 이벤트 응답을 추가할수 있다.


import { Directive, ElementRef, HostListener } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { constructor(private el: ElementRef) { } @HostListener('mouseenter') onMouseEnter() { this.highlight('yellow'); } @HostListener('mouseleave') onMouseLeave() { this.highlight(null); } private highlight(color: string) { this.el.nativeElement.style.backgroundColor = color; }


@Input 데이터 바인딩을 이용하여 값을 디렉티브에 전달한다.


import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { constructor(private el: ElementRef) { } @Input('appHighlight') highlightColor: string; //input 데이터 별칭을 사용한경우

//@Input highlightColor: string; //input 데이터 별칭을 사용 안한경우. @HostListener('mouseenter') onMouseEnter() { this.highlight(this.highlightColor || 'red'); } @HostListener('mouseleave') onMouseLeave() { this.highlight(null); } private highlight(color: string) { this.el.nativeElement.style.backgroundColor = color; } }


<p [appHighlight]="color">Highlight me!</p>


반응형
반응형


HTTP

이 튜토리얼에서, 다음  앵귤라의 HttpClient의 도움을 받아서 데이터 영속성 기능을 추가할수 있다.

  • HeroService는 HTTP 요청을 통해 영웅 데이터를 가져온다.
  • 영웅을 추가, 수정, 삭제할수 있고 이러한 변경 사항을  HTTP를 통해 저장된다.
  • 영웅들의 이름으로 검색할수 있다.

이페이지를 다 마쳤을때 , 앱은 다음 실행 샘플 / 다운로드 예제 처럼 보일 것이다.


HTTP 서비스 활성

HTTP상에서 원격서버와 통신하기위한 HttpClient는 앵귤라의 매카니즘이다.

이 앱 모든곳에서 HttpClient를 사용 가능하게 하려면,

  • root AppModule을 열어,
  • HttpClientModule을 @angular/common/http에서 import 한다.
  • 이것을 @NgModule.imports 배열을 추가한다.


데이터 서버 모의실험

이 튜토리얼 샘플은 In-memory라는 웹 API 모듈을을 사용해서 원격 데이터 서버와 통신하는 것처럼 한다.

모듈을 설치 한 후 앱은 인 메모리 웹 API가 이러한 요청을 가로 채고이를 메모리 내 데이터 저장소에 적용하고 시뮬레이션 된 응답을 반환하지 않고 HttpClient에 요청을 보내고 응답을 수신합니다.

이 기능은 튜토리얼을 위한 휼륭한 편의기능이다.  HttpClient를 배우고 서버에 셋업 않아도 될 것이다.

서버의 웹 api가 불분명하거나 아직 구현되지 않았을때 이것은 아마도 초기단계 에서 당신 자신의 앱 환경에 편의기능일 것이다.

중요 :  In-memory Web API 모듈은 Angular에 HTTP와 관계가 없다.

만약 당신이 HttpClient에 대해 배울려고 단지 이 튜토리얼을 읽기만하면 , 이번 단계를 건너 띌수 있다.  만약 당신은 이 튜토리얼을 따라 코딩한다면, 여기 있어서 In-memory Web API을 지금 추가해라.


npm을 통한 In-memory Web API 패키지 설치한다.

참고 : 이 패키지의 버전은 현재 버전인 @angular/cli과의  호환선을 유지하기 위해 v0.5은 로 잠겨 있다.

npm install angular-in-memory-web-api@0.5 --save


아래는 실행결과이다.

PS D:\workspace\dev\angular02\angular-tour-of-heroes> npm install angular-in-memory-web-api@0.5 --save

npm ERR! path D:\workspace\dev\angular02\angular-tour-of-heroes\node_modules\needle\node_modules

npm ERR! code EPERM

npm ERR! errno -4048

npm ERR! syscall scandir

npm ERR! Error: EPERM: operation not permitted, scandir 'D:\workspace\dev\angular02\angular-tour-of-heroes\node_modules\needle\node_modules'

npm ERR!  { Error: EPERM: operation not permitted, scandir 'D:\workspace\dev\angular02\angular-tour-of-heroes\node_modules\needle\node_modules'

npm ERR!   stack: 'Error: EPERM: operation not permitted, scandir \'D:\\workspace\\dev\\angular02\\angular-tour-of-heroes\\node_modules\\needle\\node_modules\'',

npm ERR!   errno: -4048,

npm ERR!   code: 'EPERM',

npm ERR!   syscall: 'scandir',

npm ERR!   path: 'D:\\workspace\\dev\\angular02\\angular-tour-of-heroes\\node_modules\\needle\\node_modules' }

npm ERR!

npm ERR! Please try running this command again as root/Administrator.

npm ERR! A complete log of this run can be found in:

npm ERR!     C:\Users\oldma\AppData\Roaming\npm-cache\_logs\2018-04-23T04_16_31_730Z-debug.log


npm cache clean 하면 된다는데 npm cache clean 해도 오류를 뱉는다.

npm cache verify 한후 실행하니 경고와 함깨 실행되었다.

PS D:\workspace\dev\angular02\angular-tour-of-heroes> npm install angular-in-memory-web-api@0.5 --save

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.0 (node_modules\fsevents):

npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.0: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})


+ angular-in-memory-web-api@0.5.4

added 127 packages and updated 1 package in 19.496s



잠시후에 만들 HttpClientInMemoryWebApiModule과 InMemoryDataService 클래스를 임포트 한다.

src/app/app.module.ts (In-memory Web API imports)

import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';

import { InMemoryDataService }  from './in-memory-data.service';

InMemoryDataService로 HttpClient를 가져온 후에 HttpClientInMemoryWebApiModule을 @ NgModule.imports 배열에 추가하십시오.

HttpClientModule,


// The HttpClientInMemoryWebApiModule module intercepts HTTP requests

// and returns simulated server responses.

// Remove it when a real server is ready to receive requests.

HttpClientInMemoryWebApiModule.forRoot(

  InMemoryDataService, { dataEncapsulation: false }

)


forRoot() 설정 메소드는 인메모리 데이터베이스가 주가된 InMemoryDataService 클래스를 가진다.

The Tour of Heroes 샘플은 다음 내용을 가진 src/app/in-memory-data.service.ts 클래스를 생성한다.  

src/app/in-memory-data.service.ts

import { InMemoryDbService } from 'angular-in-memory-web-api';


export class InMemoryDataService implements InMemoryDbService {

  createDb() {

    const heroes = [

      { id: 11, name: 'Mr. Nice' },

      { id: 12, name: 'Narco' },

      { id: 13, name: 'Bombasto' },

      { id: 14, name: 'Celeritas' },

      { id: 15, name: 'Magneta' },

      { id: 16, name: 'RubberMan' },

      { id: 17, name: 'Dynama' },

      { id: 18, name: 'Dr IQ' },

      { id: 19, name: 'Magma' },

      { id: 20, name: 'Tornado' }

    ];

    return {heroes};

  }

}

이파일은 mock-heroes.ts 파일을 대체한다. 이제는 삭제해도 안전하다.

서버가 준비 됬을때, In-memory Web API를 떼어서 분리하고  앱의 요청은 서버를 통해 할것이다.

지금 HttpClient 이야기로 돌아갑니다.


영웅과 HTTP

필요한 어떤 HTTP 을 import 한다.

src/app/hero.service.ts (import HTTP symbols)

import { HttpClient, HttpHeaders } from '@angular/common/http';

HttpClient를 http라 불리는 private 속성으로 생성자에 주입한다.

constructor(

  private http: HttpClient,

  private messageService: MessageService) { }

MessageService 주입을 유지한다.  private 로그 메소드안에서 감싸진것을 자주 호출할수 있다.


/** Log a HeroService message with the MessageService */

private log(message: string) {

  this.messageService.add('HeroService: ' + message);

}

heroesUrl을 서버에서 영웅 자원의 주소 같이 정의한다.

private heroesUrl = 'api/heroes';  // URL to web api

HttpClient를 이용한 영웅 얻기

현재의 HeroService.getHeroes()은 RxJS of()의  Observable<Hero[]> 모의 영웅들의 배열을 리턴하는 함수를 사용한다.

src/app/hero.service.ts (getHeroes with RxJs 'of()')

getHeroes(): Observable<Hero[]> {

  return of(HEROES);

}


HttpClient를 사용해서 메소드 변경

/** GET heroes from the server */

getHeroes (): Observable<Hero[]> {

  return this.http.get<Hero[]>(this.heroesUrl)

}


브라우저가 리프레시 한다. 영웅 데이터는 모의 서버에서 부터 성공적으로 로딩된다.

당신은 http.get을 바꿔 버렸고 두 기능 모두 Observable <Hero []>를 반환하기 때문에 다른 변경없이 앱은 계속 작동합니다.


Http 모듈은 하나의 값을 리턴한다.

모든 HttpClient 메소드는 어떤 RxJS Observable을 리턴한다.

HTTP은 용청/응답 프로토콜이다. 요청하면 하나의 응답을 리턴한다.

보통, Observable은 시간이 흐르면 여러 값을 리턴할수 있다.  HttpClient에서의 옵저버블은 항상 하나의 값을 보내고 그리고 완료하고 다시는 보내지 않는다.

특정한 HttpClient.get 리턴된한 Observable<Hero[]>을 호출한다. 그야말로 "an observable of hero arrays". 실제로, 그것은 하나의 영웅 배열을 한번 리턴한다.


HttpClient.get 응답 데이터를 리턴한다.

HttpClient.get은 기본적으로 타입이 지정되지 않은 JSON object 응답 본문을 리턴한다.  선택적 형식 지정자 <Hero []>를 적용하면 입력 된 결과 개체가 제공됩니다.

JSON data의 형태는 서버의 API 에서 결정한다. The Tour of Heroes의 data API는 영웅 데이터를 배열로 리턴한다.

다른 API들은 이마도 데이터를 묻을수 있다. 오브젝트를 원할때 데이터 바깥쪽에 프로세싱 으로 RxJS map 연산자로 Observable 결과를 프로세싱하는 것을 처리하는것 파내야 해야할지 모른다. 

여기서 논의되진 않았지만,  getHeroNo404() 메소드 안에 map은 간단한 소스코드 코드를 포함된 예제이다.


에러 다루기

특별히 데이터를 원격 서버에서 가져올때 문제가 발생된다. HeroService.getHeroes() 메소드 에러들을 캐치하고 어떤 적절한 것을 한다.

에러를 캐치하는것은,  http.get()에서 RxJS catchError() 연산자를 통한 옵저버블한 결과를 "pipe"한다.

나중에 필요하게 될 다른 연산자와 함께 catchError를 rxjs/operators으로 임포트 한다.

import { catchError, map, tap } from 'rxjs/operators';


이제 .pipe() 메소드를 써서 옵저버블한 결과 연장하고 catchError() 연산자를 제공한다.

getHeroes (): Observable<Hero[]> {

  return this.http.get<Hero[]>(this.heroesUrl)

    .pipe(

      catchError(this.handleError('getHeroes', []))

    );

}

catchError() 연산자는 실패된 옵저버블을 인터셉트한다.  그것은 오류와 함께 원하는 것을 할 수있는 오류 처리기를 오류에 전달합니다.

다음 handleError() 메소드는 에러를 보도한고 애플리케이션이 계속 작업되도록 무해한 결과를 리턴한다.


handleError

다음 errorHandler()은 많은 메소드를 공유 해서 이것은 그들의 다른 요구들을 만났을때 일반적이다.

오류를 직접 처리하는 대신 실패한 작업의 이름과 안전한 반환 값으로 구성된 catchError에 오류 처리기 함수를 반환합니다.

/**

 * Handle Http operation that failed.

 * Let the app continue.

 * @param operation - name of the operation that failed

 * @param result - optional value to return as the observable result

 */

private handleError<T> (operation = 'operation', result?: T) {

  return (error: any): Observable<T> => {


    // TODO: send the error to remote logging infrastructure

    console.error(error); // log to console instead


    // TODO: better job of transforming error for user consumption

    this.log(`${operation} failed: ${error.message}`);


    // Let the app keep running by returning an empty result.

    return of(result as T);

  };

}

에러콘솔로 에러를 보도후에 , 핸들러는 사용자 에게 친근한 메세지를 생성하고 안전한 값을 앱이 유지할수 있게 리턴한다.

각각의 서비스 메소드는  다른  옵저버블 결과 다른 종류를 리턴하기 때문에  errorHandler() 는 타입 매개 변수를 취하므로 앱에서 기대하는 타입에 안전한 값을 리턴할수 있다.


Observable에 다가가다.

HeroService 메소드는 관찰 가능한 값의 흐름을 두드리고 (log ()를 통해) 페이지 하단의 메시지 영역으로 메시지를 보냅니다.

그들은 관측 할 수있는 값을보고, 그 값들로 무언가를하고, 그들을 따라가는 RxJS 탭 연산자로 그것을 할 것입니다. 탭 콜백은 값 자체를 건드리지 않습니다.

다음은 작업을 기록하는 탭이있는 getHeroes의 최종 버전입니다.


/** GET heroes from the server */

getHeroes (): Observable<Hero[]> {

  return this.http.get<Hero[]>(this.heroesUrl)

    .pipe(

      tap(heroes => this.log(`fetched heroes`)),

      catchError(this.handleError('getHeroes', []))

    );

}

id로 영웅을 얻기

대부분 웹 API들은 api/hero/:id에서 요청한 id로 얻는것을  제공합니다. 쵸얻을 만드는 HeroService.getHero() 메소드를 추가한다.

src/app/hero.service.ts


/** GET hero by id. Will 404 if id not found */

getHero(id: number): Observable<Hero> {

  const url = `${this.heroesUrl}/${id}`;

  return this.http.get<Hero>(url).pipe(

    tap(_ => this.log(`fetched hero id=${id}`)),

    catchError(this.handleError<Hero>(`getHero id=${id}`))

  );

}

저것들은 getHeroes()의 3개의 중요한 차이점이다.

  • 바라던 영웅의 id로  요청 URL을 생성합니다.
  • 서버 영웅 하나보다는 영웅의 배열로 응답 할 것이다.
  • 그러므로, getHero은 영웅 배열의 옵저버블 보다는 Observable<Hero>을 리턴한다.

Update heroes

영웅 상세 뷰에서 영웅의 이름을 수정한다. 타이핑 할때, 영웅 이름을 페이지의 상단의 헤드를 업데이트한다. 그러나 "go back button"을 클릭 할때, 변경된 내용이 분실된다.

만약 당신이 변경이 유지되기 원하면, 원래 서버에 그것들을 저장해야 한다.

영웅 상세 템플릿의 끝에, 저장 버튼을 클릭 이벤트를 새로운 콤포넌트 메소드 이름은 save() 라고 언급한 바인딩과 함께 추가한다    


src/app/hero-detail/hero-detail.component.html (save)

<button (click)="save()">save</button>

영웅 서비스 updateHero () 메서드를 사용하여 영웅 이름 변경 사항을 유지 한 다음 이전보기로 다시 이동하는 다음 save () 메서드를 추가합니다.

src/app/hero-detail/hero-detail.component.ts (save)

save(): void {

   this.heroService.updateHero(this.hero)

     .subscribe(() => this.goBack());

 }


HeroService.updateHero() 추가

updateHero() 메소드의 종합적인 구조는 getHeroes()와 유사하나, 그것은 http.put()를 사용해서 서버에 변경된 영웅 정보를 유지한다.  

src/app/hero.service.ts (update)


/** PUT: update the hero on the server */

updateHero (hero: Hero): Observable<any> {

  return this.http.put(this.heroesUrl, hero, httpOptions).pipe(

    tap(_ => this.log(`updated hero id=${hero.id}`)),

    catchError(this.handleError<any>('updateHero'))

  );

}


HttpClient.put() 메소드는 3개의 파라메터를 갖는다.

  • URL
  • 데이터 업데이트 ( 클래스 안에 영웅 수정 )
  • options

The URL is unchanged. The heroes web API knows which hero to update by looking at the hero's id.

URL은 변경된다. 영웅 웹 API는 영웅이 영웅의 id로 찾아 업데이트하는것을 알게된다.


The heroes web API expects a special header in HTTP save requests. That header is in the httpOptions constant defined in the HeroService.

영웅 웹 API는 HTTP 저장요청에 특별한 헤더를 예상한다. 헤더는 httpOptions안에  HeroService에 변하지 안게 정의된것 입니다.


const httpOptions = {

  headers: new HttpHeaders({ 'Content-Type': 'application/json' })

};

브라우저가 리플래시 된고, 영웅 이름 변경한다, 변경을 저장한다, "go back"버튼을 클릭한다. 이제 목록에 변경된 이름으로 영웅은 나타납니다.


새 영웅 추가

새로운 영웅을 추가하는것은, 이 앱은 영웅의 이름만 필요로한다. input 요소가와 추가된 버튼과 짝을지어진 것을 사용할수있다.

HeroesComponent  템플릿안에 헤딩 직후에 다음을 추가한다.

src/app/heroes/heroes.component.html (add)


<div>

  <label>Hero name:

    <input #heroName />

  </label>

  <!-- (click) passes input value to add() and then clears the input -->

  <button (click)="add(heroName.value); heroName.value=''">

    add

  </button>

</div>


클릭 이벤트를 응답하는것은 콤포넌트의 클릭 핸들러로 불려지고 입력 필드를 치우서 , 이것은 다른 이름을 위해 준비된다.


src/app/heroes/heroes.component.ts (add)


add(name: string): void {

  name = name.trim();

  if (!name) { return; }

  this.heroService.addHero({ name } as Hero)

    .subscribe(hero => {

      this.heroes.push(hero);

    });

}

이미 정해진 이름은 비어있지 않다.

addHero 성공적으로 저장 했을때, 새로운 영웅웅 답신을 받는것을 구독하고 표시되는 영웅목록란으로 밀어 넣는다.

다음섹션에 HeroService.addHero 를 작성한다.

HeroService.addHero() 추가

다음 addHero() 메소드를 HeroService 클래스에 추가한다.

src/app/hero.service.ts (addHero)

/** POST: add a new hero to the server */

addHero (hero: Hero): Observable<Hero> {

  return this.http.post<Hero>(this.heroesUrl, hero, httpOptions).pipe(

    tap((hero: Hero) => this.log(`added hero w/ id=${hero.id}`)),

    catchError(this.handleError<Hero>('addHero'))

  );

}

HeroService.addHero()는 두가지 방식중에 updateHero과 다르다.

put() 대신에 HttpClient.post()을 호출한다.

그서버가 새로운 영웅의 id로 자동생성되는 기대한다. Observable<Hero>에서 호출자를(caller) 리턴한다.

브라우저가 리프래시되면 어떤 영웅들이 추가된다.


영웅 삭제

목록 영웅들 내의 각각의 영웅은 삭제 버튼을 가질수있다.

다음 버튼 요소를 HeroesComponent 템플릿에 추가하고  <li> 요소 안에 영웅 이름이 반복된다.


<button class="delete" title="delete hero"

(click)="delete(hero)">x</button>

영웅의 목록에 대한 HTML은 다음과 같아야합니다.


src/app/heroes/heroes.component.html (list of heroes)


<ul class="heroes">

  <li *ngFor="let hero of heroes">

    <a routerLink="/detail/{{hero.id}}">

      <span class="badge">{{hero.id}}</span> {{hero.name}}

    </a>

    <button class="delete" title="delete hero"

    (click)="delete(hero)">x</button>

  </li>

</ul>

영웅 항목의 맨 오른쪽에 삭제 버튼을 배치하려면 heroes.component.css에 CSS를 추가하십시오. 아래의 마지막 검토 코드에서 CSS를 찾을 수 있습니다.

구성 요소에 delete () 핸들러를 추가하십시오.

src/app/heroes/heroes.component.ts (delete)


delete(hero: Hero): void {

  this.heroes = this.heroes.filter(h => h !== hero);

  this.heroService.deleteHero(hero).subscribe();

}

비록 HeroService에 영웅 삭제를 위임한 컴포넌트 이긴하지만, 영웅들의 목록 자기 자신의 것을 계속 업데이트를 위해 책임지고 이다.  컴포넌트의 delete() 메소드는 목록에서 즉시 HeroService가 서버에서 성공할것으로 예상하고 제거한다.

컴포넌트가 heroService.delete()으로부터  옵저버블한 리턴하는것은  실제 아무것도  아니다. 게다가 구독해야한다. 

subscribe()을 방치 했다면, 서비스는  서버로 삭제요청 보내는것을 할수 없을것이다. 원칙적으로 Observable은 어떤 구독 전까지 아무것도 하지않는다.

일시적으로 subscribe() 제거를 통해 당신자신을 위해 확실하게 하다. "Dashboard"를 클릭하는것, 그리고 "Heroes" 클릭하는것.  영웅들의 목록이 다시 가득차 있는것을 볼수 있을것이다.

HeroService.deleteHero() 추가

deleteHero() 메소드를 HeroService에 다음과 같이 추가 한다.


src/app/hero.service.ts (delete)


/** DELETE: delete the hero from the server */

deleteHero (hero: Hero | number): Observable<Hero> {

  const id = typeof hero === 'number' ? hero : hero.id;

  const url = `${this.heroesUrl}/${id}`;


  return this.http.delete<Hero>(url, httpOptions).pipe(

    tap(_ => this.log(`deleted hero id=${id}`)),

    catchError(this.handleError<Hero>('deleteHero'))

  );

}


HttpClient.delete을 호출한다.

URL은 영웅 자원 URL과 삭제할 영웅의 id가 더해진 URL이다.

put과 post와 함깨 데이터를 보낼수 없다.

아직까진 httpOptions으로 보낸다.

브라우저가 리프래시 되고 새롭게 삭제하는 기능을 시도한다.


이름으로 검색

이번 마지막 예제는, chain Observable operators 연산자와 함깨 HTTP 요청과 닮은 숫자를 최소화 하는것을  배운고, 네트워크 대역을 경제적으로 소모하는것을 배운다.

영웅을 찾는 기능을 대시보드에 추가할 것이다. 검색 박스안에 사용자가 이름을 타이핑할때, 그 이름으로 필터된 영웅들을 위해 HTTP요청을 반복해서 만들 것이다. 목표는 필요한만큼 요청을 하는 것이다.

HeroService.searchHeroes

searchHeroes 메소드를 HeroService에 추가하는것을 시작 한다.


src/app/hero.service.ts

/* GET heroes whose name contains search term */

searchHeroes(term: string): Observable<Hero[]> {

  if (!term.trim()) {

    // if not search term, return empty hero array.

    return of([]);

  }

  return this.http.get<Hero[]>(`api/heroes/?name=${term}`).pipe(

    tap(_ => this.log(`found heroes matching "${term}"`)),

    catchError(this.handleError<Hero[]>('searchHeroes', []))

  );

}

만약 검색어가 없으면 빈 배열을 메소드는 즉각 리턴한다. 나머지는 getHeroes()와 매우 유사하다. 중요한 다른 단하나는  검색어로된 요청문자열을 포함한  URL이다.


대시보드에 검색 추가

DashboardComponent 템플릿을 열고 DashboardComponent 템플릿의 아래에 <app-hero-search>라는 영웅 검색 요소를 한다.


src/app/dashboard/dashboard.component.html


<h3>Top Heroes</h3>

<div class="grid grid-pad">

  <a *ngFor="let hero of heroes" class="col-1-4"

      routerLink="/detail/{{hero.id}}">

    <div class="module hero">

      <h4>{{hero.name}}</h4>

    </div>

  </a>

</div>


<app-hero-search></app-hero-search>

이템플릿 모양은  HeroesComponent template안에 *ngFor 반복자와 많이 비슷하다.

불행하게도, 앱에 고장난 요소를 추가한다. 앵귤라는 <app-hero-search>와 매치되는 섹렉터의 컴포넌트를 찾을수 없다.

HeroSearchComponent 아직 존재 하지않는다. 고쳐야된다.


HeroSearchComponent 생성

Create a HeroSearchComponent with the CLI.

CLI로 HeroSearchComponent 생성

ng generate component hero-search

CLI이 3개의 HeroSearchComponent 자동생성되고 추가된 컴포넌트를 `AppModule'에 선언한다.

자동생성된 HeroSearchComponent 템플릿은 텍스트 박스로 변경하고 검색결과의 매치를 목록화 한다.


src/app/hero-search/hero-search.component.html


<div id="search-component">

  <h4>Hero Search</h4>


  <input #searchBox id="search-box" (keyup)="search(searchBox.value)" />


  <ul class="search-result">

    <li *ngFor="let hero of heroes$ | async" >

      <a routerLink="/detail/{{hero.id}}">

        {{hero.name}}

      </a>

    </li>

  </ul>

</div>

hero-search.component.css에 아래 마지막 코드 검토에 목록화된  전용 CSS 스타일을  추가한다.

사용자가 검색 상자에 입력 할 때 keyup 이벤트 바인딩은 구성 요소의 search () 메서드를 새 검색 상자 값으로 호출합니다.


AsyncPipe

예상대로 * ngFor는 영웅 개체를 반복합니다.

자세히 살펴보면 * ngFor가 영웅이 아닌 영웅이라는 목록을 반복하는 것을 볼 수 있습니다.

<li *ngFor="let hero of heroes$ | async" >

$는 heroes$ 배열이 아닌 Observable임을 나타내는 관례입니다.

* ngFor는 Observable을 사용하여 아무 것도 할 수 없습니다. 그러나 파이프 문자 (|) 뒤에는 async가 있으며 Angular의 AsyncPipe를 식별합니다.

AsyncPipe는 Observable에 자동으로 가입하므로 구성 요소 클래스에서 Observable을 수행 할 필요가 없습니다.


HeroSearchComponent  클래스 수정

생성 된 HeroSearchComponent 클래스와 메타 데이터를 다음과 같이 바꿉니다.

src/app/hero-search/hero-search.component.ts


import { Component, OnInit } from '@angular/core';


import { Observable } from 'rxjs/Observable';

import { Subject }    from 'rxjs/Subject';

import { of }         from 'rxjs/observable/of';


import {

   debounceTime, distinctUntilChanged, switchMap

 } from 'rxjs/operators';


import { Hero } from '../hero';

import { HeroService } from '../hero.service';


@Component({

  selector: 'app-hero-search',

  templateUrl: './hero-search.component.html',

  styleUrls: [ './hero-search.component.css' ]

})

export class HeroSearchComponent implements OnInit {

  heroes$: Observable<Hero[]>;

  private searchTerms = new Subject<string>();


  constructor(private heroService: HeroService) {}


  // Push a search term into the observable stream.

  search(term: string): void {

    this.searchTerms.next(term);

  }


  ngOnInit(): void {

    this.heroes$ = this.searchTerms.pipe(

      // wait 300ms after each keystroke before considering the term

      debounceTime(300),


      // ignore new term if same as previous term

      distinctUntilChanged(),


      // switch to new search observable each time the term changes

      switchMap((term: string) => this.heroService.searchHeroes(term)),

    );

  }

}


Observable로서 영웅의 선언을 주목하라.

heroes$: Observable<Hero[]>;

ngOnInit ()에서 설정합니다. 당신이하기 전에, searchTerms의 정의에 집중하십시오.


The searchTerms RxJS subject

searchTerms RxJS 제목 

searchTerms 속성은 RxJS Subject로 선언됩니다.


private searchTerms = new Subject<string>();


// Push a search term into the observable stream.

search(term: string): void {

  this.searchTerms.next(term);

}

제목은 관찰 가능한 가치의 원천이며 Observable 자체입니다. Observable과 같이 Subject를 구독 할 수 있습니다.

search () 메소드가 수행하는 것처럼 next (value) 메소드를 호출하여 Observable로 값을 보낼 수도 있습니다.

search () 메서드는 텍스트 상자의 키 입력 이벤트에 대한 이벤트 바인딩을 통해 호출됩니다.


<input #searchBox id="search-box" (keyup)="search(searchBox.value)" />

사용자가 텍스트 상자에 입력 할 때마다 바인딩은 텍스트 상자 값인 "검색 용어"로 search ()를 호출합니다. searchTerms는 검색 용어의 꾸준한 흐름을 방출하는 Observable이됩니다.


RxJS 연산자 채널링

모든 사용자 키 입력 후 searchHeroes ()에 새로운 검색어를 직접 전달하면 과도한 양의 HTTP 요청이 만들어져 서버 리소스에 부담이되고 셀룰러 네트워크 데이터 계획을 통해 레코딩됩니다.

대신 ngOnInit () 메서드는 searchHermes ()에 대한 호출 수를 줄이는 RxJS 연산자의 시퀀스를 통해 관찰 할 수있는 searchTerms를 파이프 처리하여 궁극적으로 영웅 검색 결과 (각 Hero [])를 관찰 할 수있게합니다.


this.heroes$ = this.searchTerms.pipe(

  // wait 300ms after each keystroke before considering the term

  debounceTime(300),


  // ignore new term if same as previous term

  distinctUntilChanged(),


  // switch to new search observable each time the term changes

  switchMap((term: string) => this.heroService.searchHeroes(term)),

);

debounceTime (300)은 새로운 문자열 이벤트의 흐름이 300 밀리 초 동안 일시 중지 될 때까지 기다린 후 최신 문자열을 전달합니다. 300ms보다 자주 요청을하지 않습니다.

distinctUntilChanged는 필터 텍스트가 변경된 경우에만 요청을 보냅니다.

switchMap ()은 debounce 및 distinctUntilChanged를 통해 검색하는 각 검색어에 대해 검색 서비스를 호출합니다. 이전 검색 관측 값을 취소하고 파기하며 관찰 가능한 최신 검색 서비스 만 반환합니다.

switchMap 연산자를 사용하면 모든 규정 키 이벤트가 HttpClient.get () 메소드 호출을 트리거 할 수 있습니다. 요청간에 300ms의 일시 중지가 있더라도 비행 중에 여러 HTTP 요청을 할 수 있으며 보낸 순서대로 반환하지 않을 수 있습니다.

이전 searchHeroes () Observable을 취소한다고해서 보류중인 HTTP 요청이 실제로 중단되는 것은 아닙니다. 원치 않는 결과는 응용 프로그램 코드에 도달하기 전에 버려집니다.

구성 요소 클래스는 영웅 $ observable을 구독하지 않는다는 것을 기억하십시오. 이것이 템플릿의 AsyncPipe 작업입니다.


시도 해봐

앱을 다시 실행하십시오. 대시 보드에서 검색 상자에 텍스트를 입력하십시오. 기존의 영웅 이름과 일치하는 문자를 입력하면 다음과 같은 메시지가 표시됩니다.


요약

당신은 여행이 끝났을 때 많은 것을 성취했습니다.

  • 앱에서 HTTP를 사용하기 위해 필요한 의존성을 추가했습니다.
  • HeroService를 리팩터링하여 웹 API에서 영웅을로드하십시오.
  • post (), put () 및 delete () 메소드를 지원하도록 HeroService를 확장했습니다.
  • 영웅을 추가, 편집 및 삭제할 수 있도록 구성 요소를 업데이트했습니다.
  • 메모리 내 웹 API를 구성했습니다.
  • Observables 사용법을 배웠습니다.


반응형
반응형

앵귤라의 기본 구성 요소라합니다.

내용은 뷰와 클래스로 구성됬다네요.

뷰에서 호출된 화면 경로를 제어한다.


각각의 Hook을 implements  하여 Hook 별 처리 내용을 정의 할수 있다.

export class SpyDirective implements OnInit, OnDestroy {

ngOnInit() { this.logIt(`onInit`); } ngOnDestroy() { this.logIt(`onDestroy`); }

}

lifecycle hooks 확인


import { Component, OnInit } from '@angular/core';

import { Hero } from '../hero';

import { HeroService } from '../hero.service';


@Component({

  selector: 'app-heroes',

  templateUrl: './heroes.component.html',

  styleUrls: ['./heroes.component.css']

})

export class HeroesComponent implements OnInit {

  heroes: Hero[];

  constructor(private heroService: HeroService) { }


  ngOnInit() {

    this.getHeroes();

  }

  getHeroes(): void {

    this.heroService.getHeroes().subscribe(heroes => this.heroes = heroes);

  }

}


Component metadata 

@Component 데코레이터 어노테이션을 붙혀서 선언한다.

selector : CSS 셀렉터 처럼 사용 하면 되고 HTML 에 포함된 요소를 해당 컴포넌트로 랜더링 한다.

templateUrl : 컴포넌트의 주요 뷰를 HTML 템플릿된 파일의 상대경로를 정의한다. 

template : 컴포넌트의 주요 HTML  뷰 코드를 작성한다. 역따옴표를 사용하여 안의 따옵표 코드를 같이 사용 할수 있다.

providers : 사용할 컴포넌트의 의존성 주입하는 프로바이저이다. 배열형태로 정의한다.  컴포넌트의 생성자에서 받아서 인스턴스를 생성한다.

styleUrls : 여기에 정의한 CSS 파일은 해당 컴포넌트에서에 스타일이 적용된다.

style : 해당 컴포넌트에 적용될 스타일 코드를 작성한다.



반응형

+ Recent posts