Syntax of Foreach Statment Assistance

92 views Asked by At

I need assistance in understanding what needs to go where in my foreach statements. Not sure that I have it correct. Could someone please take a look and explain how to "phrase" this statement?

Here is the code from my Edit.cshtml page:

@page
@model RabiesShotTracker1.Pages.Cases.EditModel

<form method="post">
    <input hidden asp-for="Case.Id" />
    <div class="border p-3 mt-4">
        <div class="row pb-2">
            <h2 class="text-primary pl-3">Edit Case Information</h2>
            <hr />
        </div>
        <div asp-validation-summary="All"></div>
        <h3 class="text-primary pl-3">Case Demographic Information</h3>
 
        <table class="table table-borderless" style="width:100%">
            <tr>
                <td style="width: 25%">
                    <div class="mb-3">
                        <label asp-for="Case.CaseId"></label>
                        <input asp-for="Case.CaseId" class="form-control" />
                        <span asp-validation-for="Case.CaseId" class="text-danger"></span>
                    </div>
                </td>
                <td style="width: 25%">
                    <div class="mb-3">
                        <label asp-for="Case.SpecieId"></label>
                        <select asp-for="Case.SpecieId" id="Select1" class="form-select">
                            <option value="">---Select Species---</option>
                            @if (Model.DisplaySpeciesData != null)
                            {
                                @foreach (var item1 in Model.DisplaySpeciesData.OrderBy(x => x.SpeciesName))
                                {
                                   <option value="@item1.SpeciesName" selected="@(item1.SpecieId==Model.Case.SpecieId?true:false)">@item1.SpeciesName</option>
                                }
                            }
                        </select>
                    </div>
                </td>

The SpecieId is the value that should get stored in the Case table, but the dropdown itself should display the SpeciesName for the chosen SpecieId.

Here is my .cs behind:

using RabiesShotTracker.Data;
using RabiesShotTracker.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RabiesShotTracker.Pages.Cases;

[BindProperties]

public class EditModel : PageModel
{
    private readonly ApplicationDbContext _db;
    public Case? Case { get; set; }
    public EditModel(ApplicationDbContext db)
    {
        _db = db;
    }

    public IEnumerable<Specie> DisplaySpeciesData { get; set; }
    public IEnumerable<County> DisplayCountyData { get; set; }
    public IEnumerable<Town> DisplayTownData { get; set; }
    public IEnumerable<TestLab> DisplayTestLabData { get; set; }

    public void OnGet(int Id)
    {
        Case = _db.Case.Find(Id);
        DisplaySpeciesData = _db.Specie.ToList();
        DisplayCountyData = _db.County.ToList();
        DisplayTownData = _db.Town.ToList();
        DisplayTestLabData = _db.TestLab.ToList();
    }

    public async Task<IActionResult> OnPost()
    {
        if (ModelState.IsValid)
        {
            _db.Case.Update(Case);
            await _db.SaveChangesAsync();
            TempData["success"] = "Case updated successfully.";
            return RedirectToPage("Index");
        }
        return Page();
    }

}

Case Model in case you need that:

using System.ComponentModel.DataAnnotations;

namespace RabiesShotTracker.Model
{
    public class Case
    {
        [Key]
        public int Id { get; set; }
        [Display(Name = "Case No")]
        public int? CaseId { get; set; }
        [Display(Name = "Species Name")]
        public int? SpecieId { get; set; }
        public Specie? Specie { get; set; }
        [Display(Name ="County Name")]
        public int? CountyId { get; set; }
        public County? County { get; set; }
        [Display(Name = "Town Name")]
        public int? TownId { get; set; }
        public Town? Town { get; set; }
        public string? Location { get; set; }
        public string? Notes { get; set; }
        [Display(Name ="Animal Captured?")]
        public string? Captured { get; set; }
        [Display(Name = "Date Captured")]
        [DataType(DataType.Date)]
        public DateTime? CaptureDate { get; set; }
        [Display(Name ="Animal Tested?")]
        public string? Tested { get; set; }
        [Display(Name = "Lab Name")]
        public int? TestLabId { get; set; }
        public TestLab? TestLab { get; set; }
        [Display(Name = "Date Diagnosed")]
        [DataType(DataType.Date)]
        public DateTime? DiagnosisDate { get; set; }
        [Display(Name ="Animal Rabid?")]
        public string? Rabid { get; set; }
        [Display(Name ="Specimen No")]
        public string? SpecimenNo { get; set; }
        [Display(Name = "Added/Updated By")]
        public string? UpdatedBy { get; set; }
        [Display(Name = "Date Added/Updated")]
        [DataType(DataType.Date)]
        public DateTime? UpdateDate { get; set; }
    }
}

Here is a snip from my Create page which works just fine.

                <td style="width: 25%">
                    <div class="mb-3">
                        <label asp-for="Case.SpecieId"></label>
                        <select asp-for="Case.SpecieId" id="Select1" class="form-select" asp-items="@(new SelectList(Model.DisplaySpeciesData.OrderBy(x => x.SpeciesName),"SpecieId", "SpeciesName"))"><option value="" selected disabled>---Select Species---</option></select>
                </td>

Here is where I am getting the null error related to the Case Model as it gets past the CaseId just fine and only has issues when it hits the dropdown field.

Model Case is Null

Just not sure why I am receiving a Null error if the syntax is correct. When I look at the database table, there are values in those fields from the records created by using the Create page. Thank you. Please ask questions if I am not describing the function clearly enough.

1

There are 1 answers

30
Lajos Arpad On

My understanding of the question is that you need the chunk below to be explained in plain words:

         @foreach (var item1 in Model.DisplaySpeciesData.OrderBy(x => x.SpeciesName))
         {
             <option value="@item1.SpeciesName" selected="@(item1.SpecieId==Model.Case.SpecieId?true:false)">@item1.SpeciesName</option>
         }
  • DisplaySpeciesData is an IEnumerable<Specie>, that is, it's an enumerable whose elements are each a Specie
  • I did not paste the if that's wrapped around the loop here, but we only reach this loop if Model.DisplaySpeciesData is not null, that is, if it was properly initialized
  • we order Model.DisplaySpeciesData by SpeciesName in alphabetical order
  • we loop the result, via, impersonating an element of the collection as item1, so, the item whose SpeciesName is the first in alphabetical order will be item1 for the first time, then the second item will be item1 until all of the items were impersonated by item1
  • the inner block of the loop, that is, the code between { and } is the thing we aim to do for each item1 from the collection
  • So, for each item, in alphabetically ascending order by SpeciesName will yield an option tag, whose value is the SpeciesName of the current item and selected will have the truth value of whether SpecieId of the current item matches the value of Model.Case.SpecieId, so, if they match, then selected will be true, otherwise it will be false, while we show the species name in the option, so the matching item will be shown as selected in the select tag

EDIT

While I still do not fully understand the problem, it's possible that we just want the evaluation to be false if Case is null. In that case something like this could be the solution for the selected attribute:

selected="@((Model.Case != null) && ((item1.SpecieId==Model.Case.SpecieId))?true:false)"