설정
HttpClientModule을 추가
1 2 3 4 5 6 7 |
imports: [ BrowserModule, FormsModule, NgbModalModule.forRoot(), RouterModule.forRoot(routes), HttpClientModule, ], |
HOST 설정
개발할때 개발환경과 운영환경이 서로 다르다. 그 부분을 해결해주는 방법이 angular의 environments 폴더이다. 개발환경은 environment.ts에 운영환경은 environment.prod.ts 에 각각 설정한다. 여기서는 백엔드 서버의 호스트 아이피를 각각 세팅한다.
1 2 3 4 |
export const environment = { production: false, HOST: 'http://localhost:8080', }; |
1 2 3 4 |
export const environment = { production: true, HOST: 'http://15.164.133.165:8080', }; |
REST api 테스트
hero 리스트 가져오기
/api/heroes
hero_id로 hero 한개 가져오기
/api/hero/hero_id
hero 리스트 가져오기
heroes 리스트를 get 하는 메서드를 만든다. 먼저 http 서비스를 생성자로 주입받고, http get 으로 호출한다.
1 2 3 4 5 |
constructor(private http: HttpClient) { } getHeroes(): Observable<Hero[]> { return this.http.get<Hero[]>(environment.HOST + '/api/heroes'); } |
hero의 id는 hero_id로 리팩토링한다. 반드시 리팩토링을 해야 id를 참조하고 있는 모든 소스가 수정된다.
1 2 3 4 |
export class Hero { hero_id: number; name: string; } |
이제 화면에 REST api를 호출하여 백엔드 서버에서 가져온 hero 리스트가 보여야 한다.
hero 디테일 보기
서비스 부분을 수정한다.
1 2 3 |
getHero(hero_id: number): Observable<Hero> { return this.http.get<Hero>(environment.HOST + `/api/hero/${hero_id}`); } |
서버에서 내려온 hero 정보는 hero_id, name외에 여러가지 정보가 더 있다. 이 정보를 모두 나타내보자. 먼저 hero.ts 에 서버와 동일하게 추가된 property를 추가한다.
1 2 3 4 5 6 7 8 9 10 11 |
export class Hero { hero_id: number; name: string; email: string; sex: string; country: string; address: string; power: string; created: string; updated: string; } |
id를 hero_id로 수정을 하게 되면 이 id를 참조하는 다른 클래스들이 영향을 받으므로 반드시 refactoring을 하여서 한번에 수정을 하여야 한다. 그리고 더이상 사용하지 않는 mock-heroes 화일 등 컴파일시 에러가 나는 부분들은 모두 삭제한다.
이제 form을 이용해서 바인딩을 하는데, 아래와 같은 구성으로 bootstrap을 이용해서 폼을 만든다.
name: input type text
email: input type email
sex: intput type radio, 둘중에 하나를 선택하므로 라디오 그룹으로 구성
country: select, Japan, Korean, American 세개 중에 선택할수 있게 구성
address: textarea, 길게 입력할수 있게 textarea로 구성
power: 다중선택 checkbox,
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<div *ngIf="selectedHero"> <h3>{{ selectedHero.name | uppercase }} Details</h3> <form #myForm> <div><span>id: </span>{{selectedHero.hero_id}}</div> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" placeholder="Enter Name" id="name"> </div> <div class="form-group"> <label for="email">Email Address</label> <input type="email" class="form-control" placeholder="Enter Email" id="email"> </div> <div class="d-flex flex-column mb-1"> <div>성별</div> <div> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="sex" value="male" id="male"> <label class="form-check-label" for="male">남자</label> </div> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="sex" value="female" id="female"> <label class="form-check-label" for="female">여자</label> </div> </div> </div> <div class="form-group"> <label for="country">country</label> <select class="form-control" id="country" name="country"> <option value="Japan">Japan</option> <option value="American">American</option> <option value="Korean">Korean</option> </select> </div> <div class="form-group"> <label for="email">Address</label> <textarea class="form-control" placeholder="Enter address" id="address" rows="3"></textarea> </div> <div class="d-flex flex-column"> <div>power</div> <div> <div class="form-check"> <input type="checkbox" class="form-check-input"> <label class="form-check-label">flying</label> </div> <div class="form-check"> <input type="checkbox" class="form-check-input"> <label class="form-check-label">penetration</label> </div> <div class="form-check"> <input type="checkbox" class="form-check-input"> <label class="form-check-label">hacking</label> </div> <div class="form-check"> <input type="checkbox" class="form-check-input"> <label class="form-check-label">strength</label> </div> </div> </div> </form> <button class="btn btn-info btn-sm mt-3" (click)="goBack()">back</button> </div> |
이제 view가 완성되었으니 이 form에 서버에서 내려온 hero 모델 정보를 바인딩해보자. 만일 보여주는 용도라면 one way binding으로 충분하나, 사용자가 view를 조작해서 모델값도 변경시킨다면 two way 바인딩을 해야 한다.
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
<div *ngIf="selectedHero"> <h3>{{ selectedHero.name | uppercase }} Details</h3> <form #myForm> <div><span>id: </span>{{selectedHero.hero_id}}</div> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" placeholder="Enter Name" id="name" [(ngModel)]="selectedHero.name" name="name"> </div> <div class="form-group"> <label for="email">Email Address</label> <input type="email" class="form-control" placeholder="Enter Email" id="email" [(ngModel)]="selectedHero.email" name="email"> </div> <div class="d-flex flex-column mb-1"> <div>성별</div> <div> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="sex" value="male" id="male" [(ngModel)]="selectedHero.sex"> <label class="form-check-label" for="male">남자</label> </div> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="sex" value="female" id="female" [(ngModel)]="selectedHero.sex"> <label class="form-check-label" for="female">여자</label> </div> </div> </div> <div class="form-group"> <label for="country">country</label> <select class="form-control" id="country" name="country" [(ngModel)]="selectedHero.country"> <option value="Japan">Japan</option> <option value="American">American</option> <option value="Korean">Korean</option> </select> </div> <div class="form-group"> <label for="email">Address</label> <textarea class="form-control" placeholder="Enter address" id="address" rows="3" [(ngModel)]="selectedHero.address" name="address"></textarea> </div> <div class="d-flex flex-column"> <div>power</div> <div> <div class="form-check"> <input type="checkbox" class="form-check-input" name="flying" [(ngModel)]="powers.flying"> <label class="form-check-label">flying</label> </div> <div class="form-check"> <input type="checkbox" class="form-check-input" name="penetration" [(ngModel)]="powers.penetration"> <label class="form-check-label">penetration</label> </div> <div class="form-check"> <input type="checkbox" class="form-check-input" name="hacking" [(ngModel)]="powers.hacking"> <label class="form-check-label">hacking</label> </div> <div class="form-check"> <input type="checkbox" class="form-check-input" name="strength" [(ngModel)]="powers.strength"> <label class="form-check-label">strength</label> </div> </div> </div> </form> <button class="btn btn-info btn-sm mt-3" (click)="goBack()">back</button> </div> <p>{{selectedHero | json}}</p> <p>{{powers | json}}</p> |
서버에서 power 정보가 “flying, penetration, hacking, strength” 이 네가지중에서 다중선택하는데 다중선택이 가능한 html 위젯이 없다. checkbox는 개별적인 선택이 가능하지 그룹형태로 제공하지는 않는다. 그래서 powers라는 데이터를 추가로 만들고 바인딩 하였다.
1 2 3 4 5 6 |
powers = { flying: false, penetration: false, hacking: false, strength: false }; |
이제 서버에서 데이터를 받고 저 배열을 분해해서 위 powers에 바인딩한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
getHero(id: number) { this.heroService.getHero(id) .subscribe(hero => { this.selectedHero = hero; let powerList: string[] = this.selectedHero.power.split(','); let powerObject = {}; powerList.forEach(item => powerObject[item] = true); console.log(powerList, powerObject); Object.assign(this.powers, powerObject); console.log(this.powers); }); } |
먼저 A, B 이런식식의 데이터를 콤마로 분리해서 배열로 만든다. 그 다음에 {A: true, B: true} 형태의 객체로 변환한다. 그리고 기존 객쳉체에 해당 퍼라퍼티를 복사한다. 여기서는 Object.assign(source ,target)을 사용하여 복사하였다.