앵귤러 튜토리얼 (Angular tutorial) -21 with 파이어 베이스
* 제가 다시 작성한 최신 튜토리얼 수정본 입니다. 아래 주소를 통해서 진행하시는 것을 권장 드립니다. ^^
앵귤러 튜토리얼(Angular tutorial) - 1
안녕하세요. 앵귤러에 대해서 알아보기위해 이곳을 찾아주신 분 들께 감사의 말씀 드립니다.^^ 천천히, 초심자도 조금 더 쉽게 접근할 수 있도록 내용을 구성하여 보겠습니다. 어��
lts0606.tistory.com
이번시간에는 삭제 기능에 대해 알아보도록 하겠다.
삭제기능은 저번시간에 하였던 update라는 기능과 거의 동일하다.
저번시간에 살펴본 기능에서 문제점은 모두 수정되는 점이 문제였다면 이번시간에도 그냥 단순하게 삭제기능을 구현한다면 마찬가지 문제가 발생 할 것 이다.
그렇다면 수정 및 삭제를 위한 고유 ID값은 어떻게 가져와야 하는 것 인가?
2가지 방법으로 나누어 볼 수 있다.
먼저 첫번째는 사용자에 의해서 임의의 ID값을 주는 방법이다.
//...생략
constructor(db : AngularFirestore,strg : AngularFireStorage) { //모듈에서 만들어진 파이어 베이스 접속관련 객체
this.DataBase = db;
this.storage = strg;
this.getItem('board').subscribe((res)=>{ //리스트를 조회하는 구독행위
console.log(res);
});
this.setItem('board',{name:'NAME',number:1234,idx:this.makeID(30)}); //삭제를 위해 idx라는 속성을 추가
}
makeID(length) { //랜덤 ID를 만드는 메소드
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
위 방법데로 한다면 idx라는 속성을 만들어서 추가한다음에 KEY 형식으로 사용하는 방법이다.
즉 key를 직접 만들어 적용하는 점 이다.
두번째 방법으로, 파이어베이스 데이터베이스에서 고유로 만들어진 ID를 사용하는 것 이다.
해당 ID는 데이터를 가져오는 부분을 변경해서 사용 할 수 있다.
//..생략
getItem(db_name : string){
var items : BehaviorSubject<any[]> = new BehaviorSubject([]);
//this.getCollections(db_name).stateChanges(); //기존방식
return this.getCollections(db_name).stateChanges().pipe(map( changes => { //바꾼 방식
return changes.map(a=>{
const ID = a.payload.doc.id;
const data = a.payload.doc.data() as any;
return {data:data,idx:ID};
});
}))
}
두번째 방법으로 사용하면 키를 가져오는 점이 쉽긴한데..구독상태를 바꾸고 조립하는 복잡한 과정이 들어가야한다..
음..쉽게 이야기 하면 첫번째 방법이 두번째 방법보다 쉽다는 점 이다.
여기서는 첫번째 방식으로 구현하여 보겠다.
삭제 함수는 기존의 수정하는 함수와 거의 동일하다.
//..생략
deleteItem(db_name : string, key: any){
var subscription = this.getCollections(db_name).stateChanges().pipe(map( changes => { //pip 함수는 map 함수를 붙여주는 역할을 한다.
return changes.map(a=>{ //map 함수는 데이터의 내용을 바꾸는 역할을 한다.
const data = a.payload.doc.data() as any;
const ID = a.payload.doc.id; //고유 아이디 값
if(data.idx == key){ // idx는 사용자가 만들어준 키 값 이다.
this.getCollections(db_name).doc(ID).delete(); //key를 통해 삭제한다.
}
return data;
});
})).subscribe((oo)=>{ //해당 수정행위를 구독한다.
subscription.unsubscribe(); //getItem 함수를 통해 구독을 하고 있기 때문에 여기서 수정한 구독행위는 바로 종료시킨다.
});
}
수정함수랑 거의 동일한 것을 볼 수 있다. 그렇다면 실제 삭제를 하여보자.
간만에 html에 노드를 추가하고 클릭이벤트를 통해서 삭제하는 기능을 구현하여 보자.
app.component.ts에서 데이터를 구독하는 생성자 부분을 바꾸도록 하자.
//..생략
private list : any = new Array(); //리스트
constructor(db : AngularFirestore,strg : AngularFireStorage) { //모듈에서 만들어진 파이어 베이스 접속관련 객체
this.DataBase = db;
this.storage = strg;
this.getItem('board').subscribe((res : any)=>{ //리스트를 조회하는 구독행위
this.list = res;
});
}
위 내용에서의 핵심은 getItem을 통해서 가져온 데이터늘 list라는 변수를 바꾸어주는 점 이다.
app.component.html 파일에 리스트 목록을 추가하여본다.
<div>-s-</div>
<table>
<tr *ngFor='let items of list;let i = index' >
<td *ngIf="items" (click)='deleteItem("board",items.idx)'>{{items.text}}</td>
</tr>
</table>
<div>-e-</div>
우앗...다 된거 같다. 막상실행 하여 보면 동작을 하지 않는다. 왜냐하면 idx라는 값을 가진 속성이 없기 때문이다.
테스트용 데이터를 몇개 넣어주자.
최종 app.component.ts모습이다.
import { Component } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { BehaviorSubject } from 'rxjs';
import { AngularFireStorage} from '@angular/fire/storage';
import { map } from "rxjs/operators"; // map이다.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'testFire';
//데이터 베이스 관련 객체
private DataBase : AngularFirestore;
//컬렉션을 담아두는 배열
private collections = new Array();
//나중에 쓸 저장소 관련 객체
private storage : AngularFireStorage;
private list : any = new Array();
//의존성 주입
constructor(db : AngularFirestore,strg : AngularFireStorage) { //모듈에서 만들어진 파이어 베이스 접속관련 객체
this.DataBase = db;
this.storage = strg;
//샘플 데이터를 넣어주는 모습
this.setItem('board', {text:'test1', number:1,idx:this.makeID(30)});
this.setItem('board', {text:'test2', number:2,idx:this.makeID(30)});
this.setItem('board', {text:'test3', number:3,idx:this.makeID(30)});
this.setItem('board', {text:'test4', number:4,idx:this.makeID(30)});
this.getItem('board').subscribe((res : any)=>{ //리스트를 조회하는 구독행위
console.log(res);
this.list = res;
});
}
//컬렉션이 있는지 조사해서 해당 내용을 리턴하는 함수
getCollections (db_name : string) : AngularFirestoreCollection<any>{
var result = this.collections[db_name]; //배열에 값을 확인
if(result == undefined || result == null){ //배열에 값이 비어있다면
this.collections[db_name] = this.DataBase.collection<any>(db_name, (ref) =>ref); //새로 만들어준다.
result = this.collections[db_name];
}
return result;
}
getItem(db_name : string){
var items : BehaviorSubject<any[]> = new BehaviorSubject([]);
this.getCollections(db_name).valueChanges().forEach((val)=>{ //데이터를 가져오기
items.next(val);
});
return items;
}
setItem(db_name : string, param : any){ //데이터 등록
this.getCollections(db_name).add(param);
}
updatItem(db_name : string, param: any){
var subscription = this.getCollections(db_name).stateChanges().pipe(map( changes => { //pip 함수는 map 함수를 붙여주는 역할을 한다.
return changes.map(a=>{ //map 함수는 데이터의 내용을 바꾸는 역할을 한다.
const data = a.payload.doc.data() as any;
const ID = a.payload.doc.id; //고유 아이디 값
this.getCollections(db_name).doc(ID).update(param); //id 값을 통해 수정한다.
return data;
});
})).subscribe((oo)=>{ //해당 수정행위를 구독한다.
subscription.unsubscribe(); //getItem 함수를 통해 구독을 하고 있기 때문에 여기서 수정한 구독행위는 바로 종료시킨다.
//만약 해당 구독행위를 종료하지 않으면 구독행위가 다중 발생하여 무한loop 수정 행위가 발생한다.
});
}
deleteItem(db_name : string, key: any){
console.log(db_name, key);
var subscription = this.getCollections(db_name).stateChanges().pipe(map( changes => { //pip 함수는 map 함수를 붙여주는 역할을 한다.
return changes.map(a=>{ //map 함수는 데이터의 내용을 바꾸는 역할을 한다.
const data = a.payload.doc.data() as any;
const ID = a.payload.doc.id; //고유 아이디 값
if(data.idx == key){
this.getCollections(db_name).doc(ID).delete(); //key를 통해 삭제한다.
return data;
}
return data;
});
})).subscribe((oo)=>{ //해당 수정행위를 구독한다.
subscription.unsubscribe(); //getItem 함수를 통해 구독을 하고 있기 때문에 여기서 수정한 구독행위는 바로 종료시킨다.
});
}
makeID(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
}
그러면 여기서 수정하는 함수도 키를 통해서 1개만 바뀌도록 수정 할 수 있다.
updatItem(db_name : string, param: any, key:any){ //key 값 추가
var subscription = this.getCollections(db_name).stateChanges().pipe(map( changes => { //pip 함수는 map 함수를 붙여주는 역할을 한다.
return changes.map(a=>{ //map 함수는 데이터의 내용을 바꾸는 역할을 한다.
const data = a.payload.doc.data() as any;
const ID = a.payload.doc.id; //고유 아이디 값
if(data.idx == key){ //키 값이 동일하다면,
this.getCollections(db_name).doc(ID).update(param); //id 값을 통해 수정한다.
}
return data;
});
})).subscribe((oo)=>{ //해당 수정행위를 구독한다.
subscription.unsubscribe(); //getItem 함수를 통해 구독을 하고 있기 때문에 여기서 수정한 구독행위는 바로 종료시킨다.
//만약 해당 구독행위를 종료하지 않으면 구독행위가 다중 발생하여 무한loop 수정 행위가 발생한다.
});
}
여기까지 파이어베이스 데이터베이스를 활용하여 기본적인 읽기, 쓰기, 삭제하기에 대해서 살펴 보았다.
컴포넌트 1개에 너무많은 기능이 들어가있으면서 공통적으로 사용되는 기능이 다수 존재한다.
다음시간에는 이러한 공통 기능을 서비스로 분리하여 보도록 하자.