[JHipster] CRUD 게시판 만들기 - 5 (Create)

Junseo Kim·2019년 10월 23일
0

필요한 목록

  • src -> main -> java -> com.mycompany.myapp -> domain -> [DB 테이블과 연결할 class 파일]
  • src -> main -> java -> com.mycompany.myapp -> repository -> [repository interface 파일]
  • src -> main -> java -> com.mycompany.myapp -> web.rest -> [resource 파일(http request를 받아오는 곳)]
  • src -> main -> resources -> config -> liquibase -> changelog -> [.xml파일(테이블 구조)]
  • src -> main -> resources -> config -> liquibase -> master.xml(만들어준 .xml 파일 include)
  • src -> main -> webapp -> app -> layouts -> navbar -> navbar.component.html(메뉴 추가)
  • src -> main -> webapp -> app -> shared -> model -> [.model.ts 파일]
  • module 파일(만들어 준 후, 상위 모듈에서 import)
  • route 파일
  • service 파일
  • component.ts 파일(CRUD 각각)
  • component.html 파일(CRUD 각각)

Create 기능 구현

구현한 메인 화면의 우측 상단의 '+ Create a new Board' 버튼을 누르면, 정보 입력 창으로 넘어가고, 입력 완료 시, DB에 저장되도록 해보겠다.

board.component.html의 '+ Create a new Board' 버튼의 LouterLink가 '/board/new'이므로, BOARD_ROUTE에 path를 추가해준다.

resolve를 구현해주어야하는데, resolve란 Angular에서 route 이동전에 해당 component에서 필요한 data를 미리 확보해서 해당 component에 그 data가 무조건 있다는 가정을 가능하게 해주는 것이다.

//board.route.ts

//...

@Injectable({ providedIn: 'root' })
export class BoardResolve implements Resolve<IBoard> {
  constructor(private service: BoardService) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<IBoard> {
    const id = route.params['id'];
    if (id) {
      return this.service.find(id).pipe(
        filter((response: HttpResponse<Board>) => response.ok),
        map((board: HttpResponse<Board>) => board.body)
      );
    }
    return of(new Board());
  }
}

export const BOARD_ROUTE: Routes = [
//...

board-update.component.ts로 잘 넘어오면, board-update.component.html을 구현해줘야 한다.

<div class="row justify-content-center">
    <div class="col-8">
        <form name="editForm" role="form" novalidate (ngSubmit)="save()" [formGroup]="editForm">
            <h2 id="jhi-board-heading">Create or edit a Board</h2>
            <div>
                <jhi-alert-error></jhi-alert-error>
                <div class="form-group" [hidden]="!editForm.get('id').value">
                    <label for="id">ID</label>
                    <input type="text" class="form-control" id="id" name="id" formControlName="id"
                           readonly />
                </div>
                <div class="form-group">
                    <label class="form-control-label" for="field_title">Title</label>
                    <input type="text" class="form-control" name="title" id="field_title"
                           formControlName="title"/>
                </div>
                <div class="form-group">
                    <label class="form-control-label" for="field_contents">Contents</label>
                    <input type="text" class="form-control" name="contents" id="field_contents"
                           formControlName="contents"/>
                </div>
                <div class="form-group">
                    <label class="form-control-label" for="field_createdDate">Created Date</label>
                    <div class="input-group">
                        <input id="field_createdDate" type="text" class="form-control" name="createdDate" ngbDatepicker  #publicationDateDp="ngbDatepicker" formControlName="createdDate"/>
                        <span class="input-group-append">
                            <button type="button" class="btn btn-secondary" (click)="publicationDateDp.toggle()"><fa-icon [icon]="'calendar-alt'"></fa-icon></button>
                        </span>
                    </div>
                </div>
            </div>
            <div>
                <button type="button" id="cancel-save" class="btn btn-secondary"  (click)="previousState()">
                    <fa-icon [icon]="'ban'"></fa-icon>&nbsp;<span>Cancel</span>
                </button>
                <button type="submit" id="save-entity" [disabled]="editForm.invalid || isSaving" class="btn btn-primary">
                    <fa-icon [icon]="'save'"></fa-icon>&nbsp;<span>Save</span>
                </button>
            </div>
        </form>
    </div>
</div>

save, editForm, previousState, isSaving 메소드를 컴포넌트에서 선언 & 구현해주어야한다.

먼저 isSaving과 editForm(FormBuilder사용)을 선언해준다.

//board-update.component.ts

//...
@Component({
  selector: 'jhi-board-update',
  templateUrl: './board-update.component.html'
})
export class BoardUpdateComponent implements OnInit {
  isSaving: boolean;

  editForm = this.fb.group({
    id: [],
    title: [],
    contents: [],
    createdDate: []
  });

  constructor(
    private fb: FormBuilder
  ) {}

  ngOnInit() {
  }
}

컴포넌트가 호출되면, isSaving값을 false로 만들고, activatedRoute(현재 동작하는 라우터 인스턴스 객체)의 data 값을 기다리다가 받아서 updateForm 메소드에 전달하여 값을 재설정해준다.(이 부분이 없으면, create시 invaild id 오류발생)

//board-update.component.ts

//...
@Component({
  selector: 'jhi-board-update',
  templateUrl: './board-update.component.html'
})
export class BoardUpdateComponent implements OnInit {
//...
   constructor(
    private fb: FormBuilder,
    protected activatedRoute: ActivatedRoute
  ) {}

  ngOnInit() {
    this.isSaving = false;
    this.activatedRoute.data.subscribe(({ board }) => {
      this.updateForm(board);
    });
  }

  updateForm(board: IBoard) {
    this.editForm.patchValue({
      id: board.id,
      title: board.title,
      contents: board.contents,
      createdDate: board.createdDate
    });
  }
//...

previousState 메소드(취소 버튼 클릭 시, 전 화면으로 돌아가는 기능)도 구현해준다.

//board-update.component.ts

//...
@Component({
  selector: 'jhi-board-update',
  templateUrl: './board-update.component.html'
})
export class BoardUpdateComponent implements OnInit {
//...

  previousState() {
    window.history.back();
  }
//...

html 파일에서, save 버튼을 클릭 시, BoardService으로 연결되어 BoardService에서 http 통신으로 BoardResource에 전달된다.
그 save 기능을 구현해준다.

save() 호출 시, isSaving 값을 true로 바꿔주고, creatFromForm이라는 메소드를 실행해 board에 담아준다.
createFromForm은 editForm에 입력되어 있는 값을 가져가 board 객체로 만들어준다.
subscribeToSaveResponse로 결과를 기다리다가 http 통신 성공 시, 이전 화면으로 돌아가고, board의 id값이 이미 정의되어 있으면, BoardService의 update(구현해야함) 정의되어 있지 않으면 create(구현해야함) 메소드를 호출한다.

//board-update.component.ts

//...
@Component({
  selector: 'jhi-board-update',
  templateUrl: './board-update.component.html'
})
export class BoardUpdateComponent implements OnInit {
//...
 constructor(
    protected boardService: BoardService,
    private fb: FormBuilder,
    protected activatedRoute: ActivatedRoute,
  ) {}
  
  //...

  save() {
    this.isSaving = true;
    const board = this.createFromForm();
    if (board.id !== undefined) {
      this.subscribeToSaveResponse(this.boardService.update(board));
    } else {
      this.subscribeToSaveResponse(this.boardService.create(board));
    }
  }

  private createFromForm(): IBoard {
    return {
      ...new Board(),
      id: this.editForm.get(['id']).value,
      title: this.editForm.get(['title']).value,
      contents: this.editForm.get(['contents']).value,
      createdDate: this.editForm.get(['createdDate']).value
    };
  }

  protected subscribeToSaveResponse(result: Observable<HttpResponse<IBoard>>) {
    result.subscribe(() => this.onSaveSuccess(), () => this.onSaveError());
  }

  protected onSaveSuccess() {
    this.isSaving = false;
    this.previousState();
  }

  protected onSaveError() {
    this.isSaving = false;
  }
}

호출된 BoardService는 아래와 같다.

//board.service.ts

import { Injectable } from '@angular/core';
import {HttpClient, HttpResponse} from "@angular/common/http";
import {IBoard} from "app/shared/model/board.model";
import {SERVER_API_URL} from "app/app.constants";
import {Observable} from "rxjs";
import {createRequestOption} from "app/shared/util/request-util";

type EntityResponseType = HttpResponse<IBoard>;
type EntityArrayResponseType = HttpResponse<IBoard[]>;

@Injectable({
  providedIn: 'root'
})
export class BoardService {
  public resourceUrl = SERVER_API_URL + 'api/boards';

  constructor(protected http: HttpClient) { }

  create(board: IBoard): Observable<EntityResponseType>{
    return this.http.post<IBoard>(this.resourceUrl, board,{observe: 'response'});
  }

  query(req?: any): Observable<EntityArrayResponseType>{
    const options = createRequestOption(req);
    return this.http.get<IBoard[]>(this.resourceUrl, {params: options, observe: 'response'});
  }
}

BoardUpdateComponent의 전체코드는 아래와 같다.

//board-update.component.ts

import { Component, OnInit} from '@angular/core';
import { FormBuilder } from '@angular/forms';
import {BoardService} from "app/board/board.service";
import {IBoard, Board} from "app/shared/model/board.model";
import {Observable} from "rxjs";
import {HttpResponse} from "@angular/common/http";
import {ActivatedRoute} from "@angular/router";

@Component({
  selector: 'jhi-board-update',
  templateUrl: './board-update.component.html'
})
export class BoardUpdateComponent implements OnInit {
  isSaving: boolean;

  editForm = this.fb.group({
    id: [],
    title: [],
    contents: [],
    createdDate: []
  });

  constructor(
    protected boardService: BoardService,
    private fb: FormBuilder,
    protected activatedRoute: ActivatedRoute,
  ) {}

  ngOnInit() {
    this.isSaving = false;
    this.activatedRoute.data.subscribe(({ board }) => {
      this.updateForm(board);
    });
  }

  updateForm(board: IBoard) {
    this.editForm.patchValue({
      id: board.id,
      title: board.title,
      contents: board.contents,
      createdDate: board.createdDate
    });
  }

  previousState() {
    window.history.back();
  }

  save() {
    this.isSaving = true;
    const board = this.createFromForm();
    if (board.id !== undefined) {
      this.subscribeToSaveResponse(this.boardService.update(board));
    } else {
      this.subscribeToSaveResponse(this.boardService.create(board));
    }
  }

  private createFromForm(): IBoard {
    return {
      ...new Board(),
      id: this.editForm.get(['id']).value,
      title: this.editForm.get(['title']).value,
      contents: this.editForm.get(['contents']).value,
      createdDate: this.editForm.get(['createdDate']).value
    };
  }

  protected subscribeToSaveResponse(result: Observable<HttpResponse<IBoard>>) {
    result.subscribe(() => this.onSaveSuccess(), () => this.onSaveError());
  }

  protected onSaveSuccess() {
    this.isSaving = false;
    this.previousState();
  }

  protected onSaveError() {
    this.isSaving = false;
  }
}

실행시켜 create를 시도해보면, 아래와 같이 됨을 볼 수 있다.

0개의 댓글