- 구현할 채팅방 리스팅 화면 입니다.
1. 코드 작성
1.1 채팅방 리스트 화면을 만들기 위해 다음 코드를 추가
/**
* 초기 필드 변수 할당
*/
FirebaseChat.prototype.init = function(){
//...생략
this.dvInputChat = document.getElementById('dvInputChat');
this.ulRoomList = document.getElementById('ulRoomList');
}
/**
* 로그인 후 세팅
*/
FirebaseChat.prototype.setLogin = function(user){ //user 파라미터 추
//...생략
this.loadRoomList(); //채팅방 목록불러오기
}
/**
* 두번째 탭 채팅방 목록리스트 호출
*/
FirebaseChat.prototype.loadRoomList = function(){
this.roomTemplate = document.getElementById('templateRoomList').innerHTML;
var roomRef = this.database.ref('UserRooms/'+this.auth.currentUser.uid);
roomRef.off();
roomRef.orderByChild('timestamp').on('value', this.getRoomList.bind(this))
}
/**
* loadRoomList 에서 데이터를 받아왔을 때
*/
FirebaseChat.prototype.getRoomList = function(snapshot){
var arrRoomListHtml = [];
var cbDisplayRoomList = function(data){
var val = data.val();
var arrRoomUserName = val.roomUserName.split(this.SPLIT_CHAR);
arrRoomUserName.splice(arrRoomUserName.indexOf(this.auth.currentUser.displayName), 1); // 방 제목 타이틀에서는 자신의 이름을 제외합니다.
var eachRoomTitle = arrRoomUserName.length > 1 ?
arrRoomUserName[0] + " 외 " + (arrRoomUserName.length - 1) + "명" : arrRoomUserName[0] +'님';
if(data.key === this.roomId && this.isOpenRoom){ //데이터 키가 현재 방ID와 같고 채팅방이 열려있는 경우에 현재 메세지 상단 제목을 갱신해줍니다.
this.spTitle.innerHTML = eachRoomTitle;
}
arrRoomListHtml.push( _.template(this.roomTemplate)({roomId : data.key, lastMessage:val.lastMessage,
profileImg : val.profileImg, roomTitle : eachRoomTitle, roomUserName:val.roomUserName,
roomUserlist: val.roomUserlist,
roomType : val.roomType, roomOneVSOneTarget : val.roomOneVSOneTarget,
datetime :FirebaseChat.timestampToTimeForRoomList(val.timestamp)}));
}
snapshot.forEach(cbDisplayRoomList.bind(this));
this.ulRoomList.innerHTML = arrRoomListHtml.reverse().join(''); // 역순 정렬
/**
* roomList 클릭 이벤트 적용
*/
var arrLiList = this.ulRoomList.getElementsByTagName('li')
var arrLiListLength = arrLiList.length;
for(var i=0; i < arrLiListLength; i++){
arrLiList[i].addEventListener('click', this.onRoomListClick.bind(this));
}
}
/**
* 룸리스트 클릭
*/
FirebaseChat.prototype.onRoomListClick = function(event){
this.aBackBtn.classList.remove('hiddendiv');
this.aInvite.classList.remove('hiddendiv');
// 메세지 로드
this.roomId = event.currentTarget.getAttribute('data-roomId');
this.roomTitle = event.currentTarget.getAttribute('data-roomTitle');
this.roomUserlist = event.currentTarget.getAttribute('data-roomUserlist').split(this.SPLIT_CHAR); // 챗방 유저리스트
this.roomUserName = event.currentTarget.getAttribute('data-roomUserName').split(this.SPLIT_CHAR); // 챗방 유저 이름
this.openChatRoom(this.roomId, this.roomTitle);
// 메세지 화면 이동
this.tabMessageList.click();
}
/**
* RoomList 화면 시간변환
*/
FirebaseChat.timestampToTimeForRoomList=function(timestamp){
var date = new Date(timestamp),
year = date.getFullYear(),
month = date.getMonth()+1,
day = date.getDate(),
hour = date.getHours(),
minute = date.getMinutes();
var nowDate = new Date(),
nowYear = nowDate.getFullYear(),
nowMonth = nowDate.getMonth()+1,
nowDay = nowDate.getDate(),
nowHour = nowDate.getHours(),
nowMinute = nowDate.getMinutes();
var result;
if(year === nowYear && month === nowMonth && day === nowDay){
result = FirebaseChat.pad(hour) +":" + FirebaseChat.pad(minute);
}else{
result = FirebaseChat.pad(year) +"-" + FirebaseChat.pad(month) + "-" + FirebaseChat.pad(day);
}
return result;
}
- 코드 설명
- 채팅방 목록을 불러오는 코드
- 로그인 인증이 완료된 후 수행되는 setLogin 메소드 안에서 loadRoomList메소드를 호출.
- loadRoomList메소드를 확인을 해보면 유저리스트와 는 다르게 메세지를 받을 때마다 목록을 갱신시켜 주기위해 once메소드가 아닌 on메소드를 사용.
- getRoomList메소드는 loadRoomList에서 채팅방 목록을 데이터를 받을 때마다 화면을 만드는 메소드. underscore라이브러리의 template 메소드로 화면을 그림.
- 채팅방 목록 데이터는 채팅방 상단 타이틀을 갱신하기 위한 용도로도 사용.
var arrRoomUserName = val.roomUserName.split(this.SPLIT_CHAR); arrRoomUserName.splice(arrRoomUserName.indexOf(this.auth.currentUser.displayName), 1); var eachRoomTitle = arrRoomUserName.length > 1 ? arrRoomUserName[0] + " 외 " + (arrRoomUserName.length - 1) + "명" : arrRoomUserName[0] +'님'; if(data.key === this.roomId && this.isOpenRoom){ //현재 메세지 상단 제목을 갱신해준다. this.spTitle.innerHTML = eachRoomTitle; }
- 방목록을 클릭을 하면 채팅방을 오픈해야하는데 채팅방을 오픈하기 위해서 필요한 정보를 미리 각각의 채팅방을 감싸는 li태그의 data 속성으로 값을 저장
<!-- template 채팅방리스트 영역 --> <script type="text/template" id="templateRoomList"> <li id="liRoom<%=roomId %>" data-roomId="<%=roomId %>" data-roomTitle='<%=roomTitle%>' data-roomUserName="<%=roomUserName%>" data-roomType="<%=roomType%>" data-roomOneVSOneTarget="<%=roomOneVSOneTarget%>" data-roomUserlist="<%=roomUserlist %>" class="collection-item avatar" > <img src="<%=profileImg ? profileImg : 'img/noprofile.png' %>" alt="" class="circle"> <span class="title"><%=roomTitle%></span> <p><%=lastMessage %></p> <a href="#!" class="secondary-content"> <%=datetime %></a> </li> </script>
- 채팅방을 오픈하는데 정보로 사용할 데이터 이외에 roomType이라는 데이터가 있는데, roomType은 ‘ONE_VS_ONE’ 또는 ‘MULTI’ 값입니다. 1대1 채팅방인지 아니면 3명이상이 사용하는 채팅방인지 구분하는 구분값입니다. 유저리스트에서 유저를 클릭할 시에 새로운 채팅방을 만들지 않고 채팅방 리스트 화면을 확인해서 채팅방을 오픈하기 위한 용도.
- Realtime Database에서는 아쉽게도 내림차순의 정렬이 없습니다.
- 보통 내림 차순을 위한 데이터를 저장을 하는 방법을 쓰거나 아래와 같이 데이터를 받아서 역순으로 정렬합니다. 최신의 메세지를 받은 채팅방을 가장 상위에 올리기 위해서 아래와 같이 배열 값을 반대로 바꾸었습니다.
this.ulRoomList.innerHTML = arrRoomListHtml.reverse().join(''); // 역순 정렬
- getRoomList 메소드 하단에는 채팅방을 클릭할 시 방을 오픈하는 동작을 하는 onRoomListClick 메소드가 바인딩
var arrLiList = this.ulRoomList.getElementsByTagName('li') var arrLiListLength = arrLiList.length; for(var i=0; i < arrLiListLength; i++){ arrLiList[i].addEventListener('click', this.onRoomListClick.bind(this)); }
- onRoomListClick 메소드는 채팅방 목록 화면에 저장해둔 data 속성들을 가지고와 채팅방을 오픈하는데 필요한 변수를 설정하고 채팅방을 오픈합니다.
1.2 유저리스트 화면 클릭시 채팅방 목록을 검색 후 오픈하는 기능을 추가하기위한 코드 수정
/**
* 유저리스트 클릭
*/
FirebaseChat.prototype.onUserListClick = function(event){
this.aBackBtn.classList.remove('hiddendiv'); // 백버튼 노출
this.aInvite.classList.remove('hiddendiv'); // 초대 버튼 노툴
var targetUserUid = event.currentTarget.getAttribute('data-targetUserUid');
var targetUserName = event.currentTarget.getAttribute('data-username');
var roomListTarget = document.querySelectorAll('[data-roomType="'+ this.ONE_VS_ONE+'"][data-roomOneVSOneTarget="'+ targetUserUid +'"]')[0];
if(roomListTarget){ // null 이 아니면
roomListTarget.click();
}else{
// 메세지 로드
this.roomTitle = targetUserName+'님';
this.roomUserlist = [targetUserUid, this.auth.currentUser.uid]; // 챗방 유저리스트
this.roomUserName = [targetUserName, this.auth.currentUser.displayName] // 챗방 유저 이름
this.roomId = this.MAKEID_CHAR + this.auth.currentUser.uid + this.DATETIME_CHAR + FirebaseChat.yyyyMMddHHmmsss();
this.openChatRoom(this.roomId, this.roomTitle);
}
}
- 코드 설명 :
- 아래 코드 구문이 채팅방 목록에서 1대1 타입의 채팅방 중에 클릭한 유저의 uid 를 찾는 코드
var roomListTarget = document.querySelectorAll('[data-roomType="'+ this.ONE_VS_ONE+'"][data-roomOneVSOneTarget="'+ targetUserUid +'"]')[0];
- 해당 타겟이 있다면 채팅방 목록에서 해당항목을 클릭하게되고, 아닌 경우는 새로운 채팅방을 오픈.
- 유저리스트에서 채팅방을 오픈하는 것과 채팅방리스트에서 채팅방을 오픈하는 것이 완성되었습니다.
1.3 채팅방 화면에서 뒤로 가기 버튼을 눌렀을 시에 동작을 구현을 위한 코드 작성
/**
* 유저리스트 클릭
*/
FirebaseChat.prototype.onUserListClick = function(event){
this.roomFlag ='tabUserList';
//...생략
}
/**
* 룸리스트 클릭
*/
FirebaseChat.prototype.onRoomListClick = function(event){
this.roomFlag ='tabRoomList';
//...생략
}
- 코드 설명 :
- 유저리스트에서 채팅방을 오픈하였는지 아니면 채팅방 리스트에서 채팅방을 오픈하였는지 구분 값이 필요
- 다시 코드 추가
/**
* 초기 필드 변수 할당
*/
FirebaseChat.prototype.init = function(){
//...생략
this.ORIGIN_TITLE = "Firebase-Tutorial";
}
/**
* 초기 이벤트 바인딩
*/
FirebaseChat.prototype.initEvent = function(){
//...생략
this.aBackBtn.addEventListener('click', this.onBackBtnClick.bind(this));
}
/**
* 백버튼 클릭
*/
FirebaseChat.prototype.onBackBtnClick = function(){
this.isOpenRoom = false;
this.aBackBtn.classList.add('hiddendiv');
this.aInvite.classList.add('hiddendiv');
document.getElementById(this.roomFlag).click();
this.spTitle.innerText = this.ORIGIN_TITLE;
this.ulMessageList.innerHTML='';
}
- 코드 설명 :
- 백버튼에 onBackBtnClick 메소드를 연결.
- onBackBtnClick메소드는 방 오픈 여부 상태값을 false로 변경하고, 백버튼과 초대 버튼을 숨기고, 채팅방 오픈 전 탭으로 되돌아가며, 상단타이틀을 복원하는 코드