2013-01-02 2 views
1

여러 페이지가있는 my asp.net mvc 2 응용 프로그램에 등록 마법사가 있습니다. 첫 페이지에는이 프로세스에 관련된 사람들의 기본적인 데이터 형식이 있어야합니다. 이름, 성 및 주소로 표시된 3 개의 텍스트 상자와 "다른 사람 추가"텍스트가있는 1 개의 확인란이 있어야합니다. 사용자가 라디오 버튼을 클릭하면 새로운 라디오 버튼과 함께 새로운 텍스트 상자가 나타나기 때문에 동일한 형태로 여러 사람을 추가 할 수 있습니다. 이론적으로 가능한 한 많은 인원을 삽입 할 수 있어야합니다. 모든 필드는 필수 항목이므로 페이지 상단의 유효성 검사 요약에서 "두 번째 사람의 이름을 입력하십시오"또는 이와 비슷한 이름을 지정해야합니다. 나는 DTO 클래스가 있습니다동적 페이지에서 ASP.NET MVC 2 유효성 검사

public class Person 
{ 
    public string FullName { get; set; } 
    public string LastName { get; set; } 
    public string Address{ get; set; } 
} 

을 나는이 페이지에 대한 내 모델 List<Person>해야한다고 생각 나는 자바 스크립트/jQuery로 새로운 사람을위한 HTML을 추가 할 것입니다. 이 동적 페이지를 어떻게 검증해야합니까? 저장 및 뒤로 버튼을 사용하여이 마법사를 진행할 수 있으며 페이지의 라디오 버튼을 클릭 취소 할 수 있어야하며 해당 특정 사용자는 사라져야하며 유효성 검사자가 더 이상 catch하지 않아야합니다. 내 전체 마법사가 서버 측 유효성 검사 (DataAnnotations)를 사용하고 있으며 클라이언트 유효성 검사를 사용하고 싶지 않습니다. 미리 감사드립니다.

UPDATE :

좀 더 도움이 필요합니다. 나는 새로운 속성 Person 클래스를 확장 할 :

public int Percent { get; set; } 

및 (100) 나는이 방법에 대한 사용자 정의 속성을 만들 수에 IEnumerable<Person>에서 사람의 각각의 모든 백분율의 합이 같다면 I 제출에 따라 서버 유효성 검사를 원하는 ? 제 모델은 제네릭 목록입니다. [CustomAttribute]을 적용 할 수 없습니다. 맞습니까?
또한 각 입력 바로 다음에 페이지 상단에 검증 요약이 있어야합니다. 나는 넣었다 : <%:Html.ValidationSummary(false, "Please correct the following and resubmit the page:")%> 사람마다 다른 검증 메시지를 설정하는 방법이 있습니까? 감사합니다

답변

3

이 작업의 구현에 들어가기 전에 스티븐 샌더슨으로부터 Editing a variable length list, ASP.NET MVC 2-style을 읽는 것이 좋습니다.

준비 됐습니까?

이제는 구현할 수 있습니다.

우선, 작업에 대한 뷰 모델을 정의해야합니다. 당신은 이미 했어, 그냥에 해당하는 유효성 검사 규칙을 정의

public class Person 
{ 
    [Required] 
    public string FullName { get; set; } 

    [Required] 
    public string LastName { get; set; } 

    [Required] 
    public string Address{ get; set; } 
} 

나는이 페이지에 대한 나의 모델은 절대적으로, 목록

찬성해야한다고 가정하자.

그럼 가서 만들 수 있도록 우리의 PersonsController :

public class PersonsController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new[] 
     { 
      new Person() 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(IEnumerable<Person> persons) 
    { 
     if (!ModelState.IsValid) 
     { 
      return View(persons); 
     } 

     // To do: do whatever you want with the data 
     // In this example I am simply dumping it to the output 
     // but normally here you would update your database or whatever 
     // and redirect to the next step of the wizard 
     return Content(string.Join(Environment.NewLine, persons.Select(p => string.Format("name: {0} address: {1}", p.FullName, p.Address)))); 
    } 

    public ActionResult BlankEditorRow() 
    { 
     return PartialView("_PersonEditorRow", new Person()); 
    } 
} 

그리고 지금의 뷰 (~/Views/Persons/Index.cshtml) 정의 할 수 있습니다 :

@model IEnumerable<Person> 

@using (Html.BeginForm()) 
{ 
    <div id="editorRows"> 
     @foreach (var item in Model) 
     { 
      Html.RenderPartial("_PersonEditorRow", item); 
     } 
    </div>  

    @Html.ActionLink(
     "Add another person", 
     "BlankEditorRow", 
     null, 
     new { id = "addItem" } 
    ) 

    <p> 
     <button type="submit">Next step</button> 
    </p> 
} 

<script type="text/javascript"> 
    $('#addItem').click(function() { 
     $.ajax({ 
      url: this.href, 
      cache: false, 
      success: function (html) { $('#editorRows').append(html); } 
     }); 
     return false; 
    }); 

    $(document).delegate('a.deleteRow', 'click', function() { 
     $(this).parents('div.editorRow:first').remove(); 
     return false; 
    }); 
</script> 

와 해당 부분보기 (~/Views/Persons/_PersonEditorRow.cshtml) :

@model Person 

<div class="editorRow"> 
    @using(Html.BeginCollectionItem("persons")) 
    { 
     <div> 
      @Html.LabelFor(x => x.FullName) 
      @Html.EditorFor(x => x.FullName) 
      @Html.ValidationMessageFor(x => x.FullName) 
     </div> 
     <div> 
      @Html.LabelFor(x => x.LastName) 
      @Html.EditorFor(x => x.LastName) 
      @Html.ValidationMessageFor(x => x.LastName) 
     </div> 
     <div> 
      @Html.LabelFor(x => x.Address) 
      @Html.EditorFor(x => x.Address) 
      @Html.ValidationMessageFor(x => x.Address) 
     </div> 

     <a href="#" class="deleteRow">delete</a> 
    } 
</div> 

비고 : Html.BeginCollectionItem 여기에 사용 된 도우미는 Steven Sanderson의 블로그 게시물에서 가져온 것입니다. 이전에 내 답변에 링크되어 있으며 이미 읽고 익숙한 것입니다. 여기에 완전성의 소스 코드는 다음과 같습니다

public static class HtmlPrefixScopeExtensions 
{ 
    private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_"; 

    public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName) 
    { 
     var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName); 
     string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString(); 

     // autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync. 
     html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex))); 

     return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex)); 
    } 

    public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix) 
    { 
     return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix); 
    } 

    private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName) 
    { 
     // We need to use the same sequence of IDs following a server-side validation failure, 
     // otherwise the framework won't render the validation error messages next to each item. 
     string key = idsToReuseKey + collectionName; 
     var queue = (Queue<string>)httpContext.Items[key]; 
     if (queue == null) 
     { 
      httpContext.Items[key] = queue = new Queue<string>(); 
      var previouslyUsedIds = httpContext.Request[collectionName + ".index"]; 
      if (!string.IsNullOrEmpty(previouslyUsedIds)) 
       foreach (string previouslyUsedId in previouslyUsedIds.Split(',')) 
        queue.Enqueue(previouslyUsedId); 
     } 
     return queue; 
    } 

    private class HtmlFieldPrefixScope : IDisposable 
    { 
     private readonly TemplateInfo templateInfo; 
     private readonly string previousHtmlFieldPrefix; 

     public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix) 
     { 
      this.templateInfo = templateInfo; 

      previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix; 
      templateInfo.HtmlFieldPrefix = htmlFieldPrefix; 
     } 

     public void Dispose() 
     { 
      templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix; 
     } 
    } 
} 

UPDATE :

내 나쁜, 나는 당신의 질문 asp.net-mvc-2 태그입니다 것으로 나타났습니다. 면도기의 견해가 당신의 사건에는 적용되지 않는다고 생각합니다. 여전히 다른 모든 것들은 똑같이 작동해야합니다. 여기

~/Views/Persons/Index.aspx입니다 : 그들은 웹폼을 사용하도록 당신의 의견을 업데이트하기 만하면 엔진이 볼 부분

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<IEnumerable<Person>>" %> 
<% using (Html.BeginForm()) { %> 
    <div id="editorRows"> 
     <% foreach (var item in Model) { %> 
      <% Html.RenderPartial("_PersonEditorRow", item); %> 
     <% } %> 
    </div>  

    <%= Html.ActionLink(
     "Add another person", 
     "BlankEditorRow", 
     null, 
     new { id = "addItem" } 
    ) %> 

    <p> 
     <button type="submit">Next step</button> 
    </p> 
<% } %> 

<script type="text/javascript"> 
    $('#addItem').click(function() { 
     $.ajax({ 
      url: this.href, 
      cache: false, 
      success: function (html) { $('#editorRows').append(html); } 
     }); 
     return false; 
    }); 

    $(document).delegate('a.deleteRow', 'click', function() { 
     $(this).parents('div.editorRow:first').remove(); 
     return false; 
    }); 
</script> 

마지막으로 (~/Views/Persons/_PersonEditorRow.ascx) :

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Person>" %> 
<div class="editorRow"> 
    <% using(Html.BeginCollectionItem("persons")) { %> 
     <div> 
      <%= Html.LabelFor(x => x.FullName) %> 
      <%= Html.EditorFor(x => x.FullName) %> 
      <%= Html.ValidationMessageFor(x => x.FullName) %> 
     </div> 
     <div> 
      <%= Html.LabelFor(x => x.LastName) %> 
      <%= Html.EditorFor(x => x.LastName) %> 
      <%= Html.ValidationMessageFor(x => x.LastName) %> 
     </div> 
     <div> 
      <%= Html.LabelFor(x => x.Address) %> 
      <%= Html.EditorFor(x => x.Address) %> 
      <%= Html.ValidationMessageFor(x => x.Address) %> 
     </div> 

     <a href="#" class="deleteRow">delete</a> 
    <% } %> 
</div> 
+0

감사 대린, 이 잘 작동합니다. 좀 더 도움이 필요합니다. 새로운 속성으로 Person 클래스를 확장하고 싶습니다. 'public int Percent {get; 세트; }' IEnumerable 에있는 각 퍼센 트의 합계가 100 인 경우 제출시 서버 유효성 검사를 원합니다.이 사용자 정의 특성을 어떻게 만들 수 있습니까? 제 모델은 제네릭 목록입니다. 제발 [CustomAttribute]를 적용 할 수 없습니다. 맞습니까? – Cemsha

+0

또한 입력의 직후가 아닌 페이지 상단에 검증 요약이 있어야합니다. 나는 넣었다 : '<% : Html.ValidationSummary (false, "다음을 수정하고 페이지를 다시 제출하십시오.") %>' Person마다 각각 다른 검증 메시지를 설정할 방법이 있습니까? 감사. – Cemsha

관련 문제