4

I want to apply for each loop on two models at the same time.

My Controller Action Is:

public ActionResult MarkAttendance(int id)
{
    var students = _context.Students.Where(c => c.ClassId == id).ToList();
    var status = _context.Statuses.ToList();

    var viewModel = new AttendanceViewModel
    {
        Student = students,
        Status = status
    };

    return View(viewModel);
}

My Student Model is

 public class Student
{
    public int Id { get; set; }

    [Required]
    [StringLength(30)]
    [RegularExpression(@"^[A-Za-z\s]{1,}[\.]{0,1}[A-Za-z\s]{0,}$", ErrorMessage = "Invalid name. Use letters only")]
    public string Name { get; set; }

    [Required]
    [StringLength(30)]
    [RegularExpression(@"^[A-Za-z\s]{1,}[\.]{0,1}[A-Za-z\s]{0,}$", ErrorMessage = "Invalid name. Use letters only")]
    [Display(Name = "Father Name")]
    public String FatherName { get; set; }

    [Required]
    [Range(0, 10000)]
    public int Fee { get; set; }

    [Required]
    [RegularExpression(@"^((\+92)|(0092))-{0,1}\d{3}-{0,1}\d{7}$|^\d{11}$|^\d{4}-\d{7}$", ErrorMessage = "Please enter only mobile number, Landline not acceptable")]
    [Display(Name = "Student Contact No.")]
    public string StudentContact { get; set; }

    [Required]
    [RegularExpression(@"^[0-9]+$", ErrorMessage = "Please enter correct phone number")]
    [Display(Name = "Guardian Contact No.")]
    public string GuardianContact { get; set; }

    [Required]
    [RegularExpression(@"^[0-9]+$", ErrorMessage = "Enter only numbers")]
    [Display(Name = "Roll Number")]
    [IfRollNoExists]
    public int RollNo { get; set; }

    [Required]
    [Display(Name = "Record Date")]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
    public DateTime DateTime { get; set; }

    [Display(Name = "Student Picture")]
    public String ImageURL { get; set; }

    public Class Class { get; set; }

    [Required]
    [Display(Name = "Class Title")]
    public int ClassId { get; set; }

    [ForeignKey("Account")]
    public int AccountId { get; set; }

    public virtual Account Account { get; set; }


}

My Status Class is

  public class Status
{
    public int Id { get; set; }

    public string StudentStatus { get; set; }
}

My ViewModel Is:

public class AttendanceViewModel
{
    public IEnumerable<Student> Student { get; set; }
    public IEnumerable<Status> Status { get; set; }
}

My Razor View is:

@model  Pioneer.ViewModel.AttendanceViewModel
@foreach (var student in Model.Student)
{
    <tr>
        <td>@student.Name</td>
        <td>@student.RollNo</td>
        <td>
            <div data-toggle="buttons">
                <label class="btn btn-success active">
                    @Html.RadioButtonFor(m => m.Status.StudentStatus, "Present", new { id = "1" })
                </label>
                <label class="btn btn-danger">
                    @Html.RadioButtonFor(m => m.Status.StudentStatus, "Absent", new { id = "2" })
                </label>
                <label class="btn btn-primary">
                    @Html.RadioButtonFor(m => m.Status.StudentStatus, "On Leave", new { id = "3" })
                </label>
                <label class="btn btn-warning">
                    @Html.RadioButtonFor(m => m.Status.StudentStatus, "Short Leave", new { id = "4" })
                </label>
            </div>
        </td>                                           
    </tr>
}

Now when I am getting error for using

@Html.RadioButtonFor(m => m.Status.StudentStatus, "Present", new { id = "1" })

Below I attached an image of error. Error Screen Shot

And please tell me can I iterate over my rows without using for-each if I use HTML helper here?

Alamzaib Farooq
  • 190
  • 2
  • 18

2 Answers2

2

What you are trying to achieve is not possible. As per your view code, the Status model should be part of Student model class class.

So your view Model will look like this :

public class AttendanceViewModel
{
    public IEnumerable<Student> Student { get; set; }
}

And Student model class will include status :

public class Student
{
    public IEnumerable<Status> Status { get; set; }
}

Now you can access status in your view like this :

@model  Pioneer.ViewModel.AttendanceViewModel       
@foreach (var student in Model.Student)
{
    <tr>
        <td>@student.Name</td>
        <td>@student.RollNo</td>

        @foreach(var status in student)
        {
            <td>
                <div data-toggle="buttons">
                    <label class="btn btn-success active">
                        @Html.RadioButtonFor(status.StudentStatus, "Present", new { id = "1" })
                    </label>
                    <label class="btn btn-danger">
                        @Html.RadioButtonFor(statusStudentStatus, "Absent", new { id = "2" })
                    </label>
                    <label class="btn btn-primary">
                        @Html.RadioButtonFor(status.StudentStatus, "On Leave", new { id = "3" })
                    </label>
                    <label class="btn btn-warning">
                        @Html.RadioButtonFor(status.StudentStatus, "Short Leave", new { id = "4" })
                    </label>
                </div>
            </td>  
        }
    </tr>
}

EDIT :

Or if you're particular about using the same ViewModel as mentioned in the question, you can replace foreach with for. Check below sample code :

@model  Pioneer.ViewModel.AttendanceViewModel
@for(var studentIndex = 0; studentIndex < Model.Student.Count(); studentIndex++)
{
    <tr>
        <td>@Model.Student[studentIndex].Name</td>
        <td>@Model.Student[studentIndex].RollNo</td>

        @for(var statusIndex = 0; statusIndex < Model.Status.Count; statusIndex++)
        {
            <td>
                <div data-toggle="buttons">
                    <label class="btn btn-success active">
                        @Html.RadioButtonFor(m => m.Status[statusIndex].StudentStatus, "Present", new { id = "1" })
                    </label>
                    <label class="btn btn-danger">
                        @Html.RadioButtonFor(m => m.Status[statusIndex].StudentStatus, "Absent", new { id = "2" })
                    </label>
                    <label class="btn btn-primary">
                        @Html.RadioButtonFor(m => m.Status[statusIndex].StudentStatus, "On Leave", new { id = "3" })
                    </label>
                    <label class="btn btn-warning">
                        @Html.RadioButtonFor(m => m.Status[statusIndex].StudentStatus, "Short Leave", new { id = "4" })
                    </label>
                </div>
            </td>     
        }       
    </tr>
}
ViVi
  • 4,339
  • 8
  • 29
  • 52
  • I have tested both the solutons and it seems to work fine at my end. Did you try both the solutions mentioned in the answer? What error are you getting now? @AlamzaibFarooq – ViVi May 26 '17 at 06:25
  • In the nested loop, it's giving the error that `student` is not enumerable. **For each loop cannot iterate Pioneer.Models.Student** – Alamzaib Farooq May 26 '17 at 06:35
  • **My Controller** `public ActionResult MarkAttendance(int id) { var students = _context.Students.Where(c => c.ClassId == id).ToList(); var status = _context.Statuses.ToList(); var viewModel = new AttendanceViewModel { Student = students }; return View(viewModel); }` – Alamzaib Farooq May 26 '17 at 06:37
  • I resolved the issue in the nested loop. Now I am not able to access `status` properties. When I write in radio button `status.StudentStatus` its not recognizing `StudentStatus` – Alamzaib Farooq May 26 '17 at 06:39
  • Can you check with the `@for` method I mentioned rather than the `@foreach` method? @AlamzaibFarooq – ViVi May 26 '17 at 06:41
  • In second method its giving an error that **statusIndex does not exist in the current context.** – Alamzaib Farooq May 26 '17 at 06:44
  • You are using statusIndex before declaring it. I used `studentIndex` instead of `statusIndex` its giving error that **Cannot apply indexing on enumerable** – Alamzaib Farooq May 26 '17 at 06:47
  • both variables have separate uses. I think you dont get the point. studentIndex for accessing the first for loop and status index is for accessing the second for loop. – ViVi May 26 '17 at 06:50
  • Yes, I am understanding. How can you use `statusIndex` even before declaring it? I know they both have the purpose. I am getting the error that's why I am saying. – Alamzaib Farooq May 26 '17 at 06:55
  • @AlamzaibFarooq : Oops.. sorry..that was a mistake. I corrected – ViVi May 26 '17 at 06:57
  • I got the issue. I was using the same name `public IEnumerable Student { get; set; }` – Alamzaib Farooq May 26 '17 at 07:03
  • Your first method is correct! I should have used `Students` instead of `Student` – Alamzaib Farooq May 26 '17 at 07:04
1

m.Status its IEnumerable<Status>, it's have not StudentStatus property.

@Html.RadioButtonFor(m => m.Status.StudentStatus, "Absent", new { id = "2" })