웹 개발
45분 소요

MVC, jQuery, JSON, 페이징, mapRoute 하우투 시리즈

ASP.NET MVC, jQuery, JSON을 사용한 고성능 웹 애플리케이션 개발 기술과 실용적인 솔루션.

N
Necmettin Demir
2023년 7월 21일
로딩 중...

MVC, jQuery, JSON, 페이징, mapRoute 하우투 시리즈

MVC, jQuery, JSON, 페이징
MVC, jQuery, JSON, 페이징

소스 코드 다운로드


소개

데이터베이스 시스템에 대량의 데이터가 존재하기 때문에 클라이언트 측 작업이 매우 중요해졌습니다. 클래식 ASP.NET의 code-behind 접근 방식에서는 ASP.NET 컴포넌트를 사용하여 code-behind 파일에 대부분의 작업을 코딩하는 것이 자연스러운 방법입니다. 또한, ASP.NET 컴포넌트의 렌더링과 viewstate 메커니즘은 현재 클래식 ASP.NET의 약점으로 간주되고 있습니다.
따라서 새로운 패러다임이 등장했습니다. 이 새로운 패러다임에 따르면, 개발자는 성능을 저하시키는 viewstate 없이 더 적은 렌더링으로 순수한 HTML과 JavaScript를 다룰 수 있습니다.
MVC는 오래된 디자인 또는 아키텍처 패턴으로 알려져 있지만, 위에서 언급한 클래식 ASP.NET의 병목 현상 이후 특히 인기를 얻었습니다. jQuery와 JSON이 효과적으로 사용되는 MVC에서는 고성능 애플리케이션을 개발할 수 있습니다.

사전 지식

이 글은 MVC, jQuery, JSON에 관한 몇 가지 입문 수준의 글을 읽은 후에 유용할 수 있습니다. 다음 링크는 초보자에게 도움이 될 수 있습니다:

코드 사용법

이 글에서는 "하우투 시리즈"를 목표로 합니다. 따라서 모든 스크립트는 첨부된 소스 코드에서 제공됩니다. 실제로 각 "하우투"는 별도의 글이 될 수 있습니다. 어쨌든 모든 가능한 답변이 하나의 예제에 통합되어 있습니다. 이 글에서는 이론적인 정보보다 실용적인 접근 방식이 있습니다. 예를 들어, 간단하게 하기 위해 데이터베이스 대신 몇 가지 정적 리스트가 사용됩니다.
다음 질문에 답변합니다:
  1. MVC에서 좋은 성능으로 CRUD를 수행하는 방법은?
  2. JavaScript의 confirm 또는 alert 대신 jQuery 대화 상자를 사용하는 방법은?
  3. MVC 목록에서 페이징을 수행하는 방법은?
  4. jQuery를 사용하여 MVC에서 "더 보기" 링크를 만드는 방법은?
  5. 링크에서 속성(attribute)을 사용하는 방법은?
  6. jQuery에서 AJAX 호출을 수행하는 방법은?
  7. MVC에서 Form 컬렉션을 사용하는 방법은?
  8. 한 번에 여러 레코드를 삭제하는 방법은?
  9. MVC에서 partial action을 사용하는 방법은?
  10. MVC 애플리케이션에서 JSON 형식을 사용하는 방법은?
  11. 마스터 상세 콤보 박스를 채우는 방법은?
  12. jQuery datepicker를 사용하는 방법은?
  13. jQuery 대화 상자를 사용하여 MVC에서 이미지를 업로드하는 방법은?
  14. 클라이언트 측에서 테이블 행을 생성하는 방법은?
  15. Global.asax에서 mapRoute를 사용자 정의하는 방법은?
  16. 테이블의 모든 행을 checkALL 및 uncheckALL하는 방법은?
  17. "데이터 로딩 중"을 만드는 방법은?
  18. jQuery로 마스터 상세 그리드를 만드는 방법은?

1) MVC에서 좋은 성능으로 CRUD를 수행하는 방법은?

대략적으로 생각하면, 모든 비즈니스 솔루션에는 Create-Read-Update-Delete(생성-읽기-업데이트-삭제) 기능이 있습니다. 가능하다면, "insert"와 "update" 모두에 동일한 "저장 폼"을 사용하는 것이 개발자에게 비용 효율적일 수 있습니다. 동일한 폼을 사용하는 것은 action에 전송되는 매개변수를 관리함으로써 가능합니다.
폼에 그리드와 같은 목록(실제로는 HTML 테이블)과 별도의 "new" 버튼이 있다고 가정합니다. 테이블의 각 행에는 해당 행과 관련된 "edit"와 "delete" 버튼이 있습니다.
"New"를 클릭한 후 새 페이지(여기서는 view라고 합니다)로 리디렉션하는 것은 효율적인 방법이 아닙니다. 왜냐하면, 리디렉션된 페이지에서 데이터가 저장된 후, 사용자는 데이터베이스에 추가된 데이터를 보기 위해 "목록 보기"를 클릭해야 하기 때문입니다. 이것은 목록 뷰로의 리디렉션과 가변 선택 비용으로 데이터베이스에서 데이터를 선택하는 것을 의미합니다!
위에서 언급한 "new를 클릭하고 다시 목록" 시나리오 대신, 더 나은 방법을 적용할 수 있습니다.
Create(생성):
  • 목록 뷰에서 "New"를 클릭한 후, "jQuery 저장 대화 상자"가 표시됩니다.
  • create 뷰가 jQuery 대화 상자에 렌더링됩니다.
  • create 폼에 입력하고 "Save"를 누릅니다.
  • Save 버튼이 눌리면, 데이터는 AJAX post를 통해 관련 controller에 전송될 수 있습니다.
  • Ajax 폼에는 onSuccess JavaScript 함수가 있습니다.
  • "onSuccess" JavaScript 메서드에서, 추가된 새 행("onSuccess"에 매개변수로 오는 JSON)은 전체 목록을 새로 고치지 않고 목록의 맨 앞에 추가(prepend)됩니다.
Read(읽기):
이것은 목록 작업입니다. 가능하다면, 목록 폼에는 필요한 데이터만 표시해야 합니다. 다음 기술을 사용할 수 있습니다:
  • 콤보박스 또는 숫자에 의한 페이징,
  • "더 보기" 구현,
  • 필터링이 있는 목록.
Update(업데이트):
  • 목록 뷰에서, 목록의 임의의 행의 "Edit"를 클릭한 후, 선택한 행의 데이터로 동일한 "jQuery 저장 대화 상자"를 표시할 수 있습니다.
  • 모든 단계는 "Create"와 동일하므로, "onSuccess" 메서드만 "update" 작업에 따라 변경됩니다.
  • 이 경우, 데이터베이스 업데이트 후, 편집된 행의 데이터만 뷰에서 업데이트됩니다. 이렇게 하면, 마지막으로 편집된 레코드를 보기 위해 전체 목록을 새로 고칠 필요가 없습니다.
Delete(삭제):
  • 보기 좋은 jQuery 대화 상자로 확인한 후, 데이터베이스 삭제 후, 선택된 행만 목록에서 제거됩니다. 다시, 전체 목록을 새로 고칠 필요가 없습니다.
insert와 edit 모두에 동일한 대화 상자가 사용됩니다.
새 레코드
새 레코드
PersonList.cshtml 뷰의 링크는 다음과 같습니다:
HTML
@Html.ActionLink("New", "Save", 
  new { personNo = 0 }, new { @class = "newLink" })
 
...
 
@Html.ActionLink("Edit", "Save", new { personNo = item.PersonNo }, new { @class = "editLink" })
  • New: 표시되는 텍스트.
  • Save: Controller 내의 action.
  • personNo: "Save" action에 전송되는 매개변수. 0이면 대화 상자가 비어 있는 상태로 열리고, 0보다 크면 해당 id의 데이터가 대화 상자에 표시됩니다.
  • newLink: 아래 jQuery에서 사용되는 가상 className.
JavaScript
<div id="saveDialog" title="Person Information"></div>
 
<script type="text/javascript">
 
    var linkObj;
 
    //.....

    $(document).ready(function () {
 
       //...

        $('#saveDialog').dialog({
            autoOpen: false,
            width: 400,
            resizable: false,
            modal: true,
            buttons: {
                "Save": function () {
                    $("#update-message").html('');
                    $("#savePersonForm").submit();
                },
                "Cancel": function () {
                    $(this).dialog("close");
                }
            }
        });
 
 
       //....

       setLinks();
 
    });
 
    // ....
  
    function setLinks() 
    {
 
        $(".editLink, .newLink, uploadPicLink").unbind('click');

        $(".editLink, .newLink").click
        (
            function () 
            {
                linkObj = $(this);
                var dialogDiv = $('#saveDialog');
                var viewUrl = linkObj.attr('href');
                $.get(viewUrl, function (data) 
                {
                    dialogDiv.html(data);
                    //validation
                    var $form = $("#savePersonForm");
                    $form.unbind();
                    $form.data("validator", null);
                    $.validator.unobtrusive.parse(document);
                    $form.validate($form.data("unobtrusiveValidation").options);

                    dialogDiv.dialog('open');
                });

                return false;

            }
        );
 
        //...

 
    } //end setLinks
</script>
PersonController의 Save action은 다음과 같습니다:
C#
// ...

[HttpGet]
public ActionResult Save(int personNo)
{
            
  Person person= new Person();
  person.BirthDate = DateTime.Today;
  person.PersonNo = 0;
            
  if (personNo > 0)
  {
     person = Repository.GetPersonList().Where(c => c.PersonNo == personNo).FirstOrDefault();
  }
 
  return PartialView(person);
 
}
 
 // ...  

[HttpPost]
public JsonResult Save(Person p)
{
     //...
}

// ...

2) JavaScript의 confirm 또는 alert 대신 jQuery 대화 상자를 사용하는 방법은?

사용자 정의 메시지 박스는 Windows 애플리케이션에서 가능합니다. 웹에서는 서드파티 컴포넌트 라이브러리를 사용할 때 가능합니다. 다음과 같은 JavaScript 박스 대신 jQuery 대화 상자를 사용하는 것도 가능합니다:
삭제 확인
삭제 확인
PersonList 뷰의 Delete 링크는 다음과 같습니다:
HTML
@Html.ActionLink("Delete", "DeletePerson", new { personNo = 
item.PersonNo }, new { @class = "deleteLink", @pkNo = item.PersonNo })
HTML과 jQuery 코드는 다음과 같습니다:
JavaScript
<div id="confirmDialog" title="Warning"></div>
 
<script type="text/javascript">
//...
 
 $(".deleteLink").live("click", function (e) {
        e.preventDefault();

        // ..
        
        $("#confirmDialog").html('<br/><br/>sure?');

        $("#confirmDialog").dialog({
            resizable: false,
            height: 200,
            width: 300,
            modal: true,
            buttons: {
                "Yes": function () {
                    // ..

                 }, // end of yes button
                "No": function () {
                    $(this).dialog("close");
                }
            } //end buttons
        }); //end modal 
    });     //end delete
 
//...  
</script>

3) MVC 목록에서 페이징을 수행하는 방법은?

페이징은 데이터 목록과 데이터 전송 비용을 최소화하기 위한 좋은 접근 방식 중 하나입니다. 데이터를 표시하는 많은 방법을 적용할 수 있습니다. 이 "하우투"에서는 페이징에 콤보박스가 사용됩니다. 그러나 필요에 따라 페이지 하단에 번호 매기기도 가능합니다. 이것은 애플리케이션과 개발자에 따라 다릅니다. 콤보박스에 의한 페이징은 다음과 같이 개발할 수 있습니다.
페이징
페이징
먼저, 페이징 메타데이터의 위치를 다음과 같이 준비합니다:
HTML
@model AddressBook_mvc3_jQuery.Models.Paginginfo

...
 
<div id="paginginfo">
<hr />
    <select id="PageSelect"></select>
    
    <span class="pagingPersonNo" style="visibility:hidden">@Model.id</span>
    <span class="pagingTotalCount" style="visibility:hidden">@Model.TotalCount</span>
    <span class="pagingPageSize" style="visibility:hidden">@Model.PageSize</span>
 
    <span class="pagingSummary">aaa</span>
 
<hr/>
</div>
 
<div id="content"></div>
 
...
페이지가 처음 로드되면, "paginginfo" id의 div가 채워지고, 다음 스크립트를 사용하여 레코드의 첫 번째 페이지가 표시됩니다.
JavaScript
<script type="text/javascript">
 
//...

  function initializePaging()
  {
       var PersonNo = $("#paginginfo .pagingPersonNo").text();
       var TotalCount = $("#paginginfo .pagingTotalCount").text();
       var PageSize = $("#paginginfo .pagingPageSize").text();
       
       var PageSelect = $("#PageSelect");
 
       if (TotalCount==0)
       {
            PageSelect.html("");
            $("#paginginfo").hide();
       }
       else
       {
             PageSelect.html("");
 
             var num = Math.ceil(TotalCount/PageSize);
 
             for (var i = 1; i <= num; i++) 
             {             
                 if (i==1)
                    PageSelect.append($("<option selected></option>").val(i).text(i));
                else
                    PageSelect.append($("<option></option>").val(i).text(i));
             }
      }
        
      fillData(PersonNo, 1); 
 
  }
 
//.. 

 function fillData(parPersonNo, parPageNo) 
 { 
    if (parPageNo) 
    {
        $.ajax({
            type: "POST", 
            url: "@Url.Action("GetAddressList", "Address")",
            data: { personNo: parPersonNo, pageNo: parPageNo },
            cache: false,
            dataType: "json",
            success: function (data) 
            {                                  
                if (data.Html) 
                {                       
                    $("#content").html(data.Html);
                    
                    buttonizeALL();
                    setLinkAbilites();
                    
                    setPagingSummary(parPageNo);
                }
                else 
                {
                    alert('opps!'); 
                }
            },
            error: function(exp)        
            {
                     alert('Error address : ' + exp.responseText);
            }                
        }); //end ajax call
    } // if (parPageNo) 

  }//fillData

//...

</script>
Controller 내의 action 코드는 다음과 같습니다. 보시다시피, 결과 리스트는 RenderPartialView 메서드를 사용하여 부분적으로 렌더링되고, JSON 객체에 배치됩니다.
C#
public class AddressController : Controller
{
  //..

  public JsonResult GetAddressList(int personNo, int pageNo)
  {
        
        int pageSize = 5; //it could be parameter
        int skipCnt = ((pageNo - 1) * pageSize);

        List<Address> list = (from x in Repository.GetAddressList() where x.PersonNo == 
          personNo orderby x.AddressNo descending select x).Skip(skipCnt).Take(pageSize).ToList();
       
        JsonResult jr = Json(new
        {
            Html = this.RenderPartialView("AddressList", list),
            Message = "OK"
        }, JsonRequestBehavior.AllowGet);

        return jr;
  }
  //..

}
"PageSelect" id의 콤보의 selecteditem이 변경되면, 다음 jQuery 스크립트가 동작합니다.
JavaScript
//..

    $("#PageSelect").change(function () 
    {
 
        var $this = $(this);
        var parPageNo = $this.val();
 
        var parPersonNo = $("#paginginfo .pagingPersonNo").text();
 
        fillData(parPersonNo,parPageNo);
                      
    });//PageSelect

//..

4) jQuery를 사용하여 MVC에서 "더 보기" 링크를 만드는 방법은?

이 기술은 많은 인기 있는 웹사이트에서 사용됩니다. 큰 목록에 적용해야 합니다. "더 보기"는 다음과 같이 구현할 수 있습니다:
더 보기
더 보기
목록 뷰에는 "more" 링크가 있습니다.
HTML
//
 
<table id="NoteTable"></table>
 
<br />
<a href="#"  style="display:none"  id="more">more</a>
 
<div id="saveDialog" title="Notes Information"></div>
<div id="confirmDialog" title="Warning"></div>
 
//
"more"가 클릭되면, 다음 jQuery 스크립트가 동작합니다.
JavaScript
//..

   //load more results
    $(function () 
    {
        $("#more").click(function (e) 
        {
            e.preventDefault();
                       
            var lastNoteNo = $("#NoteTable tr:last .noteNo").text();

            if (lastNoteNo) 
            {
                var PersonNo = $("#paginginfo .pagingPersonNo").text();
                fillData(PersonNo, lastNoteNo); 
            }
 
            //--- scroll to bottom of page ---
            var $target = $('html,body'); 
            $target.animate({scrollTop: $target.height()}, "slow");
            //--- /scroll to bottom of page ---

            return false;
        });
    });
 
//..

 
   function fillData(parPersonNo, parLastNoteNo) 
    {                 
        if (parPersonNo) 
        {
            $.ajax({
                type: "POST",                
                url: "@Url.Action("GetNoteList", "Note")",
                data: { personNo: parPersonNo,  lastNoteNo: parLastNoteNo} ,
                cache: false,
                dataType: "json",
                success: function (data) 
                {
                    if (data.Html) 
                    {
                        $("#NoteTable").append(data.Html);
                        
                        buttonizeALL();
                        setLinkAbilites();
                        
                        if (data.HasMore)
                            $("#more").show();
                        else                        
                            $("#more").hide();
                    }
                    else 
                    {
                        alert('opps!'); 
                    }
                },                
                error: function(exp)        
                {
                        alert('Error address : ' + exp.responseText);
                }                
            }); //end ajax call
        } // if 
    }//func

// ..
Controller 내의 다음 action은 JSON 결과를 반환합니다.
C#
public class NoteController : Controller
{
   //...

    public JsonResult GetNoteList(int personNo,  int lastNoteNo)
    {
        int pageSize = 5; //it could be parameter
        bool hasMore = false;

        List<Note> list = null;

        if (lastNoteNo == 0)
        {            
            list = (from x in Repository.GetNoteList() where x.PersonNo == personNo 
              orderby x.NoteNo descending select x).Take(pageSize).ToList();
            hasMore = (from x in Repository.GetNoteList() where x.PersonNo == 
              personNo select x.NoteNo).Take(pageSize + 1).Count() - pageSize > 0;
        }
        else
        {
            list = (from x in Repository.GetNoteList() where x.NoteNo < lastNoteNo && 
              x.PersonNo == personNo orderby x.NoteNo descending select x).Take(pageSize).ToList();
            hasMore = (from x in Repository.GetNoteList() where x.NoteNo < lastNoteNo && 
              x.PersonNo == personNo select x.NoteNo).Take(pageSize + 1).Count() - pageSize > 0;
        }
        
        JsonResult jr = Json(new
        {
            Html = this.RenderPartialView("_NoteList", list),
            Message = "OK",
            HasMore = hasMore
        }, JsonRequestBehavior.AllowGet);

        return jr;
    }

  // ...
}

5) 링크에서 속성(attribute)을 사용하는 방법은?

이것은 특히 편집, 삭제, 상세 보기 등의 버튼에 사용하기에 좋은 기능입니다.
목록이 생성될 때, 관련 키가 링크에 속성으로 추가됩니다. 링크의 클릭 이벤트에서 해당 키가 사용되어 작업이 쉽게 수행됩니다.
예를 들어, 목록의 각 행에 삭제 링크가 있다고 가정합니다. 행의 삭제 링크가 클릭되면, controller 내의 "delete action"의 매개변수로 키를 사용하는 것이 가능합니다.
HTML
@Html.ActionLink("Delete", "DeletePerson", new { personNo = item.PersonNo }, 
  new { @class = "deleteLink", @pkNo = item.PersonNo })
클라이언트에서 소스를 확인하면, 다음 행이 표시됩니다.
HTML
<a role="button" class="deleteLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" 
  href="/Person/DeletePerson/1" pkno="1"><span class="ui-button-text">Delete</span></a>
jQuery 스크립트에서, 속성은 다음과 같이 사용됩니다. 예를 들어, pkno는 1로 사용됩니다.
JavaScript
$(".deleteLink").live("click", function (e) 
{
      e.preventDefault();
      var pkNo = $(this).attr("pkNo");
      //..
});

6) jQuery에서 AJAX 호출을 수행하는 방법은?

AJAX 호출은 애플리케이션을 더 빠르게 만들기 위한 매우 좋은 기능입니다. 데이터베이스에 대량의 데이터가 있는 일부 애플리케이션에서는, 개발자는 두 개의 데이터 라인에서 소량의 데이터를 전송하는 것에 주의를 기울여야 합니다. 첫 번째 라인은 데이터베이스와 애플리케이션 사이, 두 번째는 애플리케이션과 클라이언트 브라우저 사이입니다. 이러한 요구 사항에는 AJAX 호출이 매우 편리합니다.
JavaScript
//..

  $.ajax({
            type: "POST",
            url: "/Person/DeletePerson", 
            data: { personNo: pkNo },
            cache: false,
            dataType: "json",
            success: function () 
            {
                       //.. 
            },
            error: function (jqXHR, exception) 
            {
                 alert('Uncaught Error.\n' + jqXHR.responseText);
            }
         }); //end ajax call

//..
URL은 다음과 같이도 사용할 수 있습니다.
JavaScript
//..

url: "@Url.Action("DeletePerson", "Person")",
 
// ..

7) MVC에서 Form 컴렉션을 사용하는 방법은?

폼이 포스트되면, 모든 폼 요소가 controller 내의 관련 action에 컴렉션으로 전송됩니다. controller에서는 각 키와 값 쌍을 사용할 수 있습니다. 다음과 같은 저장 폼이 있다고 가정합니다:
HTML
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
 
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
                            {
                                InsertionMode = InsertionMode.Replace,
                                HttpMethod = "POST",
                                OnSuccess = "saveSuccess"
                            }, new { @id = "saveForm" }))
{
    @Html.ValidationSummary(true)
    <input style="visibility:hidden" type="text" name="TBPersonNo" 
      id="idTBPersonNo" value="@Model.PersonNo"/>
    <input style="visibility:hidden" type="text" name="TBAddressNo" 
      id="idTBAddressNo" value="@Model.AddressNo"/>
    
    <br />        
    <fieldset>       
        <table>        
        <tr>
        <td>Address Type</td>
        <td>        
          <select name="CBAddressType" id="idCBAddressType" style="width:120px">
          </select>
        </td>
        </tr>
        <tr>
        <td>Country</td>
        <td>            
            <select name="CBcountry" id="idCBcountry" style="width:120px">
            </select>
        </td>
        </tr>
        <tr>
        <td>City</td>
        <td>            
            <select name="CBcity" id="idCBcity" style="width:120px">
            </select>
        </td>
        </tr>
        <tr>
        <td>AddressText</td>
        <td>        
        <textarea rows="4" cols="25" name="TBAddressText" 
          id="idTBAddressText">@Model.AddressText</textarea>            
        </td>
        </tr>
        </table>        
    </fieldset>
}
뷰의 데이터는, 다음에 보이는 것처럼 모델 객체 또는 FormCollection으로 controller 내의 action에 전송할 수 있습니다:
C#
//..
 
[HttpPost]
public JsonResult Save(FormCollection fc)
{
    object obj = null;

                
    Address addrTmp = new Address();
    addrTmp.AddressNo = Convert.ToInt32(fc["TBAddressNo"].ToString());
    addrTmp.AddressTypeNo = Convert.ToInt32(fc["CBAddressType"].ToString());
    addrTmp.AddressText = fc["TBAddressText"].ToString();
    addrTmp.CityNo = Convert.ToInt32(fc["CBcity"].ToString()); ;
    addrTmp.PersonNo = Convert.ToInt32(fc["TBPersonNo"].ToString()); 
    
    if (ModelState.IsValid)
    {
        if (addrTmp.AddressNo == 0)
        {
            //find last person 
            //if it is database system no need to this line. Probably the AddressNo would be autoincrement
            addrTmp.AddressNo = Data.Repository.GetAddressList().OrderBy(x => x.AddressNo).Last().AddressNo + 1;

            Data.Repository.GetAddressList().Add(addrTmp);
            

            obj = new { Success = true, 
                        Message = "Added successfully", 
                        Object = addrTmp, 
                        operationType = "INSERT", 
                        Html = this.RenderPartialView("_addressLine", addrTmp )
                      };
        }
        else
        {
            Address addr = Repository.GetAddressList().Where(c => c.AddressNo == addrTmp.AddressNo).FirstOrDefault();
            addr.AddressTypeNo = addrTmp.AddressTypeNo;
            addr.AddressText = addrTmp.AddressText;
            addr.CityNo = addrTmp.CityNo;
            addr.PersonNo = addrTmp.PersonNo;

            obj = new { Success = true, 
                        Message = "Updated successfully", 
                        Object = addr, 
                        operationType = "UPDATE",
                        Html = this.RenderPartialView("_addressLine",  addr )
                      };
        }                

    }
    else
    {
        obj = new { Success = false, Message = "Please check form" };
    }

    return Json(obj, JsonRequestBehavior.DenyGet);
}
 
//..

8) 한 번에 여러 레코드를 삭제하는 방법은?

일부 페이지에서는, 한 번에 많은 레코드를 삭제하면 작업이 쉬워질 수 있습니다. 여러 레코드를 삭제하는 것은 선택한 모든 레코드의 키를 수집함으로써 가능합니다. 모든 키가 controller에 전송된 후, 다음과 같이 삭제를 수행할 수 있습니다.
여러 삭제
여러 삭제
먼저 "deleteALL" id의 "Delete Selected" 버튼이 클릭됩니다. Yes를 누른 후, 다음 jQuery 스크립트를 사용할 수 있습니다. 물론, 대체 스크립트도 개발할 수 있습니다.
JavaScript
//..

$("#deleteALL").live("click", function (e) 
{
    e.preventDefault();
    
    var len = $("#NoteTable tr").length;
    
    $("#confirmDialog").html('<br/><br/>deleting all selecteds.. sure?');

    $("#confirmDialog").dialog({
        resizable: false,
        height: 200,
        width: 300,
        modal: true,
        buttons: 
        {
            "Yes": function () 
            {
                $(this).dialog("close");
                
                    var strSelecteds = '';
                    var rows = $("#NoteTable tr");

                    for(var i=0; i< rows.length; i++)
                    {                               
                        var row = $(rows).eq(i);

                        var span = row.find('span#cboxSpan');
                        var cb = row.find('span#cboxSpan').find('input.cboxDELclass');
                        
                        var checked=(cb.is(':checked'));

                        var pkno =  cb.attr("pkno"); 

                        if (checked)
                        {
                            strSelecteds = strSelecteds + pkno + ',';
                        }
                    }//
                            
                    if (strSelecteds.length>0)
                    {
                        strSelecteds = strSelecteds.substring(0,strSelecteds.length-1);
                    }
                    
                    if (strSelecteds.length>0)
                    {
                        $.ajax({
                            type: "POST",
                            url: "/Note/DeleteALL",   
                            data: { noteNOs: strSelecteds },
                            cache: false,
                            dataType: "json",
                            success: function (data) 
                            {
                                var  strSelectedsArr = strSelecteds.split(',');
                                for (var i = 0; i < strSelectedsArr.length; i++) 
                                {
                                    var rowNo = '#row-' + strSelectedsArr[i];
                                    $(rowNo).remove();  
                                    //alert(strSelectedsArr[i]);

                                }//for
                                

                                $('#saveDialog').dialog('close');
                                $('#Message').html(data.Message);
                                $('#Message').delay(300).slideDown(300).delay(1000).slideUp(300);
                            },                          
                            error: function(jqXHR, exception) 
                            {
                                alert('Uncaught Error.\n' + jqXHR.responseText);
                            }

                        }); //end ajax call
                    }
                    else
                        alert('No row selected');

            }, // end of yes button
            "No": function () 
            {
                $(this).dialog("close");
            }
        } //end buttons
    }); //end modal 

});    //end deleteALL
 
//...
위에서 보는 것처럼, 여러 레코드 삭제는 "Note" controller 내의 "DeleteALL" action에 대한 ajax 호출로 수행됩니다.

9) MVC에서 Partial Action을 사용하는 방법은?

일부 상황에서는, 많은 폼에서 사용해야 하는 컴포넌트가 필요합니다. 예를 들어, 다음에 보이는 것처럼 몇 가지 별도의 폼에서 "인물 정보 박스"가 필요할 수 있습니다.
HTML Action
HTML Action
_personinfo 뷰는 다음과 같습니다.
HTML
@model AddressBook_mvc3_jQuery.Models.Person
 
@{ ViewBag.Title = "_personinfo"; }
           
<fieldset>
    <legend>Person info</legend>
 
    <table>
<tr><td><b><span> @Model.FirstName @Model.LastName </span></b>(@String.Format("{0:dd.MM.yyyy}", 
  Model.BirthDate))</td><td>(@Model.CategoryName)</td></tr>
    </table>
 
</fieldset>
임의의 뷰에서 partial action을 사용하려면, 다음 코드 행을 사용할 수 있습니다.
HTML
//..
 
<h2>Address List</h2>
<div> 
    @Html.Action("_personinfo", "Common") 
</div> 
 
//..

10) MVC 애플리케이션에서 JSON 형식을 사용하는 방법은?

JSON 형식은 controller 내의 action에 매개변수를 전송할 때와 action에서 결과를 가져올 때 사용할 수 있습니다. 다음에 보이는 것처럼, Note controller 내의 DeleteNote action에는 noteNo 매개변수가 있습니다. 여기서, pkNo는 값으로 호출되는 매개변수입니다.
JavaScript
$(".deleteLink").live("click", function (e) 
{
    e.preventDefault();

    var pkNo = $(this).attr("pkNo");

    //..

    $.ajax({
             type: "POST",
             url: "/Note/DeleteNote",
             data: { noteNo: pkNo },
             cache: false,
             dataType: "json",
             success: function () 
             {
               $(rowNo).remove();
             },
             error: function(jqXHR, exception) 
             {
                alert('Uncaught Error.\n' + jqXHR.responseText);
             }
            }); //end ajax call

    //.. 

});    //end delete
controller 내의 action에서 JSON 결과를 가져오는 것이 가능합니다. 다음 스크립트는 결과를 json 객체로 반환합니다.
C#
//..
 
[HttpPost]
public JsonResult DeleteNote(int noteNo)
{

    string message = string.Empty;

    try
    {
        Note n = Data.Repository.GetNoteList().Where(c => c.NoteNo == noteNo).FirstOrDefault();

        if (n != null)
        {
            Data.Repository.GetNoteList().Remove(n);
            message = "Deleted";
        }
        else
        {
            message = "Note not found!";
        }

    }
    catch (Exception ex)
    {
        message = ex.Message;
    }

    return Json(new { Message = message }, JsonRequestBehavior.AllowGet);
}

 
//..

11) 마스터 상세 콤보 박스를 채우는 방법은?

일부 폼에서는, 하나의 콤보박스를 변경할 때 다른 콤보박스를 채워야 합니다. 예를 들어, 국가-도시 쌍에서, 국가가 마스터이고 도시가 상세라고 생각할 수 있습니다.
마스터 상세 콤보박스
마스터 상세 콤보박스
"저장 폼"의 뷰의 html은 다음과 같습니다.
HTML
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
 
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
                            {
                                InsertionMode = InsertionMode.Replace,
                                HttpMethod = "POST",
                                OnSuccess = "saveSuccess"
                            }, new { @id = "saveForm" }))
{
    @Html.ValidationSummary(true)
    <input style="visibility:hidden" type="text" name="TBPersonNo" 
      id="idTBPersonNo" value="@Model.PersonNo"/>
    <input style="visibility:hidden" type="text" name="TBAddressNo" 
      id="idTBAddressNo" value="@Model.AddressNo"/>
    
    <br />        
    <fieldset>       
        <table>        
        <tr>
        <td>Address Type</td>
        <td>        
          <select name="CBAddressType" id="idCBAddressType" style="width:120px">
          </select>
        </td>
        </tr>
        <tr>
        <td>Country</td>
        <td>            
            <select name="CBcountry" id="idCBcountry" style="width:120px">  
            </select>
        </td>
        </tr>
        <tr>
        <td>City</td>
        <td>            
            <select name="CBcity" id="idCBcity" style="width:120px"> 
            </select>
        </td>
        </tr>
        <tr>
        <td>AddressText</td>
        <td>        
        <textarea rows="4" cols="25" name="TBAddressText" 
          id="idTBAddressText">@Model.AddressText</textarea>
        </td>
        </tr>
        </table>        
    </fieldset>
}
처음 로드 시, Address controller 내의 "GetCountryList" action을 사용하여 idCBCountry 콤보박스가 채워집니다. 그 후, 국가 콤보박스가 변경되면, 다음과 같이 도시 콤보박스가 채워집니다.
JavaScript
<script type="text/javascript">
 
    $(document).ready(function () {  
 
    //...
    //-----------------------------------------------------
    
                
   $.ajax({
        type: "POST",
        url: "@Url.Action("GetCountryList", "Address")",
        data: {},
        cache: false,
        dataType: "json",
        success: function (data) 
        {                               
             var idCBcountry = $("#idCBcountry");
             idCBcountry.html("");
                    
              if (@Model.AddressNo>0)
              {
                 for (var i = 0; i < data.List.length; i++) 
                 {
                    var item = data.List[i];

                    if (item.CountryNo == @Model.CountryNo)
                    {                                
                        idCBcountry.append($("<option selected></option>").val(item.CountryNo).text(item.CountryName));
                        fillCity(item.CountryNo);
                    }
                    else
                    {
                        idCBcountry.append($("<option />").val(item.CountryNo).text(item.CountryName));
                    }
                 }  //for   
              }      
              else
              {
                    for (var i = 0; i < data.List.length; i++) 
                     {
                        var item = data.List[i];
                        if (i==0)
                        {
                            idCBcountry.append($("<option selected></option>").val(item.CountryNo).text(item.CountryName));
                            fillCity(item.CountryNo);
                        }
                        else
                        {
                            idCBcountry.append($("<option />").val(item.CountryNo).text(item.CountryName));
                        }
                     }  //for
              }//else
            },  
            error: function(exp)        
            {
                 alert('ErrorCountry : ' + exp.responseText);
            }
        });
 
        //-----------------------------------------------------

            $("#idCBcountry").change(function () {
                var $this = $(this);
                var CountryNo = $this.val();
                if (CountryNo) 
                {
                    fillCity(CountryNo);

                }//if
            });

            //-----------------------------------------------------

});//end of function
 
function fillCity(parCountryNo)
{

    $.ajax({
        type: "POST",
        url: "@Url.Action("GetCityList", "Address")",
        data: {CountryNo: parCountryNo},
        cache: false,
        dataType: "json",
        success: function (data) 
        {
             var idCBcity = $("#idCBcity");
             idCBcity.html("");

             for (var i = 0; i < data.List.length; i++) 
             {
                var item = data.List[i];

                if (item.CityNo == @Model.CityNo)
                {
                    idCBcity.append($("<option selected></option>").val(item.CityNo).text(item.CityName));
                }
                else
                {
                    idCBcity.append($("<option />").val(item.CityNo).text(item.CityName));
                }
             }
        },
        error: function(exp)        
        {
             alert('ErrorCity : ' + exp.responseText);
        }
    });
}//fillCity

</script>
action 코드는 다음과 같습니다. 리스트는 json 객체에 포함됩니다. 그 후, 위의 jQuery 스크립트에서, 리스트 요소는 인덱스로 사용됩니다.
C#
public class AddressController : Controller
{
    //..

    public JsonResult GetCountryList()
    {
        object obj = null;
        List<Country> list = Repository.GetCountryList();
        obj = new { Success = true, Message = "OK", List = list };

        return Json(obj, JsonRequestBehavior.AllowGet);
    }
   
    public JsonResult GetCityList(int CountryNo)
    {
        object obj = null;

        List<City> list = Repository.GetCityList().Where(c => c.CountryNo == CountryNo).ToList(); ;
        obj = new { Success = true, Message = "OK", List = list };

        return Json(obj, JsonRequestBehavior.AllowGet);
    }

   //..
}
이 기술은 뷰 폼 내의 임의의 html 요소에 사용할 수 있습니다.

12) jQuery datepicker를 사용하는 방법은?

날짜 타입은 거의 모든 비즈니스 애플리케이션에서 사용됩니다. 문화의 차이로 인해, 이 타입을 사용하는 것은 개발자에게 문제를 의미할 수 있습니다. 그러나, jQuery datepicker는 날짜 타입 사용을 용이하게 합니다.
jQuery Datepicker
jQuery Datepicker
목록에서 원하는 형식으로 날짜를 표시하려면, 다음 행을 사용할 수 있습니다.
HTML
<span class="BirthDate"> @String.Format("{0:dd.MM.yyyy}", item.BirthDate) </span>
저장 폼에서는 다음 html 스크립트가 사용됩니다.
HTML
  ...
       
    <div class="editor-label">
        @Html.LabelFor(model => model.BirthDate)
    </div>
    <div class="editor-field">         
        @Html.TextBoxFor(model => model.BirthDate, 
                new { @class = "BirthDateSave", 
                      @id = "TBBirthDate",
                      @Value = Model.BirthDate.ToString("dd.MM.yyyy") 
                    })
    </div>

   ...
jQuery Datepicker는 동일 페이지 내에서 다음 스크립트로 @Html.TextboxFor와 연계할 수 있습니다.
JavaScript
<script language="javascript" type="text/javascript">
 
 $(document).ready(function () {
    $(".BirthDateSave").datepicker({  
             changeMonth: true,
             changeYear: true,  
             dateFormat: 'dd.mm.yy',
             showOn: 'both'
                   });  
                });

</script>
적절한 .cshtml의 상단에 다음 행을 포함해야 합니다.
HTML
..
  <link href="@Url.Content("~/Content/themes/base/jquery.ui.all.css")" rel="stylesheet" type="text/css" />
  <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>    
  <script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")" type="text/javascript"></script>
..

13) jQuery 대화 상자를 사용하여 MVC에서 이미지를 업로드하는 방법은?

이미지는 별도의 뷰에서 쉽게 업로드할 수 있습니다. 그러나, 이미지를 업로드하기 위해서만 별도의 뷰로 리디렉션하고, 그 후 목록 뷰로 리디렉션하는 것은 비용 측면에서 비효율적일 수 있습니다. 대신, 목록 뷰에서, 각 행의 업로드 링크를 클릭하여 jQuery 대화 상자를 열고, 이미지를 찾아 업로드할 수 있습니다.
이미지 업로드
이미지 업로드
"Upload Pic"이 클릭되면, 다음 스크립트가 동작합니다.
JavaScript
//..

$(".uploadPicLink").click
(
    function () 
    {

        linkObj = $(this);

        var dialogDiv = $('#savePicDialog');
        var viewUrl = linkObj.attr('href');
        $.get(viewUrl, function (data) {
            dialogDiv.html(data);
            //validation
            var $form = $("#savePersonPicForm");
            $form.unbind();
            $form.data("validator", null);
            $.validator.unobtrusive.parse(document);
            $form.validate($form.data("unobtrusiveValidation").options);

            dialogDiv.dialog('open');
        });

        return false;
    }
);

//..
jQueryダイアログに読み込まれるSavePersonPicフォームは以下のとおりです。jQueryダイアログでファイルをアップロードするためにiframeが使用されます。
HTML
@model AddressBook_mvc3_jQuery.Models.Person            
@{ViewBag.Title = "Save image";}

@using (Html.BeginForm("SavePersonPic", "Person", FormMethod.Post,
             new
             {
                enctype = "multipart/form-data",        
                id = "savePersonPicForm",
                name = "savePersonPicForm",
                target = "UploadTarget"
              }))        
{
    @Html.ValidationSummary(true)    
    
    <div id="update-message" class="error invisible"></div>    
    <fieldset>
        <legend>Person Picture</legend> 
        <div class="editor-label">
            <label for="file">Upload Image:</label>
        </div>
        <div class="editor-field">
            <input type="file" name="file" id="file"/>        
        </div>      
 
    </fieldset>        
}

<iframe id="UploadTarget" 
   name="UploadTarget" onload="UploadImage_Complete();" 
        style="position: absolute; left: -999em; top: -999em;">
</iframe>
controller内のファイルアップロードactionは以下のとおりです:
C#
public class PersonController : Controller
{
    //..
    //-------------- image -----

    [HttpGet]
    public ActionResult SavePersonPic(int personNo)
    {

        Person person = new Person();
                    
        if (personNo > 0)
        {
            person = Repository.GetPersonList().Where(c => c.PersonNo == personNo).FirstOrDefault();
        }

        return PartialView(person);
    }
 
    [HttpPost]        
    public JsonResult SavePersonPic(HttpPostedFileBase file,   int personNo)
    {                
        string message = string.Empty;
        bool success = false;
        string imgPath = "";
        string fileName = "";
        try
        {
            string path = System.IO.Path.Combine(Server.MapPath("~/Content/images"), 
                            System.IO.Path.GetFileName(file.FileName));
            file.SaveAs(path);

            Person p = Data.Repository.GetPersonList().Where(r => r.PersonNo == personNo).FirstOrDefault();
            p.imgFileName = file.FileName;
            ViewBag.Message = "File uploaded successfully";
            message = ViewBag.Message;

            fileName = file.FileName;
            imgPath = Url.Content(String.Format("~/Content/images/{0}", fileName)); 
            
            success = true;

        }
        catch (Exception ex)
        {
            message = ex.Message;
            success = true;
            imgPath = "";
            fileName = "";
        }
 
        return Json(
                        new { Success = success, 
                              Message = message, 
                              PersonNo=personNo,
                              ImagePath = imgPath,
                              FileName = fileName
                            }, 
                        JsonRequestBehavior.AllowGet
                    );

    }

    //------------- /image --------
    // ..
}
iframe의 JavaScript "onload" 함수는 다음과 같습니다. 업로드된 이미지는 행을 새로 고치지 않고 목록의 관련 행에 표시됩니다.
JavaScript
//..

function UploadImage_Complete() 
{            
    //Check first load of the iFrame
    if (isFirstLoad == true) 
    {
        isFirstLoad = false;
        return;
    }

    try 
    {            
        //Reset the image form
        document.getElementById("savePersonPicForm").reset();
    
        var jsonTxt = ($('#UploadTarget').contents()).text();            
        var jsonObj = JSON.parse(jsonTxt);
        
        var rowid = '#row-' + jsonObj.PersonNo;            
        var row = $('#personTable ' + rowid);           
        var imgid = "#img-" + jsonObj.PersonNo;
        var img = row.find(imgid);
            $(img).attr("src", jsonObj.ImagePath);

       
        $('#Message').html(jsonObj.Message);
        $('#Message').delay(300).slideDown(300).delay(1000).slideUp(300)


        $('#savePicDialog').dialog('close');
    }
    catch (err) 
    {
        alert(err.get_Message());
    }
}
 
//..

14) 클라이언트 측에서 테이블 행을 생성하는 방법은?

데이터베이스에 추가된 레코드는 클라이언트 측 목록에 표시해야 합니다. 이것은 많은 방법으로 할 수 있습니다. 레코드가 추가된 후, 목록은 데이터베이스에서 완전히 새로 고칠 수 있지만, 이것은 무거운 작업이 됩니다. 그러나, javascript 또는 jquery를 사용하면, 뷰 내의 모든 요소를 새로 고치지 않고 뷰에 새 행을 추가할 수 있습니다. 여기서는 두 가지 방법에 대해 설명합니다.
먼저, 다음과 같이 행과 행의 셀이 javascript로 하나씩 생성됩니다. 다음 스크립트에 표시된 것처럼, 이 폼의 submit 후, saveSuccess JavaScript 함수가 이러한 시나리오에 사용됩니다.
HTML
..
 
@model AddressBook_mvc3_jQuery.Models.Person
            
@{  ViewBag.Title = "Save Person"; }
 
..
 
@using (Ajax.BeginForm("Save", "Person", new AjaxOptions
{
    InsertionMode = InsertionMode.Replace,
    HttpMethod = "POST",
    OnSuccess = "saveSuccess"    
}, new { @id = "savePersonForm" }))
{
    @Html.ValidationSummary(true)    
    
    ..        
}
 
..
saveSuccess javascript 메서드는 다음과 같습니다. action은 작업 타입을 포함하는 json 결과를 반환합니다. 작업에 따라, 즉 INSERT 또는 UPDATE에 따라, 뷰 내의 테이블이 변경됩니다. 데이터베이스에 새 레코드가 추가되면, 테이블에 새 행이 추가(prepend)됩니다. 데이터베이스 내의 기존 레코드가 업데이트되면, 테이블 내의 관련 행만 변경됩니다.
JavaScript
function saveSuccess(data) 
{
    if (data.Success == true) 
    {
        if (data.operationType == 'UPDATE') 
        {
            //we update the table's row info
            var parent = linkObj.closest("tr");
            
            $(parent).animate({ opacity: 0.3 }, 200, function () 
            {;});

            parent.find(".FirstName").html(data.Object.FirstName);
            parent.find(".LastName").html(data.Object.LastName);
            parent.find(".CategoryName").html(data.Object.CategoryName);

            var date = new Date(parseInt(data.Object.BirthDate.substr(6)));
            var dateStr = FormatDate(date);                                     
            parent.find(".BirthDate").html(dateStr);


            $(parent).animate({ opacity: 1.0 }, 200, function () {
                ;
            });

        }
        else 
        {  //INSERT

            //we add the new row to table
            //we do not refresh all records on screen
            
            try 
            {                    
                var personTable = document.getElementById("personTable");
                var row = personTable.insertRow(1); //row 0 is header
                row.setAttribute("id", 'row-' + data.Object.PersonNo.toString());
                                                                 
                var buttonsLinks =
                '<a role="button" class="editLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only ui-state-hover ui-state-focus" href="/Person/Save/' + data.Object.PersonNo.toString() + '"><span class="ui-button-text">Edit</span></a> ' +
                '<a role="button" class="adressLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="/Address/Index/' + data.Object.PersonNo.toString()  + '"><span class="ui-button-text">Addresses</span></a> ' +
                '<a role="button" class="noteLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="/Note/Index/' + data.Object.PersonNo.toString() + '"><span class="ui-button-text">Notes</span></a> ' +
                '<a role="button" class="deleteLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="/Person/Delete/' + data.Object.PersonNo.toString() + '" pkno="' + data.Object.PersonNo.toString()  + '"><span class="ui-button-text">Delete</span></a>';

        
                var cellButtons = row.insertCell(0);
                cellButtons.innerHTML = buttonsLinks;

                var cellPersonNo = row.insertCell(1);
                cellPersonNo.innerHTML = "<span  class=\"PersonNo\">" + data.Object.PersonNo + "</span>";


                var cellCategoryName = row.insertCell(2);
                cellCategoryName.innerHTML = "<span  class=\"CategoryName\">" + data.Object.CategoryName + "</span>";

                var cellFN = row.insertCell(3);
                cellFN.innerHTML = "<span  class=\"FirstName\">" + data.Object.FirstName + "</span>";
                
                var cellLN= row.insertCell(4);
                cellLN.innerHTML = "<span  class=\"LastName\">" + data.Object.LastName + "</span>";

                var cellBirthDate = row.insertCell(5);
                var date = new Date(parseInt(data.Object.BirthDate.substr(6)));
                var dateStr = FormatDate(date);
                cellBirthDate.innerHTML = "<span  class=\"BirthDate\">" + dateStr + "</span>";

                var cellimgFileName = row.insertCell(6);
                cellimgFileName.innerHTML =
                    "<img id=\"img-" + data.Object.PersonNo.toString() + "\" alt=\"" + data.Object.ImgFileName + "\" src=\"/content/images/" + "noimg.jpg" + "\" height=\"35px\" width=\"50px\"><br><a class=\"uploadPicLink\" href=\"/Person/SavePersonPic/" + data.Object.PersonNo.toString() + "\" pkno=\"" + data.Object.PersonNo.toString() + "\" style=\"font-size:9px;\">Upload Pic</a>";

                
                setLinks();
                                 
            }
            catch (err) {
                alert(err.Message);
            }                               
        }
        
        $('#saveDialog').dialog('close');
        $('#Message').html(data.Message);
        $('#Message').delay(300).slideDown(300).delay(1000).slideUp(300);

    }
    else {
        $("#update-message").html(data.ErrorMessage);
        $("#update-message").show();
    }
}
上記で述べた最初の方法は古いアプローチのように見えるかもしれません。そのため、以下の2番目の方法がより適用しやすいかもしれません。この方法では、レンダリングされたhtmlを使用してテーブルに行を追加または更新します。以下のようなテーブルがあると仮定します。
HTML
@model IEnumerable<AddressBook_mvc3_jQuery.Models.Address>

<table id="AddressTable">
    <tr>
        <th></th>
        <th>
            #
        </th>       
        <th>
            AddressType
        </th>
        <th>
            City/Country
        </th>
        <th>
            Address Text
        </th>        
    </tr>
 
@foreach (var item in Model) 
{
    <tr id="row-@item.AddressNo">
        <td>            
            @Html.ActionLink("Edit", "Save", 
              new { addressNo = item.AddressNo, personNo = item.PersonNo }, new { @class = "editLink" })
            @Html.ActionLink("Delete", "DeleteAddress", 
              new { addressNo = item.AddressNo }, new { @class = "deleteLink", @pkNo = item.AddressNo })
        </td>
        <td>            
            <span class="AddressNo">@item.AddressNo</span>
        </td>       
        <td>            
            <span class="AddressTypeName">@item.AddressTypeName</span>
        </td>
        <td>            
            <span class="CityName">@item.CityName/@item.CountryName</span>
        </td>
        <td>            
            <span class="AddressText">@item.AddressText</span>
        </td>       
    </tr>
}
 
</table>
"new"가 클릭되면, 다음 스크립트가 jQuery 대화 상자에 로드됩니다.
HTML
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
 
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
                            {
                                InsertionMode = InsertionMode.Replace,
                                HttpMethod = "POST",
                                OnSuccess = "saveSuccess"
                            }, new { @id = "saveForm" }))
{
    @Html.ValidationSummary(true)
    <input style="visibility:hidden" type="text" 
      name="TBPersonNo" id="idTBPersonNo" value="@Model.PersonNo"/>
    <input style="visibility:hidden" type="text" 
      name="TBAddressNo" id="idTBAddressNo" value="@Model.AddressNo"/>
    
    <br />        
    <fieldset>       
        <table>        
        <tr>
        <td>Address Type</td>
        <td>        
          <select name="CBAddressType" id="idCBAddressType" style="width:120px">
          </select>
        </td>
        </tr>
        <tr>
        <td>Country</td>
        <td>            
            <select name="CBcountry" id="idCBcountry" style="width:120px">
            </select>
        </td>
        </tr>
        <tr>
        <td>City</td>
        <td>            
            <select name="CBcity" id="idCBcity" style="width:120px">
            </select>
        </td>
        </tr>
        <tr>
        <td>AddressText</td>
        <td>        
        <textarea rows="4" cols="25" name="TBAddressText" 
              id="idTBAddressText">@Model.AddressText</textarea>
        </td>
        </tr>
        </table>        
    </fieldset>
}
폼이 제출되면, controller 내의 다음 action이 동작합니다.
C#
public class AddressController : Controller
{

    //..

    [HttpPost]
    public JsonResult Save(FormCollection fc)
    {
        object obj = null;

        Address addrTmp = new Address();
        addrTmp.AddressNo = Convert.ToInt32(fc["TBAddressNo"].ToString());
        addrTmp.AddressTypeNo = Convert.ToInt32(fc["CBAddressType"].ToString());
        addrTmp.AddressText = fc["TBAddressText"].ToString();
        addrTmp.CityNo = Convert.ToInt32(fc["CBcity"].ToString()); ;
        addrTmp.PersonNo = Convert.ToInt32(fc["TBPersonNo"].ToString()); 
        
        if (ModelState.IsValid)
        {
            if (addrTmp.AddressNo == 0)
            {
                //find last person 
                //if it is database system no need to this line. Probably the AddressNo would be autoincrement
                addrTmp.AddressNo = Data.Repository.GetAddressList().OrderBy(x => x.AddressNo).Last().AddressNo + 1;

                Data.Repository.GetAddressList().Add(addrTmp);

                obj = new { Success = true, 
                            Message = "Added successfully", 
                            Object = addrTmp, 
                            operationType = "INSERT", 
                                Html = this.RenderPartialView("_addressLine", addrTmp )
                          };
            }
            else
            {
                Address addr = Repository.GetAddressList().Where(c => c.AddressNo == addrTmp.AddressNo).FirstOrDefault();
                addr.AddressTypeNo = addrTmp.AddressTypeNo;
                addr.AddressText = addrTmp.AddressText;
                addr.CityNo = addrTmp.CityNo;
                addr.PersonNo = addrTmp.PersonNo;

                obj = new { Success = true, 
                            Message = "Updated successfully", 
                            Object = addr, 
                            operationType = "UPDATE", 
                                Html = this.RenderPartialView("_addressLine",  addr )
                          };
            }                

        }
        else
        {
            obj = new { Success = false, Message = "Please check form" };
        }

        return Json(obj, JsonRequestBehavior.DenyGet);
    }

    // .. 

}
요청된 html 스크립트를 가져오기 위해 RenderPartialView 메서드가 사용됩니다.
C#
//..

public static string RenderPartialView(this Controller controller, string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = controller.ControllerContext.RouteData.GetRequiredString("action");

    controller.ViewData.Model = model;
    using (var sw = new StringWriter())
    {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
        var viewContext = new ViewContext(controller.ControllerContext, 
               viewResult.View, controller.ViewData, controller.TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
    }
}

//..
saveAddress 폼의 ajax post의 saveSuccess 함수는 다음과 같습니다:
JavaScript
<script type="text/javascript">
 
    //...

    function saveSuccess(data) 
    {
        if (data.Success == true) 
        {            
            $("#paginginfo").show();       
 
            if (data.operationType == 'UPDATE') 
            {                           
                var row = linkObj.closest("tr");
                
                // the following line can also be used  to get related row
                //$('#AddressTable #row-' + data.Object.AddressNo); 

                row.replaceWith(data.Html);  
                //..
            }
            else 
            {  //INSERT

                try 
                {                                
                      $("#AddressTable tr:first").after(data.Html);
 
                     //..

                }
                catch (err) 
                {
                       alert(err.Message);
                }
            }
            
            //..

        }
        else 
        {
           //..
        }
    }
 
    //..
    
</script>
上記で説明した2つの技術のいずれかを使用できます。

15) Global.asaxでmapRouteをカスタマイズする方法は?

クラシックasp.netアプリケーションでは、urlRewrite操作はいくつかのサードパーティのアセンブリで簡単に実現されていました。MVCアプリケーションでは、Global.asaxを使用してmapRouteをカスタマイズすることが可能です。
以下のmapRouteはGlobal.asaxのデフォルトです:
C#
public class MvcApplication : System.Web.HttpApplication
{

    //..

    public static void RegisterRoutes(RouteCollection routes)
    {

       // all new customized maproute rules can be put here
        

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

    }

    //  .. 
}
다음 스크립트에 따르면, **/Save/{addressNo}/{personNo}**가 링크로 사용됩니다.
HTML
@Html.ActionLink("Edit", "Save", 
  new { addressNo = item.AddressNo, personNo = item.PersonNo }, new { @class = "editLink" })
위 링크의 스크린샷은 다음과 같습니다.
MapRoute
MapRoute
그래서, Global.asax에 다음과 같은 사용자 정의 mapRoute 규칙을 추가하는 것이 가능합니다.
C#
//..
 
routes.MapRoute(
    "AddressSave",
    "Address/Save/{addressNo}/{personNo}",
    new { controller = "Address", action = "Save", 
         addressNo = UrlParameter.Optional, personNo = UrlParameter.Optional }
);
 
//.. 
위에서 설명한 두 가지 기술 중 하나를 사용할 수 있습니다.

16) 테이블의 모든 행을 checkALL 및 uncheckALL하는 방법은?

많은 애플리케이션에서는, 테이블 내의 모든 체크를 한 번에 마크 또는 마크 해제하고 싶을 수 있습니다.
Check/Uncheck ALL
Check/Uncheck ALL
이러한 함수에는 다음 스크립트를 사용할 수 있습니다.
HTML
..

<br />
| <a href="#" class="checkALLRecords" id="checkALL">Check ALL</a> | <a href="#" class="unCheckALLRecords" id="unCheckALL">Uncheck ALL</a> |
<br />

..

<table id="NoteTable"></table>
..  
JavaScript
//..
 

        //check ALL records
        $("#checkALL").live("click", function (e) 
        {
                e.preventDefault();                                           
                CheckALL(true);
        });    
   
        //uncheck ALL records
        $("#unCheckALL").live("click", function (e) 
        {
                e.preventDefault();                                           
                CheckALL(false);
        });   


//..  

    function CheckALL(state)
    {
                            var rows = $("#NoteTable tr");
                                                       

                            for(var i=0; i< rows.length; i++)
                            {                               
                                var row = $(rows).eq(i);
                                                                                                                               
                                var span = row.find('span#cboxSpan');
                                var cb = row.find('span#cboxSpan').find('input.cboxDELclass');
                                
                                if (state==true)                                                                                                    
                                    cb.attr('checked',true);
                                else                                    
                                    cb.attr('checked',false);
                            }                           
    }



//..  

17) "데이터 로딩 중"을 만드는 방법은?

여러 데이터 행을 로드할 때, "데이터 로딩 중" 메시지를 사용자에게 표시해야 합니다.
데이터 로딩 중
데이터 로딩 중
다음 div는 필요한 메시지에 따라 사용자 정의할 수 있습니다.
HTML
..
<div id="loadMessage"></div>
..   
div 영역을 사용자 정의하기 위해 다음 javascript 함수를 사용할 수 있습니다.
JavaScript
..

function showLoader(root, txt) {
       
    $("#loadMessage").html("");
    $("#loadMessage").show();
    var loader = '<img src="' + root + '/ajax-loader.gif" align="absmiddle">&amp;nbsp;<span><br/>' + txt + '...</span>';
    $("#loadMessage").fadeIn(100).html(loader);
}

function hideLoader() {
    $("#loadMessage").hide();
}

..   

18) jQuery로 마스터 상세 그리드를 만드는 방법은?

마스터 행이 클릭되면, 상세 행은 다음에 보이는 것처럼 마스터 그리드 아래에 표시됩니다.
마스터 상세 그리드
마스터 상세 그리드
그리드로 다음 테이블이 사용됩니다.
HTML
..
<table id="CountryTable" class="hovertable2"></table>
<br />
<br />

<table id="CityTable" class="hovertable"></table>
..    
마스터 상세 접근 방식을 시뮬레이션하기 위해 다음 javascript 함수가 사용됩니다.
JavaScript
..

 function setTableRowClick()
   {        

        $("#CountryTable tr  td.clickable").unbind('click');
        
        $('#CountryTable  tr  td.clickable').click(function ()         
        {           
             var row = $(this).parent();             
             setRow(row);

        });

        //-------------        




   }//func 


   function setRow(row)
   {   
              var rowid = row.attr('id'); //current
                            
              var higlightedCountryTableRowid = $("#pageinfo .higlightedCountryTableRowid").text();               

               $("#pageinfo .higlightedCountryTableRowid").html(rowid.toString());

              if ((rowid==0) || (rowid!=higlightedCountryTableRowid))
              {
                  //------
                    row.siblings().removeClass('diffColor');                                              
                    row.addClass("diffColor");
                  //-------

                 fillCityData(rowid);
             }

   }


..   

    function fillCountryData() 
    {                         
            $.ajax({
                type: "POST",                
                url: "@Url.Action("GetCountryList", "Country")",
                data: {},
                cache: false,
                dataType: "json",
                success: function (data) 
                {                                  
                    if (data.Html) 
                    {                                        
                        $("#CountryTable").html(data.Html); 
                        
                        buttonizeALL();
                        
                        setLinkAbilitesCountry();  
                        setLinkAbilitesCity();

                                              
                        setTableRowClick();

                    }
                    else 
                    {
                        alert('opps-- country list error!'); 
                    }
                },                
                error: function(exp)        
                {
                         alert('Error address : ' + exp.responseText);
                }                
            }); //end ajax call
     

    }//func


    function fillCityData(parCountryNo) 
    {                         
            $.ajax({
                type: "POST",                
                url: "@Url.Action("GetCityList", "Country")",
                data: { countryNo: parCountryNo},                
                cache: false,
                dataType: "json",
                success: function (data) 
                {                                  
                    if (data.Html) 
                    {                                       
                        $("#CityTable").html(data.Html);        

                        
                        buttonizeALL();
                        setLinkAbilitesCity();                        
                        setTableRowClick();

                    }
                    else 
                    {
                        alert('opps-- city list error!'); 
                    }
                },                
                error: function(exp)        
                {
                         alert('Error address : ' + exp.responseText);
                }                
            }); //end ajax call
     

    }//func

.. 

결론

이 글이 도움이 되셨기를 바랍니다.

클라우드 컴퓨팅 서비스

AWS, Azure, Google Cloud 플랫폼에서의 인프라 설계, 마이그레이션, 관리, 최적화 서비스를 제공합니다.

서비스 보기

문의하기

AWS 및 클라우드 컴퓨팅 솔루션에 대한 자세한 정보를 얻으려면 팀에 문의하세요.

문의하기