잊고 계셨을지도 모를 jqGrid 마지막편입니다.
이번 시간은 jqGrid를 이용하여 데이터를 추가, 편집, 삭제해보는 시간을 가져보도록 하겠습니다.


뷰페이지부터 보죠


지난 포스팅에 이어나갑니다. 먼저 가장 중요한 스크립트 부분을 보시면,

var updateDialog = {
                url: '<%= Url.Action("Update", "Home") %>'
                , closeAfterAdd: true
                , closeAfterEdit: true
                , modal: true
                , onclickSubmit: function (params) {
                    var ajaxData = {};
                    var list = $("#list");
                    var selectedRow = list.getGridParam("selrow");
                    rowData = list.getRowData(selectedRow);
                    ajaxData = { dirId: rowData.dirId };
                    return ajaxData;
                }
                , width: "400"
            };
            $.jgrid.nav.addtext = "추가";
            $.jgrid.nav.edittext = "편집";
            $.jgrid.nav.deltext = "삭제";
            $.jgrid.edit.addCaption = "전화번호부 추가";
            $.jgrid.edit.editCaption = "전화번호부 편집";
            $.jgrid.del.caption = "전화번호부 삭제";
            $.jgrid.del.msg = "정말 삭제하실거에요?";
            $("#list").jqGrid({
                url: '<%= Url.Action("EntityGridData", "Home") %>',
                datatype: 'json',
                mtype: 'POST',
                colNames: ['No', '이름', '전화번호', '이메일', '단축다이얼'],
                colModel: [
                  { name: 'dirId', index: 'dirId', width: 40, align: 'center', editable: true, editrules: { edithidden: false }, hidedlg: true, hidden: true },
                  { name: 'name', index: 'name', width: 200, align: 'left', editable: true, edittype: 'text', editrules: { required: true }, formoptions: { elmsuffix: ' *'} },
                  { name: 'phone', index: 'phone', width: 200, align: 'left', editable: true, edittype: 'text', editrules: { required: true }, formoptions: { elmsuffix: ' *'} },
                  { name: 'email', index: 'email', width: 300, align: 'left', editable: true, edittype: 'text', editrules: { required: true, email: true }, formoptions: { elmsuffix: ' *'} },
                  { name: 'speedDial', index: 'speedDial', width: 200, align: 'center', editable: true, edittype: 'text', editrules: { required: true }, formoptions: { elmsuffix: ' *'}}],
                pager: $('#pager'), 
                emptyrecords: "Nothing to display",             
                rowNum: 3,
                rowList: [3, 10, 20, 50],
                sortname: 'dirId',
                sortorder: "desc",
                viewrecords: true,
                caption: '전화번호부',
                ondblClickRow: function (rowid, iRow, iCol, e) {
                    $("#list").editGridRow(rowid, updateDialog);
                }
            }).navGrid('#pager',
                {
                    edit: true, add: true, del: true, search: false, refresh: true
                },
                updateDialog,
                updateDialog,
                updateDialog

            );

너무 많이 바뀌었나요? 그래도 알아보시죠? :) 굵은거~굵은거~

먼저 보이는것은 updateDialog가 보이네요. url도 보이고 submit 하고 ajax도 보이고.
데이터의 추가,편집,삭제시에 뜨는 팝업창에서 할일들이죠. Home 컨트롤러의 Update라는 액션메쏘드를 호출할거고요.
추가, 편집 후에는 창을 닫을 것이고(closeAfterAdd: true, closeAfterEdit: true), 모달창이고(modal: true), submit시 ajax를 사용하는 것 같아보이네요^^

다음으로 보이는게 $.jgrid.nav... 입니다. 이것은 지난 시간에도 말씀드렸던  grid.locale-en.js 을 수정하는 부분입니다. 이런 언어파일에는 디폴트값이 들어가 있다고 말씀드렸었죠? 기억하시죠? ;;

$.jgrid.edit = {
    addCaption: "Add Record",
    editCaption: "Edit Record",
    bSubmit: "Submit",
    bCancel: "Cancel",
    bClose: "Close",
    processData: "Processing...",
    msg: {
        required:"Field is required",
        number:"Please, enter valid number",
        minValue:"value must be greater than or equal to ",
        maxValue:"value must be less than or equal to",
        email: "is not a valid e-mail",
        integer: "Please, enter valid integer value",
        date: "Please, enter valid date value"
    }
};
$.jgrid.del = {
    caption: "Delete",
    msg: "Delete selected record(s)?",
    bSubmit: "Delete",
    bCancel: "Cancel",
    processData: "Processing..."
};
$.jgrid.nav = {
    edittext: " ",
    edittitle: "Edit selected row",
    addtext:" ",
    addtitle: "Add new row",
    deltext: " ",
    deltitle: "Delete selected row",
    searchtext: " ",
    searchtitle: "Find records",
    refreshtext: "",
    refreshtitle: "Reload Grid",
    alertcap: "Warning",
    alerttext: "Please, select row"
};

뷰페이지에서 수정한 부분은 두껍게 표시하였습니다.

$.jgrid.edit 의 msg중 required:"Field is required", email: "is not a valid e-mail" 이 부분이 뷰페이지의 colModel의 editrules: { required: true, email: true } 값과 매치가 되는 거죠.
또, grid의 네비게이션바에서 추가, 편집, 삭제 표시가 이미지로만 되어있었던 것을( $.jgrid.nav 의 add,edit,del 텍스트값이 빈값으로 되어있죠?) 뷰페이지에서 타이틀을 달아본겁니다.

나머지 부분도 재미있게 수정해서 테스트해보세요^^ 버튼 이름 변경, 필수값 에러 메시지, 경고메시지 등이 수정가능하네요. 



데이터를 처리하자


컨트롤러의 액션메쏘드가 추가되었겠죠? 다음은 HomeController의 추가된 Update 액션메쏘드입니다.

public ActionResult Update(TelDir telInfo, FormCollection formCollection)
{
    var operation = formCollection["oper"];
    if (operation.Equals("add"))
    {
       TelDir telData = new TelDir();
       telData.name = telInfo.name;
       telData.phone = telInfo.phone;
       telData.speedDial = telInfo.speedDial;
       telData.email = telInfo.email;
       _db.AddToTelDirSet(telData);
       _db.SaveChanges();
    }
    else if (operation.Equals("edit"))
    {
       var telData = _db.TelDirSet.First(m => m.dirId == telInfo.dirId);
       telData.name = telInfo.name;
       telData.phone = telInfo.phone;
       telData.speedDial = telInfo.speedDial;
       telData.email = telInfo.email;
       _db.SaveChanges();
    }
    else if (operation.Equals("del"))
    {
       var telData = _db.TelDirSet.First(m => m.dirId == telInfo.dirId);
       _db.DeleteObject(telData);
       _db.SaveChanges();
    }
    return Content("ok");
}

각 요청(add,edit,del) 대로 분기하여 처리하도록 하였습니다.



이제야 보는구나


실행을 해서 결과화면을 보면


멋드러지게 지난시간과는 다른 모습의 grid 가 있는 것을 확인할 수 있습니다. 추가,편집,삭제 버튼이 들어가 있고 옆에 리프레쉬 버튼도 있네요.

추가 버튼을 누르면


깔끔한 박스가 뜨네요. 전 슈퍼맨을 등록해보도록 하겠습니다. 값을 입력하지 않고 그냥 Submit 버튼을 살짝 눌러보시면 이름 입력하라고, 전화번호 입력하라고 아우성일겁니다. editrules: { required: true } 이것때문이죠. 매치된 메시지는 언어 스크립트에 있는 required:"Field is required" 이고요. 값을 정상적으로 입력후에 Submit을 하면...
바로바로 처리가 가능하네요^^ 모달창이 닫히는 부분은 위에서 설명드렸던 closeAfterAdd: true 때문인거죠. 편집하는 부분도 해볼까요? closeAfterEdit: truefalse로 하여 테스트해보세요. 모달창이 닫히지 않고 수정한 값들이 화면의 울렁거림 없이 처리가 되는 것을 확인하실 수 있습니다.

편집하는 부분을 테스트 하시려면 먼저 수정하려는 해당 로우(row)를 선택하신 후 편집 버튼을 클릭하시거나, 해당 로우를 더블클릭하시면 됩니다. 해보시죠?^^;


마지막으로 정말 삭제하실거에요? 를 본후 노는 시간을 마치도록 하겠습니다.




마무리요


정말 jquery 관련 플러그인들은 참 편리하네요. 이렇게 손쉽게 처리가 가능하니 말이죠.
암튼, 이번시간으로 jqGrid는 마치겠습니다. 뭐 한것도 없이 마친다고 하니 웃기네~ 라고 말씀을 해주셔도 마칠겁니다.^^;

아직은 무덥고, 다양한 날씨속에서 지내는 지금, 건강 꼭 챙기세요. 감사합니다^^

참고자료 : http://elijahmanor.com/webdevdotnet/post/jQuery-jqGrid-Plugin-Add-Edit-Delete-with-ASPNET-MVC.aspx
신고
안녕하세요. 지난 시간에는 jqGrid를 이용해서 리스트를 구현해봤습니다. 정말 맛보기였죠? :)
이번 시간은 실제 데이터베이스에서 데이터 조회, 페이징과 정렬부분을 다루도록 하겠습니다.

먼저 데이터베이스 생성

테이블 구조는 다음과 같습니다.

 컬럼명  데이터 타입
 dirId  int
 name  nvarchar(50)
 phone  nvarchar(50)
 email  nvarchar(50)
 speedDial  decimal(2,0)

그냥 기본세팅이죠^^;

엔터티 모델 클래스를 생성할 건데요, 자세히(?)를 원하신다면 이전 포스팅을 참고해주세요^^;
완료가 되면,


여기까지 잘 오셨죠? 저는 Entity Set Name을 TelDir에서 TelDirSet으로 변경하였습니다. 헷갈려서요^^;;

자. 이제는 본격적(?)으로 살펴볼까요? (어째.. 오늘도 맛보기일것 같은 분위기가 물~씬 풍기시죠? ㅡ,.ㅡ;)

페이징 기능을 달자

지난 뷰페이지에 pager란 id로 div 태그를 추가하겠습니다.

<div id="pager" class="scroll" style="text-align:center;"></div>

테이블 뒤에 추가하시면 됩니다.
그리고, 스크립트 부분도 수정해야겠죠?

    <script src="/Scripts/grid.locale-en.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#list").jqGrid({
                url: '<%= Url.Action("EntityGridData", "Home") %>',
                datatype: 'json',
                mtype: 'POST',
                colNames: ['No', '이름', '전화번호', '이메일', '단축다이얼'],
                colModel: [
                  { name: 'dirId', index: 'dirId', width: 40, align: 'center' },
                  { name: 'name', index: 'name', width: 100, align: 'left' },
                  { name: 'phone', index: 'phone', width: 150, align: 'left' },
                  { name: 'email', index: 'email', width: 250, align: 'left' },
                  { name: 'speedDial', index: 'speedDial', width: 100, align: 'center'}],
                    pager: $('#pager'),
                emptyrecords: "Nothing to display",            
                rowNum: 3,
                rowList: [3, 10, 20, 50],
                sortname: 'dirId',
                sortorder: "desc",
                viewrecords: true,

                caption: '전화번호부'
            });
        });
    </script>

추가된 부분은 굵은글씨로 표시하였습니다. 일단, grid.locale-en.js를 추가해야되더라고요^^; 디폴트로 그냥 jqGrid 스크립트를 넣을때 추가하라고 하였는데, 제가 지난 포스팅때는 빠뜨렸죠.
이런 언어 스크립트 파일에는 페이징 관련한 디폴트 값들이 들어가 있습니다.

defaults:{
   recordtext:"View {0} - {1} of {2}",
   emptyrecords:"No records to view",
   loadtext:"Loading...",
   pgtext:"Page {0} of {1}"
  }


나머지 프로퍼티에 대한 설명을 드리자면,
pager는 위 이미지 보이시죠? ^^; 저렇게 레코드들을 이동할수 있게 해주는 페이징 바를 정의합니다.
저같은 경우는 $('#pager')로 jQuery 표현을 썼는데요, jqGrid의 wiki를 보니 '#pager', 'pager', jQuery('#pager') 세가지 경우가 모두 가능한데요. 앞에 두가지 방법을 추천한다네요. 흠. jQuery 변수가 내보내기, 가져오기 모듈을 이용할때 문제를 발생시킬수 있다고 합니다. 이 부분은 차츰(?) 찾아보도록 하죠;;

The definition of the pager in the grid can be done this way:pager : '#gridpager', pager : 'gridpager' or pager : jQuery('#gridpager'). All the three methods are valid, but I recommend to use the first or second one, since the jQuery variant causes problems when we try to use Exporting and Importing modules.

emptyrecords는 말 그대로 데이터가 없을 때 표현할 문구를 나타내고요,
rowNum은 페이지에서 보여줄 레코드 갯수,
rowList는 페이지 갯수를 선택할 수 있도록 하는 셀렉트박스의 옵션들,
sortname, sortorder는 각각 정렬할 컬럼과 정렬방식(오름차순, 내림차순),
viewrecords는 토탈 레코드의 수(위 이미지에서 View 1 -3 of 5)를 표현하는 것을 허용할 것인지 여부를 나타냅니다.

이제 뷰페이지는 완성이 되었고요, 컨트롤러 손봐야겠죠?
EntityGridData() 라는 이름의 액션메쏘드를 추가하겠습니다.

[HttpPost]
        public ActionResult EntityGridData(string sidx, string sord, int page, int rows)
        {
            // 데이터베이스 연결
            MvcDbEntities _db = new MvcDbEntities();

            // 페이징 변수 세팅
            int pageIndex = Convert.ToInt32(page) - 1;
            int pageSize = rows;    // 3
            int totalRecords = _db.TelDirSet.Count();
            int totalPages = (int)Math.Ceiling((float)totalRecords / (float)pageSize);

            // 데이터 조회(페이징&정렬)
            // sidx : dirId
            // sord : desc
            var dirs = _db.TelDirSet
                .OrderBy("it." + sidx + " " + sord)
                .Skip(pageIndex * pageSize)
                .Take(pageSize)
                .ToList();

            var jsonData = new
            {
                total = totalPages,
                page = page,
                records = totalRecords,
                rows = (
                  from dir in dirs
                  select new
                  {
                      i = dir.dirId,
                      cell = new string[] {
                          dir.dirId.ToString(), dir.name.ToString(), dir.phone.ToString(), dir.email.ToString(), dir.speedDial.ToString()                         
                      }
                  }).ToArray()
            };
            return Json(jsonData);
        }

궁금해 보이는 것이 없죠? ㅎㅎ
jqGrid가 EntityGridData를 호출할때 파라미터(sidx : dirId, sord : desc, page : 1, rows : 3)를 날립니다~~~
실행을 해보면,


너무 간단하게 페이징 기능이 완성되었습니다^^
네이게이션 기능 되고요~ 셀렉트박스로 로우 갯수 선택 기능 되고요~ No탭 클릭하시면 정렬 기능 됩니다요~

마무리요

실행화면 출력하고 보니 아직도 맛!보!기! 인것을 보면 아직 한참 멀은 듯 합니다.
더 알찬 정보로 준비하도록 하겠습니다^^
감사합니다. 


참고자료 :
http://haacked.com/archive/2009/04/14/using-jquery-grid-with-asp.net-mvc.aspx
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pager&s[]=paging&s[]=properties
신고
이번 시간은 jQuery 플러그인인 jqGrid를 잠깐(?) 사용해보는 시간을 갖도록 하겠습니다. 

jqGrid 플러그인 다운

먼저, jqGrid 사이트에서 jqGrid 플러그인을 다운받습니다.
다운받은 압축파일을 푸신 후, ASP.NET MVC 프로젝트에 3개의 파일을 추가하겠습니다. jquery.jqGrid.min.js 파일과 jquery-ui-1.7.1.custom.css, ui.jqgrid.css 파일입니다.


자, 이제 시작해볼까요?

jqGrid 맛보기

한꺼번에 다 보여드리기 보다는 조금조금씩~ 맛을 보여드리도록 하겠습니다^^

좀전에 프로젝트에 추가한 파일을 뷰페이지에 쭈~욱 끌어다 놓습니다.

<link href="/Content/jqGrid/jquery-ui-1.7.1.custom.css" rel="stylesheet" type="text/css" />
<link href="/Content/jqGrid/ui.jqgrid.css" rel="stylesheet" type="text/css" />
<script src="/Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="/Scripts/jqGrid/jquery.jqGrid.min.js" type="text/javascript"></script>

그 다음으로, 이 jqGrid 관련 자바스크립트 소스를 추가하겠습니다. 한눈에 봐도 너무 간단한 스크립트 부분이라 jQuery를 모르셔도 딱!! 파악하실수 있을 겁니다.

<script type="text/javascript">
        $(function () {
            $("#list").jqGrid({
                url: '<%= Url.Action("GridData", "Home") %>',
                datatype: 'json',
                mtype: 'get',
                colNames: ['No', '이름', '전화번호', '이메일', '단축다이얼'],
                colModel: [
                  { name: 'DirId', index: 'DirId', width: 40, align: 'center' },
                  { name: 'Name', index: 'Name', width: 100, align: 'left' },
                  { name: 'Phone', index: 'Phone', width: 100, align: 'left' },
                  { name: 'Email', index: 'Email', width: 200, align: 'left' },
                  { name: 'SpeedDial', index: 'SpeedDial', width: 100, align: 'center'}],
                caption: '전화번호부'
            });
        });
    </script> 

위 소스를 잠깐 살펴보면, url은 Home 컨트롤러에서 GridData라는 액션메쏘드를 호출하고 있습니다. 잠시 후에 이를 구현해야겠죠?^^; datatype은 json이네요. 음.. GridData라는 놈이 json객체를 넘겨주겠군?! 하고 생각하시면 되죠. colNames는 리스트를 보여줄때 각각의 컬럼을 구분짓는 이름입니다. colModel을 통해 grid에서 받을 리스트에 width라던지 align을 주고 있는 것을 보실수 있습니다.

그래서 완성된 Index.aspx 뷰페이지를 보게되면,

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    홈 페이지
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <link href="/Content/jqGrid/jquery-ui-1.7.1.custom.css" rel="stylesheet" type="text/css" />
    <link href="/Content/jqGrid/ui.jqgrid.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="/Scripts/jqGrid/jquery.jqGrid.min.js" type="text/javascript"></script>
 
    <script type="text/javascript">
        $(function () {
            $("#list").jqGrid({
                url: '<%= Url.Action("GridData", "Home") %>',
                datatype: 'json',
                mtype: 'GET',
                colNames: ['No', '이름', '전화번호', '이메일', '단축다이얼'],
                colModel: [
                  { name: 'DirId', index: 'DirId', width: 40, align: 'center' },
                  { name: 'Name', index: 'Name', width: 100, align: 'left' },
                  { name: 'Phone', index: 'Phone', width: 100, align: 'left' },
                  { name: 'Email', index: 'Email', width: 200, align: 'left' },
                  { name: 'SpeedDial', index: 'SpeedDial', width: 100, align: 'center'}],
                caption: '전화번호부'
            });
        });
    </script> 
<h2><%: ViewData["Message"] %></h2>
<table id="list" class="scroll" cellpadding="0" cellspacing="0"></table>
</asp:Content>

table에 리스트를 쫙~ 뿌려주도록 하겠습니다.

이제, Home 컨트롤러를 잠깐 손보도록 하겠습니다. jqGrid에서 받을 json객체를 리턴하는 GridData라는 액션메쏘드를 만들도록 하겠습니다. 이번 포스팅은 정말 맛보기이기 때문에 간단하게 바로 객체를 만들어서 리턴하겠습니다.


와우~ 정말 간단하게 모든 구현이 완료되었습니다! 이제 실행을 해볼까요?


엥? 이건 또 뭔가요? 역시 한번에 되는 것은 없나봐요;;
내용을 보니 GET 요청이 차단되었고, JsonRequestBehavior를 AllowGet으로 설정하라고?! 호출 스택을 보니 JsonResult를 실행하다가 에러가 발생하였네요. 음.. JsonResult 부분이 잘못되었군. 한번 수정해보죠^^;

return Json(dirs, JsonRequestBehavior.AllowGet);

수정후 실행해보면~


네. 멋지게 성공하였습니다.

ASP.NET MVC 2 에서는 기본적으로 이러한 GET방식의 호출을 보안상의 문제로 막아놨습니다. 그래서 JSON 객체를 리턴할때는 JsonRequestBehavior.AllowGet을 추가하여 클라이언트의 GET요청을 허용하도록 한 것이죠.

하지만, 막아놓은 것을 굳이 풀 필요는 없겠죠?^^; POST 방식으로 호출하는 것이 좀더 좋을 듯 합니다.
이 부분은 따로 설명드릴 필요없겠죠? 약간(^^;;) 설명드리면~
일단 GridData액션 메쏘드 위에 GET으로 요청한 놈은 접급하지마! 라는 표지판([HttpPost])을 세워두는거죠. 실행시켜보면 역시 에러가 발생할겁니다. 리소스를 찾을수 없다는... 그래서! 뷰페이지 스크립트 부분의 mtype을 POST로 수정하는거죠^^ 실행해보세요~ 잘되시나요?

이거슨 번외요~

웹 개발자를 위한 Web Development Helper 유틸이 있습니다. 익스플로러에 확장할 수 있죠. 저같은 경우는 Fiddler를 많이(?) 사용하는데요. Web Development Helper는 특히 Ajax와 ASP.NET 개발자를 위한 것이라고 하네요. 사이트에서 다운 받고 인스톨하시고, 익스플로러의 도구 메뉴의 탐색창->Web Development Helper를 클릭하시면 됩니다.
이번 jqGrid 맛보기에서의 request&response정보도 확인할 수 있네요.


마무리요

이번시간은 정말 jqGrid 플러그인의 맛보기였고요, 다음 포스팅에서 뵙도록 하겠습니다. (다음 포스팅도 맛보기처럼 보이면 어떡하죠?^^;;)

참고자료 :
http://haacked.com/archive/2009/04/14/using-jquery-grid-with-asp.net-mvc.aspx
http://www.trirand.net/
http://projects.nikhilk.net/WebDevHelper/
http://geekswithblogs.net/michelotti/archive/2008/06/28/mvc-json---jsonresult-and-jquery.aspx
신고
안녕하세요. 늦바람이 무섭다고 하는데요. jQuery를 향한 늦바람이 불어주길 바라는 1인입니다. ㅎㅎ

이렇게 간단해도 되는겨?

이번 포스팅을 준비하면서 정말 jQuery의 놀라운 힘에 다시 한번 놀랐습니다. 이렇게 간단히 탭메뉴를 넣는게 가능했던건가요?

준비물 준비

먼저, jQueryUI 사이트에서  jquery-ui-1.8.2.custom.zip 파일을 다운받습니다. 압축을 푸시면 jquery-ui-1.8.2.custom.min.js 와 jquery-ui-1.8.2.custom.css 파일이 있습니다.(각각 js폴더와 css폴더에 있습니다.) 이 두 파일을 프로젝트의 Content와 Scripts 폴더에 추가시킵니다. 이제 준비는 됐고요.

준비끝! 예제로!

Index.aspx 페이지 소스입니다.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    홈 페이지
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <script type="text/javascript">
        $(function () {
            $("#tabs").tabs();
        });
    </script>
    <div>
        <div id="tabs">
        <ul>
            <li><%: Html.ActionLink("홈", "Index", "Product")%></li>
            <li><%: Html.ActionLink("제품", "List", "Product")%></li>
            <li><%: Html.ActionLink("연락", "Contact", "Product")%></li>
        </ul>
        </div>
    </div>
</asp:Content>

$("#tabs").tabs() 이게 바로 그 놀라운 능력을 가진 탭메뉴를 가능케하는 힘입니다. (자세한 것은 다음으로 미루고~ 언제가 될지는 몰라요. 그냥 잘 쓰면 되는거죠^^;;)
아. 추가시켰던 두 파일은 마스터페이지에 끌어다놨습니다.


이제 Html.ActionLink() 에 걸린 액션들만 만들어 주면 됩니다.


요청 컨트롤러입니다. 첫 Index() 액션 메쏘드를 보시면 dynamic 이라는 타입이 보이는데요. 처음에는 Contact()와 마찬가지로 PartialView()만 리턴을 하였는데, 파샬뷰를 생성해 놓고 보니.


저렇게 dynamic 이 눈에 딱 띄는바람에 어쩔수(?) 없이 dynamic데이터를 전달하게 되었습니다. 간단히 설명드리면 dynamic은 대인배의 마음 씀씀이를 갖고 있어서 어떤 타입이던지 모두 수용합니다.(컴파일타임에는 터치를 안합니다. 귀찮아서 런타임한테 넘기는거죠;;) dynamic으로 선언된 변수에 멤버, 메쏘드, string, int 가리지 말고 막 넣어주세요. 다 받아줍니다. 하.. 저도 대인배로 살아가야 할텐데 참.. 아쉽습니다 :)
다음 기회에 dynamic에 대해 좀더 자세히 알아보면 좋겠네요.

다시 본론으로 넘어와서, /Product/Index.ascx 를 보시면

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<h3><%: Model.Message %></h3>
<p>
    ASP.NET MVC에 대한 자세한 내용을 보려면 <a href="http://asp.net/mvc" title="ASP.NET MVC 웹 사이트">http://asp.net/mvc</a>를 방문하십시오.
</p>

Model객체의 Message의 접근하면(Model.Message) Index 메쏘드에서 넘겨준 다이나믹한 메시지를 받을 수 있습니다.

두번째, /Product/List.ascx는

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<MvcWithjQuery.Models.Product>>" %>
<table width="400px">
<tr>
    <th>제품명</th>
    <th>가격</th>
</tr>
<% foreach (var product in Model) { %>
<tr>
    <td><%: product.Name %></td>
    <td><%: product.Price %></td>         
</tr>
<% } %>
</table>

너무 간단해서 할말을 잃게 만들죠. foreach문을 통해 루프를 돌면서 데이터를 출력합니다.
나머지 Contact.ascx는 안보셔도 됩니다.^^;

자, 완료가 되었으니 확인을 해보죠.


페이지 로드 없이 깔끔하게 탭기능이 완성되었습니다.

마무리요

일반적인 페이지(aspx)도 탭메뉴로 가능합니다. 파샬뷰를 사용한 것은 한 페이지 전체보다 불필요한 부분을 제거한(head, html, body가 보시다시피 파샬뷰에는 존재하지 않습니다.) 간결함때문이랄까요? ㅎㅎ
다음은 더 재미있는 것으로 찾아뵙겠습니다. (지금은 재밌다는겨? 뭐여? ㅡ.ㅡ 이렇게 생각하시는 분은 제발 없으시길 바래요^^)

참고자료 :  http://www.kevgriffin.com/blog/index.php/2010/02/23/using-jquery-tabs-and-asp-net-mvc-partial-views-for-ajax-goodness/
신고
지금 잠을 자면 꿈을 꿀 수 있지만, 잠을 자지 않으면 꿈을 이룰 수 있다고 하죠. 그래서 이렇게 눈꺼풀이 내려오는데도 버티고 있는가 봅니다^^; 이 글을 읽고 있는 분들도 꿈을 위해 노력하고 계신거겠죠?

귀 따갑다 jQuery

고마해라~ 마이 들었다 아이가~. 너무 들어서 지겨울 만큼의 jQuery. 이제 시작합니다. 이렇게 늦게 jQuery를 들쳐보는 저를 용서하시고, 격려의 한말씀 해주시면 정말 감사하겠습니다. :)
그런데, jQuery 정말 다들 아시는거죠?

jQuery가 뭔데?

아직도 jQuery를 모른단 말인가?! 자네 정말 웹 관련 일하는 사람이 맞긴 맞는건가? 어헣. 이런 말이 오고가진 않아야 겠죠?

jQuery 공식 홈페이지에는 다음과 같은 말이 떡~하니 있습니다.

jQuery is a new kind of JavaScript Library.
jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript.

쭉 보면,
jQuery는 자바스크립트 라이브러리의 한 종류입니다. jQuery는 신속한 웹 개발을 위한 HTML 문서 탐색, 이벤트 처리, 애니메이션, Ajax와의 상호작용을 간단하게하는 빠르고 간결한 자바스크립트 라이브러리입니다. jQuery는 자바스크립트 작성 방식의 전환을 위해 설계되었습니다.

다른건 몰라도, 암튼 웹 개발을 빠르게 해준다니까 오케이입니다. 귀찮은 작업도 간결하게 해주는 것 같고요.
Visual Studio 에 jQuery가 탑재되어있는 것도 마이크로소프트가 이를 지원한다는 얘기? 그래서 오케이. 스캇 구쓰리의 블로그를 보시면 계속 jQuery 플러그인 얘기가 올라오고 있는 것으로 봐서 활발하게 개발중인 것 같습니다.

간단 예제

정말 간단한 예제를 한번 살펴보도록 하겠습니다. 실망하시면 안~되요.
지금 하려는 것은 'ASP.NET MVC에 대한 자세한 내용을 보려면...' 이 있는 p 태그의 스타일을 변경해 볼겁니다. 먼저 MVC 프로젝트를 새로 생성하겠습니다. 그 다음, Index.aspx 페이지에 Contents 폴더에 있는 jquery-1.4.1.js 파일을 끌어다 놓습니다. '$(' 입력해보시면 놀랍게도 정말 놀~랍게도 인텔리센스를 지원해주는 것을 확인하실 수 있습니다. 멋지죠? :-)


아. 이거할때가 아닌데 좋아하고 있었네요. 먼저 필요한 스타일을 추가하겠습니다. 간단합니다.


색과 크기변경만 할겁니다.^^;
그 다음 스타일을 변경해줄 소스를 추가하겠습니다.

    <script src="../../Scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {           
            $('#btnStyle1').click(function () {
                $('p').removeClass();
                $('p').addClass('color-yellow').addClass('size-large');
            });
            $('#btnStyle2').click(function () {
                $('p').removeClass();
                $('p').addClass('color-red').addClass('size-small');
            });
        });
    </script>
    <div id="styleChange" style="background-color:Gray; width:300px">
        <h3 style="color: Yellow">스타일을 바꿔요</h3>
        <button id="btnStyle1">스타일_1</button>
        <button id="btnStyle2">스타일_2</button>
    </div>

jQuery 의 경우, 메쏘드 체인이 가능합니다. $().addClass().addClass().removeClass()...
암튼, 너무 간단해서 할 말을 잃으셨다면, 다음을 기대(?)해주세요^^;
실행 결과를 보면 스타일_1 버튼을 클릭했을시,


스타일_2 버튼을 클릭했을시,


참~ 이쁘게(?) 되네요.

마무리요

간단해서 따로 드릴 말씀은 없고요. 바로 다음 글 준비하겠습니다!!!


참고자료 : jQuery 1.3, 조나단 채퍼, 칼 스웨드버그
신고
유효성 검사 안끝난겨?

네. 아직입니다. ^^; 원래는 마무리를 지으려고 했었는데요. 갑자기 jQuery 가 급땡기는 바람에 슬슬 관련글을 적어보렵니다.

클라이언트단에서 유효성검사하기

지난번 포스팅을 보시면, 서버단의 모델 클래스에 DataAnnotaion을 사용하여 유효성검사를 했습니다. 물론, 클라이언트단에서도 자바스크립트를 사용하여 유효성검사를 할 수 있지만, 이는 동일한 유효성 검사를 두번(서버와 클라이언트) 하게됩니다. DRY(Don't Repeat Yourself) 규칙에 위반되는 작업인 거죠.

근데 왜?

저 아시는 분 없죠? 듣보잡인거죠. 그래서 이렇게 앞뒤가 없습니다. 이번 포스팅을 먼저 했으면 하는 마음도 있지만, 뭐 이렇게 된 것 그냥 적어내려갑니다.^^
DRY에 반하는 작업을 한다고 너무 차가운 피드백은 달지 말아주세요; '이런 방법도 있는 거였군'이라는 생각만 가져주셨으면 좋겠습니다.

먼저, 지난번 유효성 검사를 했던 소스에 jQuery를 이용한 유효성 검사 스크립트를 추가하겠습니다.


프로젝트내의 Scripts폴더에 있는 jquery-1.4.1.js와 jquery.validate.js파일을 추가합니다.(프로젝트에 이런 스크립트 파일들이 자동으로 적용되어있는 것으로 봐서는 맘껏 사용하라는 거겠죠?^^; 아. 그리고 미니버전을 사용해도 되는 것은  다들 아시죠? *min.js)

추가된 소스도 함께 보시죠.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
 Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <script src="/Scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script src="/Scripts/jquery.validate.js" type="text/javascript"></script>   
    <script type="text/javascript">
        $(function () {
            $("form").validate({               
                rules: {
                    "Name": { required: true, maxlength: 5 },
                    "Phone": { required: true },
                    "SpeedDial": { required: true, range: [1, 99] },
                    "Email": { email: true }
                },
                messages: {
                    "Name": "5자 이내로 이름을 입력하시오.",
                    "Phone": " 전화번호를 입력하시오.",
                    "SpeedDial": "1~99까지의 수만 입력하시오.",
                    "Email": "이메일이 형식에 맞지 않습니다."
                }
            });
        });   
    </script>
    <h2>Create</h2>
    <% using (Html.BeginForm()) { %>
    <div>
        이름 : <%= Html.TextBox("Name") %>
    </div>
    <div>
        전화번호 : <%= Html.TextBox("Phone")%>
    </div>
    <div>
        단축다이얼 : <%= Html.TextBox("SpeedDial")%>
    </div>
    <div>
        이메일 : <%= Html.TextBox("Email")%>
    </div>
    <input type="submit" value="Create" />
    <% } %>
</asp:Content>

소스를 보시면(빨간색) jQuery 스크립트와 유효성 검사를 위한 스크립트를 추가하였습니다. 또한 유효성 검사를 담당하는 jQuery 스크립트 구문도 추가하였습니다.

자, $("form").validate() 를 통해 유효성 검사를 합니다. 보시는대로, rulesmessages를 통해 에러를 표시하게되죠. Email을 제외한 각 필드를 필수값으로 세팅을 했고( required: true), 이름은 5자 이내(maxlength :5), 단축다이얼은 1~99까지의 숫자를 받도록(range[1,99]), 이메일은 이메일 형식을 체크(email: true)하도록 하였습니다. 이밖의 옵션들은 여기서 확인하실 수 있습니다.
빈값으로 폼을 전송하려고하면 클라이언트단에서 이에 제재를 가하게 됩니다.


이메일(필수값 아님)을 제외한 나머지는 에러가 났습니다. 올바른 값을 하나하나 입력하면 바로바로 에러메시지가 사라지는 것을 확인할 수 있습니다.


이메일을 잘못입력하면 에러메시지가 뜨는 것도 확인할 수 있습니다.

여기까지 잘 따라오셨으면 보다 싶게 클라이언트단에서의 유효성 검사를 진행해보죠. (윗부분은 이제 잊어도 좋습니다. 딱히 잊으라는게 아닌 아래 소스에서는 필요가 없어서.. 이렇게 말씀드리는건데...음.. '아 이런방법도 있구나'만 기억하시면 됩니다.^^;;)

DRY 잊지말자

지난번 포스팅에서는 서버단에서 유효성 검사를 하였기때문에 유효성 에러 메시지를 보려면 서버단까지 다녀와야할 필요가 있었습니다. 이를 가만히둘 마이크로소프트가 아닙니다. 정말 심플한 방법으로 손쉽게 클라이언트단과 서버단 두군데 모두 유효성검사를 할 수 있도록 하는 단 세줄의 코드가 있습니다.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcTest.Models.TelDir>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
 Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
    <script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>
    <% Html.EnableClientValidation(); %>
    <h2>Create</h2>
    <% using (Html.BeginForm()) {%>       
        <fieldset>
            <legend>Fields</legend>
           
            <div class="editor-label">
                <%: Html.LabelFor(model => model.Name) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.Name) %>
                <%: Html.ValidationMessageFor(model => model.Name) %>
            </div>
           
            <div class="editor-label">
                <%: Html.LabelFor(model => model.Phone) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.Phone) %>
                <%: Html.ValidationMessageFor(model => model.Phone) %>
            </div>
           
            <div class="editor-label">
                <%: Html.LabelFor(model => model.SpeedDial) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.SpeedDial) %>
                <%: Html.ValidationMessageFor(model => model.SpeedDial) %>
            </div>
           
            <div class="editor-label">
                <%: Html.LabelFor(model => model.Email) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.Email) %>
                <%: Html.ValidationMessageFor(model => model.Email) %>
            </div>
           
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>
    <% } %>
</asp:Content>

위 세줄을 추가함으로 지난번 포스팅에서 DataAnnotation을 이용한 유효성 검사 로직을 클라이언트단에서도 사용할수 있게 되었습니다. 실행을 시킨 후, Create 버튼을 클릭하면 리로드없이 즉각적으로 에러메시지를 확인할 수 있습니다.


또한, 유효한 값을 입력하면 즉시 에러메시지가 사라집니다.
저희는 지금 클라이언트단에 유효성 검사 로직을 추가하지 않았습니다. 유효성 검사로직은 모델클래스에만 존재하고 있습니다. 하하하.(승리자의 웃음인거죠^^) 룰은 한 곳에다가 두고, 두군데(클라이언트와 서버)에서 모두 검사를 하도록 하였습니다. 이로써 DRY를 잊지 않은체 작업이 완료되었습니다.

마무리요

이렇게 손쉽게 클라이언트단에서도 검사가 가능한 방법이 있었습니다. ㅎㅎ 기분좋네요.
마이크로소프트는 현재 jQuery 프로젝트에 참여하여 계속 플러그인을 개발중에 있습니다. (이 얘기는 왜하는 걸까요? 음..) 이 부분에 대해서도 포스팅을 하도록 노력해보겠습니다.


참고자료 :
http://docs.jquery.com/Plugins/Validation
http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx
신고