Search code examples
htmljqueryasp.netforeachrazor-pages

binding values to elements in foreach loops


I have

  • a foreach loop populating a list of categories and
  • inside, another foreach loop populating items.

Using jQuery,

  • when the addItemButton is clicked this whole foreach loop is hidden and an item create form is shown in the same space.

The input element shown in the code snippet passes an id to the form.

The problem is that it only ever passes the first categories id no matter which category's button is clicked.

My current thought is to use jQuery and make an object array to capture an unique id for both the button and input element then bind their Ids together as an object, then use logic if button1 is pushed input value equals categoryid1. I am not sure if this would work or if there is a better way to do it.

Any ideas on how to do this?

What I would like to accomplish

  • Each button in the category opens the form and passes that categories Id to that form.
  • There is only one create item form for all categories.

foreach loop

@foreach (var category in categoryList)
{
  <li>
     <a class="sidebar-sub-toggle">
        <i class="ti-home"></i>@category.Name
        <span class="badge badge-primary">2</span>
        <span class="sidebar-collapse-icon ti-angle-down"></span>
     </a>
     <ul>
       <li>
        <button class="addItemButton" type="button">Add Item</button>
       </li>
       <input class="categoryId" value="@category.Id" 
              name="CategoryId" form="itemCreateForm" />

       @foreach (var item in itemList)
       {
          @if (item.CategoryId == category.Id)
          {
             <li><a href="index.html">@item.Name</a></li>
          }
       }
       </ul>
  </li>
}

form

<form id="itemCreateForm" asp-controller="Items" asp-action="Create">
  <div id="itemCreateFormContent" class="form-group">
    <label class="col-form-label">Item Name</label>
    <input name="Name" type="text" class="form-control">
    <br />
    <label class="col-form-label">Item Type</label>
    <select id="itemTypeList" name="ItemTypeId" class="form-control">    
    </select>
    <button id="addItemType" type="button" class="btn btn-link">Add</button>
    <br />
    <label class="col-form-label">Language</label>
    <select id="languageList" name="languageId" class="form-control">
    </select>
    <button id="addLanguage" type="button" class="btn btn-link">Add</button>
    <br />
    <label class="col-form-label">Framework</label>
    <select id="frameworkList" name="FrameworkId" class="form-control">
    </select>
    <button id="addFramework" type="button" 
            class="btn btn-link">Add</button>
  </div>
  <div class="form-group text-center">
     <input type="submit" value="Create" class="btn btn-primary" />
  </div>
</form>

Solution

  • <input class="categoryId" value="@category.Id" name="CategoryId" form="itemCreateForm" /> in your loop is creating multiple input controls that are all associated with the form "itemCreateForm". It would be easier to put an input type control inside the form itself. Put an attibute on your button "data-catid", then you can easily pick that up when you click the button, and shove that value into the field in the form before displaying it.

    In your loop, change:

    <button class="addItemButton" type="button">Add Item</button>
    

    to:

    <button class="addItemButton" type="button" data-catid="@category.Id">Add Item</button>
    

    In your loop, remove:

    <input class="categoryId" value="@category.Id" name="CategoryId" form="itemCreateForm" />
    

    In your form, just inside the form element add:

    <input type="hidden" name="CategoryId" />
    

    Then update your jquery to something like:

    $(document).on('click','.addItemButton', function() {
      var cat = $(this).data('catid');
      $('[name=CategoryId]').val(cat);
      // Hide your stuff here
    
      // Show your create form here
    });