파이어베이스 수정, 삭제하는 방법을 연구중입니다.
어째 잘 안되네요 ㅠㅠ
24.10.31 현황
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<style>
.allcard {
width: 1400px;
display: flex;
justify-content: center;
margin: 30px auto 0px auto;
}
.myteamcard {
height: auto;
width: auto;
padding: 15px;
border: 1px solid black;
border-radius: 5px;
background-color: whitesmoke;
margin: 24px 10px 0px 10px;
display: flex;
flex-direction: column;
align-items: center;
}
.myteamcard:hover {
background-color: rgba(0, 0, 0, 0.1);
cursor: pointer;
}
/*faceimge 랑 cardtext를 묶는 거.*/
.faceimge {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border: 1px solid black;
width: 175px;
height: 225px;
border-radius: 5px;
}
/*사진임*/
.cardtext {
margin: 0px 0px 0px 20px;
padding: 15px;
border: 1px solid black;
border-radius: 5px;
text-align: center;
background-color: white;
}
/*이름,mbti등*/
.cardtext2 {
margin-top: 20px;
padding: 15px;
border: 1px solid black;
border-radius: 5px;
width: 287px;
background-color: white;
}
/*장점등*/
.blog-link {
display: flex;
justify-content: center;
text-decoration: none;
color: black;
font-weight: bold;
}
.plsbt {
height: 500px;
width: 320px;
border-radius: 5px;
}
.plsbt:hover {
background-color: rgba(0, 0, 0, 0.1);
/* 약간 어두워짐 */
cursor: pointer;
}
.postingbtng {
height: 500px;
width: 330px;
}
/*위에 버튼 공간 잡는거 없으면 찌그러짐*/
/*이 밑은 카드 누르면 나오는 팝업창이므로 바꾸기.*/
.popup-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: none;
justify-content: center;
align-items: center;
}
.popup-content {
padding: 20px;
border-radius: 8px;
text-align: center;
/*box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);*/
background-color: rgb(108, 209, 162);
width: 1000px;
height: 600px;
/* margin: 30px; */
box-shadow: 0px 0px 30px 0px rgb(88, 163, 128);
}
.close-btn {
margin-top: 10px;
padding: 8px 16px;
background-color: blue;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
#imgsbox {
padding: 5px;
margin-right: 15px;
border-radius: 30px;
}
#infobox {
padding: 5px;
margin-left: 30px;
border-radius: 30px;
background-color: white;
}
#memberImg {
width: 300px;
height: 400px;
}
#link_img {
width: 100px;
height: 100px;
}
#blBtn {
margin: 10px 10px 0px 10px;
padding: 1px;
}
#infoup {
margin: 10px 10px 0px 5px;
border-radius: 10px;
height: 160px;
}
#infodown {
margin: 10px 10px 0px 5px;
border-radius: 10px;
height: 300px;
}
#info1 {
height: max-content;
}
#info2 {
background-color: rgba(108, 209, 162, 0.41);
border-radius: 10px;
height: 160px;
text-align: left;
}
#reviseBtn {
width: 90px;
margin: 10px;
padding: 3px;
}
#deleteBtn {
width: 90px;
margin: 10px;
padding: 3px;
}
#info3 {
height: 300px;
background-color: rgba(108, 209, 162, 0.41);
border-radius: 10px;
text-align: left;
}
</style>
<script type="module">
// Firebase SDK 라이브러리 가져오기
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
import { getFirestore, collection, addDoc, getDocs, deleteDoc, doc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
// import { getFirestore, doc, deleteDoc } from "https://www.gstatic.com/firebasejs/9.x/firebase-firestore.js";
//
import { getStorage, ref, uploadBytes, getDownloadURL } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-storage.js";
// Firebase 구성 정보 설정
const firebaseConfig = {
apiKey: "AIzaSyCGqR4KmttjxTiDXOgnAlq_zK85FfceU_4",
authDomain: "sparta-1aa54.firebaseapp.com",
projectId: "sparta-1aa54",
storageBucket: "sparta-1aa54.appspot.com",
messagingSenderId: "210610766907",
appId: "1:210610766907:web:f3553a0bb7e166be9c081e",
measurementId: "G-8ETLMBCMF2"
};
// Firebase 인스턴스 초기화
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const storage = getStorage(app);
let docs = await getDocs(collection(db, "members"));
docs.forEach((doc) => {
let row = doc.data();
let imageUrl = row['imageUrl'];
let name = row['name'];
let mbti = row['mbti'];
let hobby = row['hobby'];
let introduction = row['introduction'];
let strengths = row['strengths'];
let collaborationStyle = row['collaborationStyle'];
let resolution = row['resolution'];
let blogLink = row['blogLink'];
let temp_html = `
<div class="myteamcard">
<div class="card">
<img src="${imageUrl}"
class="faceimge">
ardtext">
<div class="cardtext">
<h5 class="card-title">이름<p>${name}</p>
</h5>
</div></div></div>`;
let cardElement = $(temp_html).insertBefore('#cardlist');
// 클릭 이벤트 핸들러 추가
cardElement.click(function () {
// $('#popup-name').text(name); // 클릭한 카드의 이름을 팝업에 설정
let temp_html = `
<div>
<div class="row">
<div id="imgsbox" class="col-3">
<div class="imgcard">
<img id="memberImg" src="${imageUrl}" class="card-img-top" alt="...">
<div>
<div class="row">
<!--블로그버튼-->
<button id="blBtn" type="button" class="col btn btn-outline-success">
<a href="${blogLink}" target="_blank" rel="noopener noreferrer">
<img id="link_img"
src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTq_V5ImHw0BTMnCJ4GSqBsDdD-bxLsyuCh4Q5V7XX2aiVuxCbTG6RT2151CA1-G6XaE7k&usqp=CAU"
class="card-img-top" alt="...">
</a>
</button>
</div>
</div>
</div>
</div>
<div class="col"></div>
<div id="infobox" class="col-8">
<div id="infoup" class="row">
<div id="info1" class="col-3">
<table class="table">
<thead>
<tr>
<th scope="col">이름</th>
<th scope="col">${name}</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">MBTI</th>
<td>${mbti}</td>
</tr>
<tr>
<th scope="row">취미</th>
<td>${hobby}</td>
</tr>
</tbody>
</table>
</div>
<div id="info2" class="col-5">
<ul class=" list-group">
<p>${introduction}</p>
</ul>
</div>
<div class="col">
<button id="reviseBtn" type="button" class="btn btn-outline-secondary">
<a href="/.addcard.html" class="text-muted">수정</a>
</button>
<!--
<button id="reviseBtn" type="button" class="btn btn-outline-secondary">
<a class="p-2 text-muted" href="/._includes\addcard.html">수정</a></button>-->
<button id="deleteBtn" type="button" class="btn btn-outline-secondary">삭제</button>
</div>
</div>
<div id="infodown" class="row">
<div id="info3" class="col-8">
<ul class=" list-group">
<p id="strengths" style="display: none;">${strengths}</p>
<p id="collaborationStyle" style="display: none;">${collaborationStyle}</p>
<p id="resolution" style="display: none;">${resolution}</p>
</ul>
</div>
<div class="col-2">
<div class="btn-group-vertical" role="group" aria-label="Vertical radio toggle button group">
<input type="radio" class="btn-check" name="vbtn-radio" id="vbtn-radio1" autocomplete="off"
checked>
<label id="strengthsBtn" class="btn btn-outline-danger" for="vbtn-radio1">장점</label>
<input type="radio" class="btn-check" name="vbtn-radio" id="vbtn-radio2" autocomplete="off">
<label id="resolutionBtn" class="btn btn-outline-danger" for="vbtn-radio2">각오</label>
<input type="radio" class="btn-check" name="vbtn-radio" id="vbtn-radio3" autocomplete="off">
<label id="collaborationStyleBtn" class="btn btn-outline-danger" for="vbtn-radio3">협업스타일</label>
</div>
</div>
</div>
</div>
</div>
</div> `
// 전역 변수로 PopCardElement 선언
let PopCardElement = $(temp_html).insertBefore('#popup_content');
//let PopCardElement = $(temp_html).insertBefore('#popup_content');
$('#popup').css('display', 'flex'); // 팝업 열기
$("#strengths").show();
$("#collaborationStyle").hide();
$("#resolution").hide();
console.log('팝업 열림');
})
});
// 수정화면으로 이동
$("#reviseBtn").click(function () {
$("#popup").css("display", "none");
console.log('수정화면으로 이동')
})
// 파이어베이스에서 해당 자료 삭제
$("#deleteBtn").click(async function (e) {
// e.preventDefault();
$("#popup").css("display", "none");
//if (name === `${name}`) {
//if (confirm("정말 삭제 하시겠습니까?")) {
//const docRef = doc(db, 'members', `${name}`);
//await deleteDoc(docRef);
console.log('삭제되었습니다.');
// window.location.href = './membercard.html';
//} else {
// return false;
//}
});
// 텍스트 -> 버튼으로 토글 사용하기
$("#strengthsBtn").click(function () { // 장점
$("#strengths").show();
$("#collaborationStyle").hide();
$("#resolution").hide();
});
$("#collaborationStyleBtn").click(function () { // 협업 스타일
$("#strengths").hide();
$("#collaborationStyle").show();
$("#resolution").hide();
});
$("#resolutionBtn").click(function () { // 각오
$("#strengths").hide();
$("#collaborationStyle").hide();
$("#resolution").show();
});
// 팝업 닫기 버튼 클릭 시 팝업을 닫습니다.
$("#clbtn").click(function () {
// PopCardElement.remove();
if (PopCardElement) {
PopCardElement.remove();
}
$("#popup_content").empty();
$("#popup").css("display", "none");
});
$(document).ready(function () {
$("#plsbtn").click(function () {
window.location.href = 'addcard.html';
});
});
//분리 안하면 작동을 안함;;
</script>
<script></script>
</head>
<body>
<div class="allcard">
<div class="row row-cols-1 row-cols-md-3 g-4">
<div class="postingbtng" id="cardlist">
</div>
</div>
</div>
<!-- 팜업창 -->
<div class="popup-overlay" id="popup">
<div class="popup-content">
<!-- <h4>팝업 창</h4>
<p>이름: <span id="popup-name"></span></p> -->
<div id="popup_content">
<button class="close-btn" id="clbtn">닫기</button>
</div></div>
</div>
</body>
</html>
> 오류1
팝업창을 닫은 뒤 멤버카드를 눌러 다시 팝업창이 뜰 때 이전 팝업창의 내용이 남아있습니다.
수정 완료
<button class="close-btn" id="clbtn">닫기</button>
// 팝업 닫기 버튼 클릭 시 팝업을 닫습니다.
$("#clbtn").click(function () {
document.getElementById("removePop").remove();
$("#popup").css("display", "none");
console.log(' $("#popup").css("display", "none");')
})
> 오류2
수정, 삭제버튼 오류
삭제버튼 해결함
where빼고 다시 시도해서 성공함
$(document).on("click", "button[name='delete']", async function () {
// Firestore의 "members" 컬렉션에서 모든 문서를 가져옵니다.
const membersSnapshot = await getDocs(collection(db, "members"));
// 가져온 문서 각각에 대해 ID와 데이터를 콘솔에 출력하고 일치하는 문서를 삭제합니다.
membersSnapshot.forEach(async (doc) => {
const row = doc.data(); // 해당 문서의 데이터를 가져옵니다.
const name = row['name'];
// name 필드가 data.name과 일치하는 경우
if (name === data.name) {
// 일치하는 문서를 삭제합니다.
await deleteDoc(doc.ref); // doc.ref로 문서 참조를 가져옵니다.
console.log(doc.id, " => ", row);
}
});
// 삭제 후 UI 업데이트
document.getElementById("removePop").remove();
$("#popup").css("display", "none");
alert('성공적으로 삭제되었습니다!');
});
> 오류3
장점, 협업, 창 전환 안됨. <- window.함수.function() {} 로 해결
시도
>오류1
팝업창이 닫히긴 하지만 여전히 이전정보 같이 보입니다.
// 팝업 닫기 버튼 클릭 시 팝업을 닫습니다.
$("#clbtn").click(function () {
$("#popup").css("display", "none");
// PopCardElement.find('#tempContent').remove();
PopCardElement = null; // 또는 PopCardElement = undefined;
$("#popup_content").empty();
console.log('$("#popup_content").empty();')
})
에러
membercard copy.html:414 Uncaught ReferenceError: PopCardElement is not defined
at HTMLButtonElement.<anonymous> (membercard copy.html:414:28)
at HTMLButtonElement.dispatch (jquery.min.js:2:43090)
at v.handle (jquery.min.js:2:41074)
> 오류2
스크립트 안에서 쓰는 코드가 작동되지 않습니다.
<body> 안의 코드만 작동됩니다,
일단 수정버튼은 페이지 이동만 가능하게 만들어 뒀습니다.
<div class="col">
<button id="reviseBtn" type="button" class="btn btn-outline-secondary" onclick="location.href='addcard.html'">수정</button>
<button onclick="console.log('수정화면으로 이동')" id="deleteBtn" type="button" class="btn btn-outline-secondary">삭제</button>
</div>
코드인식하는 방법을 찾았습니다.
window.reviseBtn = function() {
// 원하는 기능
console.log('페이지 이동')
};
window.deleteBtn = function() {
// 원하는 기능
console.log('삭제키 작동')
};
기능 (수정 멤버 정보 들고 페이지 이동, 해당 멤버 삭제) 추가하겠습니다.
삭제 코드 - '삭제중 오류 발생' . 파이어 베이스를 특정짓지 못한다고 하는데.. 이름이 팝업창과 일치하는 회원의 정보를 어떻게 삭제하지?
오류 메시지 : firebase is not defined
// 모듈 스크립트에서 전역 deleteBtn 함수 생성
window.deleteBtn = async function (name) {
try {
// Firestore의 'members' 컬렉션 참조
const membersRef = firebase.firestore().collection('members');
// 'members' 컬렉션에서 이름이 일치하는 문서 조회
const querySnapshot = await membersRef.where('name', '==', name).get();
// 문서가 있을 때 삭제 진행
if (!querySnapshot.empty) {
querySnapshot.forEach(async (doc) => {
await doc.ref.delete();
console.log(`멤버 ${name} 삭제 완료`);
});
} else {
console.log(`멤버 ${name}을 찾을 수 없습니다.`);
}
} catch (error) {
console.log('삭제 중 오류 발생:'+ error);
}
};
파이어베이스 초기화, 하는거 다 했는데 자꾸 오류가 뜸
TypeError: doc is not a function
at HTMLButtonElement.<anonymous> (cardmodal.html:399:24)
at HTMLDocument.dispatch (jquery.min.js:2:43090)
at v.handle (jquery.min.js:2:41074)
팀원들과 합치고 나서 팀원들의 파이어베이스 초기화를 믿고 다시 시도... 그치만 동일한 오류 발생
//// 삭제 버튼 클릭 함수
$(document).on("click", "button[name='delete']", async function () {
// firebase 데이터 다시 읽어오기
let membersDb = await getDocs(query(collection(db, "members"), orderBy("name")));
membersDb.forEach((docRef) => {
// 데이터 조리해서 가져오기
let row = docRef.data();
let name = row['name'];
if (name === `${data.name}`) {
deleteDoc(doc(db, "members", docRef.id))
alert('성공적으로 삭제되었습니다!');
$("#popup").css("display", "none");
} else {
//alert('잘못된 접근입니다.');
}})
문서 삭제 오류: TypeError: doc is not a function
at HTMLButtonElement.<anonymous> (cardmodal.js:141:40)
at HTMLDocument.dispatch (jquery.min.js:2:43090)
at v.handle (jquery.min.js:2:41074)
await를 사용해 deleteDoc가 실행될 때 까지 기다리 -> await 줄에서 오류가 발생했습니다.
$(document).on("click", "button[name='delete']", async function () {
// firebase 데이터 다시 읽어오기
let membersDb = await getDocs(query(collection(db, "members"), orderBy("name")));
for (let doc2 of membersDb.docs) { // forEach 대신 for..of 사용
let row = doc2.data();
let name = row['name'];
if (name === data.name) {
await deleteDoc(doc(db, "members", doc2.id)); // await 추가
document.getElementById("removePop").remove();
$("#popup").css("display", "none");
alert('성공적으로 삭제되었습니다!');
break; // 삭제 후 루프 종료
}
}
console.log('삭제 끝');
});
에러메시지
Uncaught (in promise) TypeError: doc is not a function
at HTMLButtonElement.<anonymous> (cardmodal.js:179:45)
(anonymous) @ cardmodal.js:179
await in (anonymous)
dispatch @ jquery.min.js:2
v.handle @ jquery.min.js:2Understand this errorAI
doc is not a function... doc가 아니라 doc2로 해야했을까? 파이어뱅이스 함수가 아니라 변수인걸까?
await deleteDoc(doc2(db, "members", doc2.id));
Uncaught (in promise) TypeError: doc2 is not a function
음.. 아니었음
where로 찾으려고 했는데 'where'를 import하니 오류가 생겼습니다.
$(document).on("click", "button[name='delete']", async function () {
//Firestore의 "members" 컬렉션에서 name 필드가 data.name과 같은 문서를 검색하는 쿼리를 생성합니다.
const q = query(collection(db, "members"), where("name", "==", data.name));
//생성한 쿼리를 실행하여 해당하는 문서들의 스냅샷을 가져옵니다.
const querySnapshot = await getDocs(q);
// 가져온 문서 각각에 대해 ID와 데이터를 콘솔에 출력합니다. doc.data()는 해당 문서의 데이터를 반환합니다.
querySnapshot.forEach((doc) => { // doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());})
document.getElementById("removePop").remove();
$("#popup").css("display", "none");
await deleteDoc(doc(db, "members", q.id));
alert('성공적으로 삭제되었습니다!');
// card modal.js
import {
db,
getDocs,
collection,
deleteDoc,
addDoc,
doc,
orderBy,
query,
where, // 오류발생
} from './firebase.js';
그리고 'where'를 추가하니 멤버 카드가 사라졌습니다.
where빼고 다시 시도
$(document).on("click", "button[name='delete']", async function () {
// Firestore의 "members" 컬렉션에서 모든 문서를 가져옵니다.
const membersSnapshot = await getDocs(collection(db, "members"));
// 가져온 문서 각각에 대해 ID와 데이터를 콘솔에 출력하고 일치하는 문서를 삭제합니다.
membersSnapshot.forEach(async (doc) => {
const row = doc.data(); // 해당 문서의 데이터를 가져옵니다.
const name = row['name'];
// name 필드가 data.name과 일치하는 경우
if (name === data.name) {
// 일치하는 문서를 삭제합니다.
await deleteDoc(doc.ref); // doc.ref로 문서 참조를 가져옵니다.
console.log(doc.id, " => ", row);
}
});
// 삭제 후 UI 업데이트
document.getElementById("removePop").remove();
$("#popup").css("display", "none");
alert('성공적으로 삭제되었습니다!');
});
성공!!!
이제 수정버튼만 남았습니다!!!
기억하기
◆ 변수 삭제
//let, const로 선언한 경우
PopCardElement = null; // 또는
PopCardElement = undefined;
//var로 선언한 경우
delete PopCardElement;
◆ id로 <dev> 삭제하기
document.getElementById("id이름").remove();
◆ 같은 폴더의 다른html 파일로 이동하기
<button type="button" onclick="location.href='second.html'">이동1</button>
<button type="button">
<a class="p-2 text-muted" href="/._includes/addcard.html">이동2</a></button>
◆ 제이쿼리(jQuery) 라이브러리와 다른 자바스크립트(javascript) 라이브러리를 동시 사용했을 때 발생하는 충돌 해결하기
1. 제이쿼리를 사용하기 전에 jQuery.noConflict() 이 메서드를 이용하여 $ 이 기호를 대처할만한 다른 변수에 저장합니다.
2. 다른 변수에 저장한 $jQ 변수를 제이쿼리 기호로 사용합니다.
사용은 무조건 제이쿼리를 사용하기 전에 jQuery.noConflict() 이 메서드를 이용하여 새로운 변수를 지정하여 사용해야합니다.
https://knowing-passion.tistory.com/66#google_vignette
jQuery.noConflict(); // 충돌방지
기존 $ 이 기호 하나를 이용해서 제이쿼리를 이용했는데 충돌이 일어나니 JQury $ 기호를 $jQ 이걸로 치환해서 사용합니다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script type="text/javascript">
var $jQ = jQuery.noConflict();
$jQ(document).ready(function(){
$jQ('h1').text('충돌방지 해결');
});
</script>
</head>
<body>
</body>
</html>
◆ 전역 객체를 활용하는 방법
모듈 스크립트(type="module")에서 정의한 함수나 변수는 기본적으로 모듈 스코프 내에서만 유효합니다. 즉, 다른 일반 스크립트나 jQuery로 동적으로 추가한 DOM 요소에서 모듈 스코프에 있는 코드를 바로 접근하기 어렵습니다
// module.js
window.someFunction = function() {
// 원하는 기능
};
<!--사용-->
<button onclick='someFunction()' ...
◆ 파이어베이스
https://duckgugong.tistory.com/208
◆ 파이어스토어 다큐멘트 삭제
const res = await db.collection('cities').doc('DC').delete();
◆ break; 오류 : 점프 대상은 함수 경계를 벗어날 수 없습니다.
https://hsly22xk.tistory.com/387
forEach()나 함수 등 for loop 바깥쪽에 break/continue를 사용하려고 할 때 발생하는 오류입니다.
◆파이어베이스 컬렉션의 여러 문서 가져오기
https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#web
import { collection, query, where, getDocs } from "firebase/firestore";
const q = query(collection(db, "cities"), where("capital", "==", true));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
◆
◆
◆
◆
◆
◆
◆
◆
◆
◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆
'내일배움캠프_게임서버(202410) > TIL,WIL' 카테고리의 다른 글
내일배움 Notion.js 7기 1주차 후기 (0) | 2024.11.01 |
---|---|
수정버튼만 만들면 된다 (0) | 2024.11.01 |
강의 먼저 볼걸 (0) | 2024.10.30 |
멤버소개 모달 만들기, 왕초보 4,5주차 수강 (2) | 2024.10.29 |
10/28 TIL - Node.Js_7기 본캠 첫날 (0) | 2024.10.28 |