티스토리 뷰
개발환경 : nodejs / mariaDB / JS / jqgrid
jqgrid : 그리드 조회, 수정, 추가, 삭제 전부 구현하기(1) - 그리드 조회
jqgrid : 그리드 조회, 수정, 추가, 삭제 전부 구현하기(2) - 그리드 수정
조회 / 수정을 했으니 추가를 구현 해 보자 !
처음에 그리드 조회 화면에서 추가버튼을 누르면 아래에 새로운 row 가 생기고 inline 형식으로 입력 후 저장버튼을 누르면 데이터가 저장되는 형식으로 만들려고 했으나 현재 셀 수정시 remote 형식을 사용하고 있기 때문에 row 추가할때 한셀 한셀이 입력되게 되는 문제가 있어서 추가할때 inline으로 바꿔주고 또 수정할땐 remote로 바꿔주고 할 수 없어서 추가 버튼 누르면 모달팝업이 떠서 입력 후 저장하는 방식으로 구현하기로 하였다.
일단 먼저 html 부분부터 수정하자. 첫번째 포스팅에서 html에 추가, 삭제 버튼을 만들어 줬는데 추가 버튼을 클릭했을 때 모달팝업이 뜰 수 있도록 이벤트를 걸어주자
<div class="main-panel">
<div class="content-wrapper">
<div class="row col-12 d-flex align-items-center justify-content-end">
<button class="btn onclick="javascript:gridFunc.addRow();">추가</button>
<button class="btn">삭제</button>
</div>
<div class="row ">
<div class="col-12 grid-margin">
<div class="card">
<div class="card-body">
<div class="table-responsive">
<table id="dataGrid"></table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
그리고 스크립트를 작성하자 !
버튼을 클릭하면 gridFunc.addRow 함수를 타게 되는데 editGridRow 메소드를 이용해서 모달 팝업을 띄우게 된다.
$("#dataGrid").jqGrid('editGridRow', "new", options );
여기에서 new 는 새로운 데이터를 생성한다는 의미이고 options에 이제 띄워질 모달팝업의 속성들과 이벤트를 넣어줄 수 있다.
그래서 options를 작성해보자
const gridFunc = {
addRow : function(){
const options = {
modal : true,
width : 400,
url : '/data/menumast/createGridData',
mtype : 'POST',
addCaption : "MENUMAST 추가",
closeAfterAdd : true,
recreateForm : true, //대화상자가 활성화될 때 마다 form이 다시 생성된다
reloadAfterSubmit:true //서버 ajax후 그리드 데이터 다시 로드
}
$("#dataGrid").jqGrid('editGridRow', "new", options );
}
}
modal : true 로 해야 모달이 뜬다
url : 모달 팝업에서 데이터 입력 후 전송 눌르면 전송되는 url
closeAfterAdd : true Add 후 모달이 자동으로 닫힌다
recreateForm : true 모달이 생성될 때 마다 form이 새로고침된다.(안그러면 데이터 남아있음)
reloadAfterSubmit : true 추가 후 reload 자동으로 해줌
이게 모달팝업이 띄워졌을때 기본적으로 설정해준 속성들이다.
이제 모달팝업이 떴을 때 입력가능한 데이터들은 기본적으로 그리드에 띄운 colName들인데. 이걸 colModel 속성에서 정의해 줘야 한다.
예를 들면 처음에 colModel 을 선언할 때에 아래와 같이 한다고 하면 여기 속성에다가 editable : true 를 넣어주면 팝업 띄웠을 때 수정 가능하도록 나오게 된다. 그런데 이 속성을 처음부터 주면 문제가 생기는데 (나의 경우에) editable : true를 주면 모달팝업 뿐 아니라 그리드 내에서 클릭시 바로 수정 가능한 Input 박스를 띄워주게 된다.
var gridColModel = [
{name:'chkbox', index:'chkbox', align:'center', width:'3%', edittype:'checkbox', editoptions:{value:'Y:N'}, formatter:'checkbox', formatoptions: {disabled: false}}
]
그리드 수정시에 봤듯 editable 속성을 처음에 주지 않고 있다가. 더블클릭시 클릭한 colName의 속성을 editable : true 로 바꿔준것을 기억할 수 있을 것이다.
그래서 현재 editable 속성이 없기 때문에 모달 팝업을 띄우면 입력 요소들이 나오지 않는다.
Form 데이터들을 초기화 하기 전에 호출되는 beforeInitData 메소드를 사용해서 editable : true 속성을 주자.
beforeInitData : function(formid){ //form 데이터를 초기화 하기 전에 호출
$("#dataGrid").setColProp("group_code", {editable : true});
}
이런식으로 입력값을 받아야 하는 모든 컬럼에 대하여 setColProp를 해주어야 하는데
나의 경우에는 7개의 컬럼 모두의 값을 받아와야 하고 또 모달이 닫힌 후에는 editable 속성을 false로 또 바꿔줘야 하는데 그때마다 7개의 컬럼을 모두 바꾸는게 비효율적이라고 생각해서 함수를 따로 빼서 boolean 값을 전달하게 하였다.
function setColData(param){
const gridColData = ["group_code", "prog_id", "depth_lv", "prog_name", "prog_url", "order_no", "view_yn"];
for(var idx in gridColData){
$("#dataGrid").setColProp(gridColData[idx], {editable : param});
}
}
const gridFunc = {
addRow : function(){
const options = {
modal : true,
width : 400,
url : '/data/menumast/createGridData',
mtype : 'POST',
addCaption : "MENUMAST 추가",
closeAfterAdd : true,
recreateForm : true, //대화상자가 활성화될 때 마다 form이 다시 생성된다
reloadAfterSubmit:true, //서버 ajax후 그리드 데이터 다시 로드
beforeInitData : function(formid){ //form 데이터를 초기화 하기 전에 호출
setColData(true);
}
}
$("#dataGrid").jqGrid('editGridRow', "new", options );
}
}
setColData(true) 를 주어 컬럼들에 editable : true 속성을 주면 팝업이 생성되면서 입력할 수 있는 컬럼들이 보이게 된다.
그럼 이제 submit 전에 입력 값을 validation 할 수 있는 beforeSubmit과
완료 후 성공/실패를 반환하는 afterComplete, 취소버튼을 눌렀을 때 닫히는 메소드인 onClose를 구현하자
beforeSubmit : function(postdata, formid){
/* 입력 값 validation*/
if(postdata.group_code.length>2){
return [false, "그룹코드의 입력값은 두자리 입니다."];
}
if(postdata.prog_id.length>10){
return [false, "프로그램 아이디는 10자리를 넘을 수 없습니다."];
}
if(postdata.prog_name.length>50){
return [false, "프로그램명은 50자리를 넘을 수 없습니다."];
}
if(postdata.prog_url.length>50){
return [false, "프로그램 URL은 50자리를 넘을 수 없습니다."];
}
/*group_code === prog_id (_)이전 값 */
const progid = postdata.prog_id.split('_');
console.log(progid);
if(postdata.group_code!==progid[0]){
return [false, "그룹코드와 프로그램 ID의 코드는 동일해야 합니다."];
}
const rowData = $("#dataGrid").getRowData();
/*prog_id 중복확인 */
for(const idx in rowData){
if(rowData[idx].prog_id===postdata.prog_id){
return [false, "프로그램 ID는 중복값을 가질 수 없습니다."];
}
}
// const progIdArr = [];
// for(const idx in rowData){
// progIdArr.push(rowData[idx].prog_id);
// }
// let progIdCnt = progIdArr.reduce((cnt, element)=>cnt +(postdata.prog_id=== element),0);
// if(progIdCnt>=1){
// return [false, "프로그램 ID는 중복값을 가질 수 없습니다."];
// }
/*depth_lv===1일때 존재하는 상위메뉴 체크 */
if(postdata.depth_lv==='1'){
// const depthLvArr = [];
for(const key in rowData){
if(rowData[key].group_code===postdata.group_code && rowData[key].depth_lv===postdata.depth_lv){
return [false, "상위 메뉴가 이미 존재합니다. 메뉴레벨을 변경 해 주세요."];
}
}
}
return [true, ''];
},
afterComplete : function(response, postdata, formid){
setColData(false);
if(response.responseText==='success'){
alert("등록되었습니다 !");
}else{
alert("에러 발생 !\nerrMsg : "+response.responseText);
}
},
onClose : function(){
setColData(false);
}
beforeSubmit : submit 전에 input 값들의 validation 체크를 할 수 있다. 기본적인 속성에서 validation 체크를 해주는데 colModel 부분에 editrules를 추가를 해 주면 된다. required: true (필수 입력값) number:true (숫자만 입력 가능) 등등 속성이 많다..
var gridColModel = [
{name:'chkbox', index:'chkbox', align:'center', width:'3%', edittype:'checkbox', editoptions:{value:'Y:N'}, formatter:'checkbox', formatoptions: {disabled: false}},
{name:'group_code', index:'group_code', align:'center', width:'7%',edittype:'text', editrules:{required:true}},
{name:'prog_id', index:'prog_id', align:'center', width:'10%', edittype:'text', editrules:{required:true}, key:true},
{name:'depth_lv', index:'depth_lv', align:'center', width:'5%', edittype:'text', editrules:{required:true, number:true, integer:true, maxValue:255}},
{name:'prog_name', index:'prog_name', align:'left', width:'25%', edittype:'text', editrules:{required:true}},
{name:'prog_url', index:'prog_url', align:'left', width:'30%', edittype:'text'},
{name:'order_no', index:'order_no', align:'center', width:'5%', edittype:'text', editrules:{required:true, number:true, integer:true, maxValue:65535}},
{name:'view_yn', index:'view_yn', align:'center', width:'5%', edittype:'select', editoptions:{value:{"Y":"Y","N":"N"}}, formatter:'select', editrules:{required:true},}
];
그리고 내가 직접 설정해서 validation 체크할 항목을 구현하면 된다.
중간에 주석 처리한 부분은 처음에 중복확인 하는 코드를 reduce ? 까지 써가면서 복잡스럽게도 짜놓은 코드다.. 쉽게 생각하자
리턴값을 [true , "" ] 이렇게 주어야하는데 validation에 걸리면 모달 창에 에러메시지가 나온다
afterComplete는 서버에 데이터가 전송되어서 DB작업을 마치고 리턴해주는 값을 받아올 수 있다. 전송버튼을 누르면 자동으로 모달팝업창이 닫히게 설정 해 주었기 때문에 그리드가 reload 되고 성공/실패시에 리턴되는 값에 따라 결과값을 화면에 표시해준다.
그리고 setColData(false)를 호출해서 editable:true 설정을 다시 false로 바꿔주어 그리드 화면에서 수정 input이 뜨지 않게 해줘야 한다!
onClose는 모달팝업에서 취소버튼을 눌렀을 때 발생하는 이벤트이다. 클릭시 전송 완료때와 동일하게 setColData(false)를 호출해서 editable:true 설정을 다시 false로 바꿔주어야 한다.
수정부분 전체 코드
function setColData(param){
const gridColData = ["group_code", "prog_id", "depth_lv", "prog_name", "prog_url", "order_no", "view_yn"];
for(var idx in gridColData){
$("#dataGrid").setColProp(gridColData[idx], {editable : param});
}
}
const gridFunc = {
addRow : function(){
const options = {
modal : true,
width : 400,
url : '/data/menumast/createGridData',
mtype : 'POST',
addCaption : "MENUMAST 추가",
closeAfterAdd : true,
recreateForm : true, //대화상자가 활성화될 때 마다 form이 다시 생성된다
reloadAfterSubmit:true, //서버 ajax후 그리드 데이터 다시 로드
beforeInitData : function(formid){ //form 데이터를 초기화 하기 전에 호출
setColData(true);
},
beforeSubmit : function(postdata, formid){
/* 입력 값 validation*/
if(postdata.group_code.length>2){
return [false, "그룹코드의 입력값은 두자리 입니다."];
}
if(postdata.prog_id.length>10){
return [false, "프로그램 아이디는 10자리를 넘을 수 없습니다."];
}
if(postdata.prog_name.length>50){
return [false, "프로그램명은 50자리를 넘을 수 없습니다."];
}
if(postdata.prog_url.length>50){
return [false, "프로그램 URL은 50자리를 넘을 수 없습니다."];
}
/*group_code === prog_id (_)이전 값 */
const progid = postdata.prog_id.split('_');
console.log(progid);
if(postdata.group_code!==progid[0]){
return [false, "그룹코드와 프로그램 ID의 코드는 동일해야 합니다."];
}
const rowData = $("#dataGrid").getRowData();
/*prog_id 중복확인 */
for(const idx in rowData){
if(rowData[idx].prog_id===postdata.prog_id){
return [false, "프로그램 ID는 중복값을 가질 수 없습니다."];
}
}
/*depth_lv===1일때 존재하는 상위메뉴 체크 */
if(postdata.depth_lv==='1'){
// const depthLvArr = [];
for(const key in rowData){
if(rowData[key].group_code===postdata.group_code && rowData[key].depth_lv===postdata.depth_lv){
return [false, "상위 메뉴가 이미 존재합니다. 메뉴레벨을 변경 해 주세요."];
}
}
}
return [true, ''];
},
afterComplete : function(response, postdata, formid){
setColData(false);
if(response.responseText==='success'){
alert("등록되었습니다 !");
}else{
alert("에러 발생 !\nerrMsg : "+response.responseText);
}
},
onClose : function(){
setColData(false);
}
}
$("#dataGrid").jqGrid('editGridRow', "new", options );
}
}
그럼 이제 화면쪽은 구현이 완료되었고 라우터에서 DB 처리를 해주자
router.post('/data/menumast/createGridData', (req, res) => {
const body = req.body;
let sql="";
sql = "INSERT INTO MENUMAST (sys_gbn, group_code, prog_id, depth_lv, prog_name, prog_url, order_no, view_yn, cre_date)";
sql += "values ('USEPAY', ? , ? , ? , ? , ? , ? , ? , now())";
const param = [body.group_code, body.prog_id, body.depth_lv, body.prog_name, body.prog_url, body.order_no, body.view_yn];
console.log(sql);
db_pool.getConnection(async function (err, conn) {
if (err) { //connction 오류
if (conn)
conn.release();
return;
}
await conn.beginTransaction();
await conn.query(sql, param, function(err, result){
if(err){ //쿼리 에러
console.log("쿼리 에러");
conn.rollback();
console.log(err);
res.send(err.sqlMessage);
}else{ //에러 안남
console.log("에러 안남");
res.send('success');
conn.commit();
}
});
conn.release(); //connection pool을 반납
});
});
추가 완 !
* jqGrid 관련해서 구글을 미친듯이 뒤졌는데 그중에서도 참고한 포스팅들 목록
http://1004lucifer.blogspot.com/2019/05/jqgrid-cell.html (이분게 찐임..다 나와있으나 나같은 초보자는 이해하기 쉽지 않았음)
https://withsoju.tistory.com/703
https://okky.kr/article/307721
https://backback.tistory.com/92
https://isprogramming.tistory.com/13
https://blog.naver.com/PostView.naver?blogId=aufcl4858&logNo=220988211038&parentCategoryNo=&categoryNo=40&viewDate=&isShowPopularPosts=true&from=search
https://monkeybusiness.tistory.com/25
https://pjsprogram.tistory.com/30
https://hianna.tistory.com/488
https://jjanggun.tistory.com/466
'업무 > nodejs' 카테고리의 다른 글
jqgrid : 그리드 조회, 수정, 추가, 삭제 전부 구현하기(4) - 그리드 삭제 (0) | 2022.04.07 |
---|---|
jqgrid : Cannot read properties of undefined (reading '0') 에러 (0) | 2022.04.06 |
jqgrid : (에러) 셀 수정시 ajax 두번 호출되는 경우 (0) | 2022.04.05 |
jqgrid : 그리드 조회, 수정, 추가, 삭제 전부 구현하기(2) - 그리드 수정 (0) | 2022.04.04 |
jqgrid : 그리드 조회, 수정, 추가, 삭제 전부 구현하기(1) - 그리드 조회 (0) | 2022.03.30 |
- Total
- Today
- Yesterday
- jsp 기초 개념
- Split
- selectbox에 값 매핑
- spring
- java
- servlet
- input[type=text]초기화
- servlet게시판
- 체크박스전체선택
- 체크박스전체해제
- input[type=file]초기화
- windows hyper-v
- SQL
- String[] 파라미터
- 이클립스DB연결
- Javascript
- 체크박스
- c 태그
- 제이쿼리
- 자바
- foreach 배열
- Hyper-V
- 게시판table설계
- jsp
- 스크립팅 요소
- 자바스크립트
- 스프링
- windows 8.1
- 게시판페이지설계
- 윈도우8.1
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |