2015-01-20 26 views
17

Tôi đang bắt đầu dự án ASP.NET MVC đầu tiên của mình, vì vậy tôi có một câu hỏi đơn giản. Tôi đã mã sau:ASP.NET MVC 5 nhóm các nút radio

foreach(var question in Model.GeneralQuestions) 
{ 
    <div class = "well"> 
     <h3> 
      <strong>@question.QuestionString</strong> 
     </h3> 
     @foreach (var answer in question.PossibleAnswers) 
     { 
      @Html.RadioButtonFor(model => question.QuestionString, answer.Answer) 
      @Html.Label(answer.Answer) 
      <br /> 
     } 
    </div> 
} 

Tất cả các câu hỏi trong Model.GeneralQuestions là duy nhất, vì vậy nút radio nên được chia thành các nhóm theo tên thuộc tính (cho mỗi câu hỏi một nhóm các nút radio). Nhưng mã này chỉ tạo ra một nhóm, vì vậy khi tôi trả lời câu hỏi thứ hai, câu hỏi đầu tiên sẽ bị bỏ chọn. Tôi cần thay đổi điều gì?

EDIT
Mô hình của tôi trông giống như:

public class StudentViewModel 
{ 
    public Student Student { get; set; } 
    public List<Question> GeneralQuestions { get; set; } 
    public List<SubjectQuestions> SubjectQuestions { get; set; } 
} 
public class Student 
{ 
    public int StudentID { get; set; } 
    public string Index { get; set; } 
    public string Name { get; set; } 
    public string Surname { get; set; } 

    public virtual ICollection<Subject> Subjects { get; set; } 
} 
public class Question 
{ 
    public int QuestionID { get; set; } 
    public string QuestionString { get; set; } 
    public bool IsAssociatedWithSubject { get; set; } 

    public virtual ICollection<PossibleAnswer> PossibleAnswers { get; set; } 
    public virtual ICollection<Results> Results { get; set; } 
} 
public class SubjectQuestions 
{ 
    public Subject Subject { get; set; } 
    public List<Question> Questions { get; set; } 
} 
public class Results 
{ 
    public int ResultsID { get; set; } 
    public int QuestionID { get; set; } 
    public int? SubjectID { get; set; } 
    public int PossibleAnswerID { get; set; } 

    public virtual Question Question { get; set; } 
    public virtual PossibleAnswer PossibleAnswer { get; set; } 
    public virtual Subject Subject { get; set; } 
} 

Trong một trường hợp của StudentViewModel tôi tiết kiệm một sinh viên và tất cả những câu hỏi mà anh nên trả lời (cả nói chung và liên quan đến đối tượng ông đang nghiên cứu) và vượt qua nó để xem. Theo quan điểm, tôi đặt tất cả các câu hỏi dưới dạng đơn và tất cả đều là loại radio. Vì vậy, bất cứ ai có thể giúp tôi với nhóm các nút radio và gửi lại mẫu đơn này một cách chính xác?

+1

Chỉ là câu trả lời nhanh nhưng bạn có thấy bài viết này không? http://stackoverflow.com/a/22178728/1765853 – macoms01

+0

Miễn là 'QuestionString' là duy nhất, điều này sẽ tạo ra một nhóm cho mỗi câu hỏi mặc dù ràng buộc với' QuestionString' có vẻ như là lạ - bạn không nên ràng buộc với một thứ gì đó như 'SelectedAnswer'? Bạn có thể hiển thị một số html này được tạo ra –

+0

Vòng lặp ngoài của bạn cũng phải là một vòng lặp 'for' để các điều khiển của bạn là thuộc tính có tên với các bộ chỉ mục có thể ràng buộc điều này trên bài đăng trở lại. –

Trả lời

23

Có một số vấn đề với mã của bạn, bao gồm tạo các thuộc tính trùng lặp id (không hợp lệ), tạo các thuộc tính trùng lặp name (đó là lý do bạn chỉ tạo một nhóm, nhưng quan trọng hơn điều này sẽ ngăn bạn liên kết với mô hình khi bạn đăng lại) và bạn không thực sự ràng buộc với thuộc tính hợp lệ.

Bạn sẽ cần tạo mô hình xem để thể hiện những gì bạn muốn hiển thị và chỉnh sửa và tạo nút radio trong vòng lặp for (hoặc sử dụng EditorTemplate) để chúng được đặt tên chính xác với người lập chỉ mục.

Xem mô hình

public class QuestionVM 
{ 
    public int ID { get; set; } // for binding 
    public string Text { get; set; } 
    [Required] 
    public int? SelectedAnswer { get; set; } // for binding 
    public IEnumerable<AnswerVM> PossibleAnswers { get; set; } 
} 

public class SubjectVM 
{ 
    public int? ID { get; set; } 
    [DisplayFormat(NullDisplayText = "General")] 
    public string Name { get; set; } 
    public List<QuestionVM> Questions { get; set; } 
} 

public class AnswerVM 
{ 
    public int ID { get; set; } 
    public string Text { get; set; } 
} 

public class StudentVM 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    // plus any other properties of student that you want to display in the view 
    public List<SubjectVM> Subjects { get; set; } 
} 

Xem

@model YourAssembly.StudentVM 
@using(Html.BeginForm()) 
{ 
    @Html.HiddenFor(m => m.ID) 
    @Html.DisplayFor(m => m.Name) 
    for(int i = 0; i < Model.Subjects.Count; i++) 
    { 
    @Html.HiddenFor(m => m.Subjects[i].ID) 
    @Html.DisplayFor(m => m.Subjects[i].Name) // will display "General" if no name 
    for (int j = 0; j < Model.Subjects[i].Questions.Count; j++) 
    { 
     @Html.HiddenFor(m => m.Subjects[i].Questions[j].ID) 
     @Html.DisplayFor(m => m.Subjects[i].Questions[j].Text) 
     foreach(var answer in Model.Subjects[i].Questions[j].PossibleAnswers) 
     { 
     <div> 
      @Html.RadioButtonFor(m => m.Subjects[i].Questions[j].SelectedAnswer, answer.ID, new { id = answer.ID}) 
      <label for="@answer.ID">@answer.Text</label> 
     </div> 
     } 
     @Html.ValidationMessageFor(m => m.Subjects[i].Questions[j].SelectedAnswer) 
    } 
    } 
    <input type="submit" value="save" /> 
} 

khiển

public ActionResult Edit(int ID) 
{ 
    StudentVM model = new StudentVM(); 
    // populate your view model with values from the database 
    return View(model); 
} 

[HttpPost] 
public ActionResult Edit(StudentVM model) 
{ 
    // save and redirect 
} 

Note Tôi là một chút nhầm lẫn bởi các cấu trúc cơ sở dữ liệu bao hàm bởi mô hình của bạn (ví dụ tại sao bạn cần các kiểu riêng biệt cho QuestionSubjectQuestion khi một null giá trị cho SubjectID xác định đó là câu hỏi "Chung"). Tôi khuyên bạn nên bắt đầu bằng cách chỉ cần mã hóa một số giá trị trong phương thức GET để xem cách hoạt động và đăng lại.

StudentVM model = new StudentVM(); 
model.ID = 1; 
model.Name = "bambiinela"; 
model.Subjects = new List<SubjectVM>() 
{ 
    new SubjectVM() 
    { 
    Questions = new List<QuestionVM>() 
    { 
     new QuestionVM() 
     { 
     ID = 1, 
     Text = "Question 1", 
     SelectedAnswer = ?, // set this if you want to preselect an option 
     PossibleAnswers = new List<AnswerVM>() 
     { 
      new AnswerVM() 
      { 
      ID = 1, 
      Text = "Answer A" 
      }, 
      new AnswerVM() 
      { 
      ID = 1, 
      Text = "Answer B" 
      } 
     } 
     }, 
     new QuestionVM() 
     { 
     ID = 2, 
     Text = "Question 2", 
     PossibleAnswers = new List<AnswerVM>() 
     { 
      // similar to above 
     } 
     } 
    } 
    }, 
    new SubjectVM() 
    { 
    ID = 1, 
    Name = "Math", 
    Questions = new List<QuestionVM>() 
    { 
     // similar to above 
    } 
    } 
}; 

Khi bạn đăng, mô hình được điền ID của câu trả lời đã chọn cho mỗi câu hỏi trong từng chủ đề. Lưu ý việc sử dụng DisplayFor() đối với một số thuộc tính. Các thông báo này sẽ không đăng lại, do đó bạn cần phải điền lại các thuộc tính này nếu bạn trả lại chế độ xem (ví dụ: ModelState không hợp lệ). Hoặc bạn có thể tạo một hộp văn bản chỉ đọc hoặc thêm đầu vào bị ẩn cho các thuộc tính đó. Tôi cũng đề nghị bạn kiểm tra mã HTML được tạo ra, đặc biệt là tên các thuộc tính đó sẽ giống như thế

<input type="radio" name="Subjects[0].Questions[0].SelectedAnswer" ... 

để cung cấp cho bạn một sự hiểu biết về cách thức bộ sưu tập đang bị ràng buộc để mô hình của bạn về bài đăng lại

+0

Cảm ơn bạn! Tất cả các lời khuyên đều hữu ích và mã là chính xác. Bây giờ tôi đã tách mô hình cho MVC và entites để tiết kiệm trong cơ sở dữ liệu kể từ khi tôi entites trong cơ sở dữ liệu nên nhìn một chút khác nhau từ mô hình MVC. – bambi

+0

có cách nào để đăng lại văn bản câu hỏi, tên chủ đề, v.v. trong đối tượng StudentVM không? Tất cả những gì tôi nhận được là ID của các câu hỏi được trả lời trong phương thức bài ('[HttpPost] Sinh viên hành động phản hồi công cộng (mô hình StudentVM) {}'), các trường khác dường như trống. – bambi

+0

Như tôi đã lưu ý, bạn có thể tạo đầu vào bị ẩn cho các thuộc tính đó bổ sung vào '@ Html.DisplayFor()' - ví dụ: '@ Html.HiddenFor (m => m.Name)' hoặc bạn có thể thay thế 'DisplayFor' bằng' @ Html.TextBoxFor (m => m.Name, new {@readonly = "readonly", @ class = "readonly ")' và sau đó sử dụng css để tạo kiểu cho nó.Tuy nhiên việc tạo ra rất nhiều đầu vào không cần thiết ẩn có thể làm suy giảm hiệu suất (gửi nó đến máy khách và sau đó quay lại) và mở ra cho bạn các cuộc tấn công overposting. Thường thì tốt hơn là chỉ lấy lại dữ liệu từ cơ sở dữ liệu nhưng chỉ bạn mới có thể đánh giá tùy chọn tốt nhất là gì. –

2

Bí quyết là sử dụng một biểu thức (tham số đầu tiên để Html.RadioButtonFor) có chứa một giá trị thay đổi theo nhóm các nút radio.Trong trường hợp của bạn, nó sẽ là một chỉ số trong danh sách các câu hỏi.

Dưới đây là một số mẫu mã:

@for (int i = 0; i < Model.GeneralQuestions.Count; i++) 
{ 
    var question = Model.GeneralQuestions[i]; 
    @Html.Label(question.QuestionString) 
    <br /> 
    foreach (var answer in question.PossibleAnswers) 
    { 
     @Html.RadioButtonFor(model => 
      Model.GeneralQuestions[i].SelectedAnswerId, answer.Id) 
     @Html.Label(answer.Answer) 
     <br /> 
    } 
} 

này tạo ra mã HTML sau đây:

<label for="Q1">Q1</label> 
<br /> 
<input id="GeneralQuestions_0__SelectedAnswerId" 
    name="GeneralQuestions[0].SelectedAnswerId" type="radio" value="1" /> 
<label for="A01">A01</label> 
<br /> 
<input id="GeneralQuestions_0__SelectedAnswerId" 
    name="GeneralQuestions[0].SelectedAnswerId" type="radio" value="2" /> 
<label for="A02">A02</label> 
<br /> 
<label for="Q2">Q2</label> 
<br /> 
<input id="GeneralQuestions_1__SelectedAnswerId" 
    name="GeneralQuestions[1].SelectedAnswerId" type="radio" value="11" /> 
<label for="A11">A11</label> 
<br /> 
<input id="GeneralQuestions_1__SelectedAnswerId" 
    name="GeneralQuestions[1].SelectedAnswerId" type="radio" value="12" /> 
<label for="A12">A12</label> 
<br /> 

Và vì lợi ích của sự hoàn chỉnh, đây là một phiên bản thu gọn của các mô hình sử dụng:

public class StudentViewModel 
{ 
    public List<Question> GeneralQuestions { get; set; } 
} 

public class Question 
{ 
    public int QuestionId { get; set; } 
    public string QuestionString { get; set; } 
    public ICollection<PossibleAnswer> PossibleAnswers { get; set; } 
    public int SelectedAnswerId { get; set; } 
} 

public class PossibleAnswer 
{ 
    public int Id { get; set; } 
    public string Answer { get; set; } 
} 

và đây là mã từ phương thức hành động:

return View(new StudentViewModel 
{ 
    GeneralQuestions = 
     new List<Question> 
     { 
      new Question 
      { 
       QuestionString = "Q1", 
       PossibleAnswers = 
        new[] 
        { 
         new PossibleAnswer {Id = 1, Answer = "A01"}, 
         new PossibleAnswer {Id = 2, Answer = "A02"} 
        } 
      }, 
      new Question 
      { 
       QuestionString = "Q2", 
       PossibleAnswers = 
        new[] 
        { 
         new PossibleAnswer {Id = 11, Answer = "A11"}, 
         new PossibleAnswer {Id = 12, Answer = "A12"} 
        } 
      }, 
     } 
});