Bloater
Bloater

Reputation: 69

MVC view not binding inputs in for loop if loop contains if statement to control input rendering

I have a view that creates a number of input boxes based on the length of a view model property of type List<decimal>.

I use a for loop with index to bind the inputs to the list. This works fine, and user inputted values get passed to POST method ok. The following code works fine (e.g. 3 inputs with values of 1, 2 and 3 then MyList = [1,2,3]):

@for (var i = 0; i < Model.MyList.Count; i++)
{
    <input asp-for="MyList[i]" type="text">
}

However, I need to set the disabled state of the first input box to "disabled". If I add an if statement as follows, the binding doesn't work and the MyList property is empty with count of zero. (e.g. 2 inputs - first one is read only - with values of 2 and 3 then MyList = []. I pre-populate first input box in controller with value of 1 so I would hope to get MyList = [1,2,3] but I don't)

@for (var i = 0; i < Model.MyList.Count; i++)
      if (i == 0)
      {
          <input asp-for="MyList[i]" type="text" disabled="disabled">
      }
      else
      {
          <input asp-for="MyList[i]" type="text">
      }
}

Code has been boiled down to the minimum for brevity

Any ideas why this if statement is killing the binding, or how to get round this? Thanks for reading!

EDIT: I have tried rendering the first input before and outside the loop and then starting the loop at index of 1, but the same problem occurs.

UPDATE: I can easily set the disabled state to true by using jQuery but this kills the property too. So any bound input that is disabled is clearing MyList.

Upvotes: 2

Views: 324

Answers (1)

user3559349
user3559349

Reputation:

The DefaultModelBinder requires that collection indexers start an zero and be consecutive (unless you add a input for the collection indexer).

Disabled controls do no submit a value, so when you disable the first input, the first item has an indexer of 1, not 0, so model binding fails.

A simple way to solve this would be to make the input readonly

<input asp-for="MyList[i]" type="text" readonly="readonly"> 

Another option is to include a hidden input for the collection indexer which allows collection to be bound where the indexer is not zero-based and consecutive.

@for (var i = 0; i < Model.MyList.Count; i++)
      if (i == 0)
      {
          <input asp-for="MyList[i]" type="text" disabled="disabled">
      }
      else
      {
          <input asp-for="MyList[i]" type="text">
      }
      <input type="hidden" name="MyList.Index" value="@i" />
}

But note that in that case, the collection will be missing the first item (because the value of the disabled input will not be submitted).

Upvotes: 1

Related Questions