인디노트

Angular - Firebase Firestore 데이터 바인딩 본문

개발 플랫폼 및 언어/파이어베이스 Firebase

Angular - Firebase Firestore 데이터 바인딩

인디개발자 2020. 12. 15. 14:11

Angular 를 가장 잘 활용하려면 역시 Google 의 Firebase 를 이용하는 것이다. Angular - Node - Firebase 의 연결성으로 우리는 웹 어플리케이션을 만들고자 할 때 최상의 환경을 경험하게 된다.

우리는 이번 포스팅에서 Angular 의 데이터 바인딩 기능을 배울 수 있다.

준비사항 : Angular 에서 jquery, jquery.backstretch 사용하기 포스팅에 있는 Angular 프로젝트를 기본으로 할 것이다. 따라서 해당 포스팅을 참조하여 습득하도록 한다.

 

Firebase 계정

본인의 Firebase 계정이 있어야 한다. 아직 계정이 없다면 지금 즉시 등록하길 바란다. 무료이며 구글 계정이 있다면 바로 계정을 생성할 수 있다.

firebase.google.com

Firebase 계정을 가지고 있다면 Firebase Console 에 접속 가능하다.

console.firebase.google.com

 

새로운 Firebase Project 생성

Firebase 에서 새로운 프로젝트를 하나 생성한다. MyProject 라는 이름의 프로젝트를 생성하자.

새로운 Firebase 프로젝트를 만들 수 있다

 

다음과 같이 MyProject 라는 이름으로 프로젝트를 만들기 시작한다.

여기에서 myproject-xxxxx 이라고 표시된 사항은 Firebase 의 전체 시스템에서 고유한 프로젝트 ID 를 구성하기 위해서 자동으로 뒤에 숫자하고 문자들이 난수로 들어가게 된다. 원한다면 해당 표시내용을 클릭하여 원하는 프로젝트 ID 로 수정할 수 있다. 필자는 myproject-study 로 바꾸어서 시작했다. 여러분은 아마도 다른 이름을 선택해야 할 것이다. 사실 이건 별로 중요하지 않다. 그냥 편한 프로젝트 이름으로 하면 된다.

[계속] 을 눌러서 디폴트 값으로 다음과 같은 화면까지 진행한다.

[프로젝트 만들기] 를 눌러 프로젝트를 생성하기 된다.

약간의 시간이 경과되면 (프로젝트 생성의 프로그래스 표시 확인) 다음과 같이 완료되었다는 메시지가 표시될 것이다.

[계속] 을 누르면 생성된 프로젝트의 데시보드가 다음과 같이 나타날 것이다. 우리는 Spark 요금제 (무료 요금제)를 사용할 것이다. 이것으로도 충분하다.

 

새로운 Web App 생성

Firebase 프로젝트에는 다양한 종류의 플랫폼을 지원할 수 있다. 그 중에서 우리는 이번 포스팅에서 웹앱을 이용한 데이터 바인딩을 다룰 것이므로 웹앱을 만들기로 하자.

위의 화면에서 </> 아이콘을 클릭하면 웹앱을 시작할 수 있다. 진행하면서 Firebase Hosting 을 추가할 수도 있지만 Hosting 은 다른 포스팅에서 다시 다루기로 한다.

앱 닉네임에 "MyWeb" 을 입력한 후 [앱 등록] 버튼을 이용하여 앱을 등록하도록 하자.

 

앱 등록이 완료되면 아래 그림과 같이 Firebase SDK 추가 관련 내용이 표시된다. 이 내용은 중요하며 가능하면 노출되지 않도록 주의 할 필요가 있다. 우리는 여기서 당장 해당 내용을 사용할 것은 아니므로 그냥 [콘솔로 이동] 버튼을 클릭하여 Firebase Console 로 이동하자.

Firebase Console 에 다음과 같이 등록한 웹앱 (MyWeb) 이 표시되며, 하나의 프로젝트에 여러가지의 앱을 추가로 등록할 수 도 있다.

 

궁극의 목적

우리는 이전 포스팅에서 다음과 같은 웹 화면을 출력하였다.

이번 포스팅에서 우리는 "처음 만드는 Angular 페이지" 라는 문구를 서버의 데이터베이스를 참조하여 웹 화면에 출력하려고 한다. 또한, 웹 화면의 하단에 문구 입력란을 추가하여 이용자가 문구를 변경할 수 있도록 할 예정이다.

이를 이용하여 데이터 바인딩이 어떤 뚯인지와 데이터베이스의 내용을 웹 화면과 바인딩 시키는 방법에 대하여 알게 되는게 목적이다.

 

Cloud Firestore 준비

앞전에 우리는 자신의 Firebase 계정을 만들고 MyProject 라는 프로젝트를 생성하였다.

이제 여러분들은 다음과 같이 Cloud Firestore 를 선택하여 데이터 베이스를 만들 준비가 되어 있는 것이다.

[데이터베이스 만들기] 버튼을 클릭하여 진행하면 가장 먼저 마주하게 되는 내용이 다음과 같은 내용이다.

(O) 프로덕션 모드에서 시작을 하도록 하자. 테스트 모드에서 시작을 해도 무방하지만 우리의 목적은 서비스를 만들고 이를 프로덕션으로 배포하는것이 최종 목적일 수 있기 때문이다.

그 다음 우리가 선택할 일은 다음과 같이 데이터베이스가 위치할 지역을 선택하게 된다.

우선 연습 과전에서는 기본으로 선택되어진 지역으로 선택하자. 다른 지역으로 선택하면 거의 대부분 유료 플랜을 가져야만 할 것이므로 연습하기에는 적합하지 않다. 나중에 진짜 프로덕션 프로젝트를 진행할 때는 지역을 잘 선택해야 한다. 한번 선택하면 변경할 수 없기 때문이다.

[사용 설정] 버튼을 클릭하면 "Cloud Firestore 프로비저닝 중..." 이라는 표시가 나오면서 조금 기다리면 완료될 것이다.

짜잔~~~~

이제. 위와 같은 화면이 나왔다면 자신의 MyProject 에 Cloud Firestore 데이터베이스가 생성되었음을 의미 한다.

 

Firestore 규칙 설정

우리는 개발하는 과정에서 외부 개발용 컴퓨터에서 접근할 수 있도록 Firestore 의 규칙 (룰) 을 설정해야 한다.

다음을 참조하여 규칙을 설정하자. 기존 내용중에서 if false; 를 if true 로 변경하면 된다. 하지만 이것을 개발할 때문 사용하자. 누구든지 쉽게 해당 데이터를 읽어가거나 함부로 수정하면 안되기 때문이다. 정확한 설정은 향후 Firebase 보안 규칙 사항을 따르도록 하자.

 

Firestore 는 No-SQL 의 Database 이다. Query 를 수행할 수 있지만 그것이 우리가 일반적으로 알고있는 Database 의 SQL 구문하고는 다르기 때문에 유의할 필요가 있다.

Firestore 는 크게 다음과 같은 기본 구조를 갖는다.

  • 컬렉션 (Collection) - 문서 (Document) - 필드 (Field)

문서 아래에는 새로운 컬렉션을 둘 수도 있다.

필드는 데이터 필드라고 생각하면 된다. 실제 데이터는 필드가 담고 있게 된다.

"+ 컬렉션 시작" 이라는 항목을 클릭하여 다음과 같은 WEB - HOME - TITLE = "파이어베이스에서 설정한 웹페이지 타이틀" 을 구성해 보자. 여러분이 여기까지 온것은 이러한 웹 과정은 이제 별도로 설명하지 않아도 손쉽게 할 수 있을 정도라고 판단하겠다.

 

웹 페이지 적용

이제 우리의 목표를 본격적으로 실현 해보자.

앞의 포스팅에서 다뤘던 Angular 에서 jquery, jquery.backstretch 사용하기 에서 우리는 MyProject 라는 Angular 프로젝트를 기억할 것이다.

 

 

Angular 프로젝트에 Firebase 모듈 설치

Angular 프로젝트에서 @angular/fire 와 firebase 모듈을 설치해야 한다.

터미널 (Terminal, 이전 포스팅에서 우리는 Visual Studio Code 의 터미널에 대해서 익혔다) 을 하나 추가로 열어서 다음과 같은 명령라인을 입력한 후 실행한다.

npm install firebase @angular/fire

큰 문제가 없다면 대략 위와 같은 진행이 되었을 것이다.

 

Angular 프로젝트에 Firebase 연결

Firebase 에 아무나 접속할 수 있다면 보안상 큰 문제가 된다. 우리는 자신의 Angular 프로젝트에 자신의 Firebase 를 접근할 수 있는 무엇인가를 해야만 한다.

다시, 자신의 Firebase 를 접속해서 다음의 과정을 수행한다.

"프로젝트 개요"의 "오른쪽 톱니바퀴 아이콘"을 클릭하여 "프로젝트 설정"을 클릭하여 들어가는 설정 화면 아랫쪽으로 이동한다.

웹앱의 MyWeb 이라는 항목을 앞전에 이미 생성한 기억이 있을 것이다.  여기에서 "Firebase SDK snippet" 라는 항목에서  (O) 구성 을 선택한다.

그 내용을 우리는 클립보드로 복사를 하여 다음과 같은 Angular 프로젝트에 적용 한다.

environment.prod.ts

environment.ts

 

 

Angular 프로젝트에 Firebase 코드 추가

이제 다음을 참조하여 자신의 Angular 프로젝트에 코딩 작업을 진행한다.

아래 내용에서 1. 2. 3 항목을 진행하면 된다.

src/app/app.module.ts

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

// 1. Import the firebase libs you need
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFireModule } from '@angular/fire';
import { AngularFireDatabaseModule } from '@angular/fire/database';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireStorageModule } from '@angular/fire/storage';

// 2. Add your enviroment
import { environment } from '../environments/environment';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    // 3. Imports needed Firebase Modules in your Angular
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFireDatabaseModule,
    AngularFireStorageModule,
    AngularFirestoreModule, // imports firebase/firestore, only needed for database features
    AngularFireAuthModule,  // imports firebase/auth, only needed for auth features

    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

이쯤에서 Angular 의 ng serve 를 다시 실행하여 에러가 있는지 여부를 확인하길 바란다. 작업 과정에서 오류가 발생이 있다면 미리 처리한 후 다음으로 넘어가야만 진행이 매끄러울 수 있기 때문이다.

 

 

Firestore Service 코드 생성

이제 Angular 에서 중요한 역할을 하는 Service 를 만들어 볼 것이다. Service 는 Component 와 함께 Angular 에서 가장 많이 사용하는 소스 모듈중의 하나이다.

Angular 의 ng 명령으로 다양한 코드를 생성할 수 있다. 주의할 점은 자신의 Angular 프로젝트 메인 디렉토리 안에서 작업해야 한다. 참고로 Visual Studio Code 의 터미널을 새로 열면 항상 해당 Angular 프로젝트의 메인 디렉토리에서 시작하도록 되어 있다.

터미널에서 다음과 같은 명령라인을 수행하다.

ng generate service service/firestore

다음과 같이 Angular 프로젝트에 service 폴더에 firestore service 코드가 추가되었을 것이다.

 

다음의 내용을 참조하여 코드를 적용한다.

 

app.module.ts

다음 내용에서 Firebase Service 관련 항목을 적용한다.

// Firestore Service 추가
import { FirestoreService } from './service/firestore.service';
  providers: [
    // Firestore Service 제공
    FirestoreService
  ],

 

firestore.service.ts

import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';

@Injectable({
  providedIn: 'root'
})
export class FirestoreService {
  constructor(
    private firestore: AngularFirestore
  ) { 

  }

  // Firestore 의 WEB / HOME 내용이 변경되는것을 감지한다.
  getWebHomeTitle() {
    let doc = this.firestore.collection('WEB').doc('HOME')
    return doc.snapshotChanges();
  }
  // Firestore 의 WEB / HOME 내용을 업데이트 한다.
  updateWebHomeTitle(title: string) {
    let doc = this.firestore.collection('WEB').doc('HOME')
    return new Promise<any>((resolve, reject) => {
      doc.update({'TITLE': title}).then(res => resolve(res), err => reject(err));
    });
  }
}

 

app.component.ts

다음 내용을 참조하여 코드를 적용한다.

import { Component, OnInit } from '@angular/core';
import { FirestoreService } from './service/firestore.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  title = '처음 만드는 Angular 페이지';

  constructor(    
    private firestoreService: FirestoreService
  ) {
    this.firestoreService.getWebHomeTitle().subscribe(data=>{
      if(data.type=="added") {
        this.title = data.payload.get("TITLE");
      } else 
      if(data.type=="modified") {
        this.title = data.payload.get("TITLE");
      } else
      if(data.type=="removed") {
        this.title = "서버에서 삭제됨";
      } 
    });
  }

  onTitleApply(event: any) {
    this.firestoreService.updateWebHomeTitle($("#titleInput").val().toString())
      .then(res => {
        console.log("성공!!!");
      }, err => {
        console.log("실패!!! : " + err);
      });
  }

  ngOnInit(): void {
    $["backstretch"]([
      "../assets/bg1.jpg",
      "../assets/bg2.jpg",
      "../assets/bg3.jpg",
      "../assets/bg4.jpg",
      "../assets/bg5.jpg",
      "../assets/bg6.jpg",
      "../assets/bg7.jpg",
      "../assets/bg8.jpg",
      "../assets/bg9.jpg",
    ], {duration: 3000});
  }
}

 

app.component.html

<div>{{title}}</div>
<div>
    <input id="titleInput" type="text" placeholder="새로운 제목을 입력하세요" size=40 value="{{title}}">
    <br>
    <input id="titleApply" type="submit" value="적용" (click)="onTitleApply($event)">
</div>

 

이제 웹 화면이 다음과 같이 표시되는지 확인하자.

만약 정상적으로 표시되지 않으면 ng serve 를 다시 수행하여 문제가 있는지를 확인하는 절차를 해야 한다. 참고로 Angular 에서 새로운 Component 등이 추가되거나 컴파일 환경이 변경 되었을 경우 다이나믹 컴파일에 오류가 있을 수 있다. 이럴때는 Ctrl+C 로 기존 ng serve 를 빠져 나와서 새로 ng serve 를 시작하면 대부분의 문제는 해결된다.

 

Firestore 에서 데이터를 변경 => WEB 페이지 실시간 반영

우리는 일련의 Firebase 작업과 Firestore 의 데이터 작업 그리고 Angular 의 코딩 작업 등을 통해서 서버에 있는 데이터를 웹 브라우저의 페이지에 표시하는 내용을 습득 하였다.

이제, 웹 브라우저에서 웹 페이지를 열어놓은 상태에서 Firestore 에 있는 해당 데이터의 값을 바꿔보자.

위와 같이 TITLE 필드를 "변경한 타이틀" 이라고 수정하여 [업데이트] 한다.

다음과 같이 웹브라우저에 표시되는 내용이 즉시 변경됨을 알 수 있을 것이다.

지금까지 우리는 서버의 데이터를 웹브라우저에 표시하는 단방향 데이터 바인딩 (서버 to 클라이언트) 을 실현해 보았다. 이것은 서버의 다양한 데이터를 웹브라우저에 실시간 표시하는 기능을 구현하는데 사용된다.

예를 들어, 서버의 게시판 목록을 웹브라우저를 통해서 자사 웹페이지에 표시하거나, 혹은 더 나아가 날씨 관련 위젯을 만들수도 있을 것이다.

 

웹브라우저에서 데이터를 변경하여 서버의 데이터 변경

우리는 이제 클라이언트 (웹브라우저 등) 에서 데이터를 변경하여 이를 서버에 저장하는 방법이 필요하다. 즉, 클라이언트의 데이터 변경 내용을 실시간으로 서버에 업데이트하는 기술이 된다.

우리는 앞서서 HTML 부분에 다음과 같은 부분도 추가되어 있음을 알 수 있다. 여기서 titleInput 는 글자를 입력하는 부분이며 titleApply 는 버튼 부분으로 표시될 것이다.

<div>
    <input id="titleInput" type="text" placeholder="새로운 제목을 입력하세요" size=40 value="{{title}}">
    <br>
    <input id="titleApply" type="submit" value="적용" (click)="onTitleApply($event)">
</div>

특히, titleInput 부분의 value 부분에 {{title}} 형식으로 입력하였다. 이것은 ts 소스파일의 변수를 표시하게 하는 Angular 의 구현 규칙이다. HTML 에 {{  }} 형식으로 둘러쌓인 부분이 변수 이름이 들어가며 해당 변수의 값이 표시되는 것이다.

또한 titleApply 부분의 (click) 부분과 같이 ( ) 로 둘러 쌓인 부분은 이벤트 이름이 들어간다. 이벤트 이름은 JavaScript 의 이벤트 이름과 같다. onclick 의 앞부분 on 을 제외한 click 부분을 ( ) 로 둘러쌓아서 선언하게 된다.

이벤트의 뒷쪽에는 실행할 ts (Type Script) 의 함수명을 넣으면 된다. 즉, titleApply 버튼을 클릭하면 onTitleApply 함수가 실행되는 것이다.

 

웹에서 입력한 값을 서버에 업데이트

titleInput 의 입력창에 값을 입력한 후 titleApply 버튼을 클릭해 보자. 아래 그림과 같이 "웹에서 입력한 타이틀" 을 입력한 후 [적용] 버튼을 클릭한다. 즉시, 윗쪽의 표시도 입력한 문장으로 변경된 것이다.

 

Firestore 서버의 값을 확인해 보자. 다음과 같이 TITLE 값이 입력한 값으로 업데이트 되어 있게 된다.

 

firestore.service

이제 우리는 위와 같은 동작이 가능하게 하는 firestore service 에 대해서 알아보자.

firestore service 에서 다음의 함수들이 이를 수행하는 역할의 함수이다.

import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';

@Injectable({
  providedIn: 'root'
})
export class FirestoreService {
  constructor(
    private firestore: AngularFirestore
  ) { 

  }

  // Firestore 의 WEB / HOME 내용이 변경되는것을 감지한다.
  getWebHomeTitle() {
    let doc = this.firestore.collection('WEB').doc('HOME')
    return doc.snapshotChanges();
  }
  // Firestore 의 WEB / HOME 내용을 업데이트 한다.
  updateWebHomeTitle(title: string) {
    let doc = this.firestore.collection('WEB').doc('HOME')
    return new Promise<any>((resolve, reject) => {
      doc.update({'TITLE': title}).then(res => resolve(res), err => reject(err));
    });
  }
}

여기에서 우리가 사용한 대부분의 문장은 Type Script 언어로 짜여져 있다. 하지만 해당 문장은 대부분 JavaScript 언어이다. TypeScript 는 JavaScript 형식의 프로그래밍을 좀더 조직적으로 혹은 구조적으로 짤 수 있게 해주는 역할을 할 뿐이다. 대부분 JavaScript 의 형식을 따르게 된다.

다음 포스팅에서 우리는 좀더 강력한 Firebase 관련 함수들을 배우게 될 것으로 생각된다.

 

반응형
Comments