Search code examples
asp.net-mvcformsasp.net-mvc-5asp.net-mvc-viewmodel

Passing data from Form with variable number of inputs - MVC 5


I've been looking for similar questions in here but still couldn't find a solution to my problem.

I have a page that contains some text and a form and they both share the same ViewModel as follows:

public class MyViewModel
 {
   public IEnumerable<WordingB> WordingBs { get; set; }
   public IEnumerable<WordingC> WordingCs { get; set; }
   public IEnumerable<Question> Questions { get; set; } 
}

Here's a bit more detail about WordingB, WordingC and Question:

public class WordingB
    {           
        public string EOW { get; set; }
    }



public class WordingC
    {           
        public string EOW { get; set; }
    }




public class Question
    {           
        public string QuestionText { get; set; }
        public string Answer {get; set;}
    }

And this is the page in question:

@model MyProject.ViewModels.MyViewModel   

<div class="col-md-6 masonry listview-block">
    @foreach (var wording in Model.WordingBs)
    {
        <div class="block">                
            <p>@Html.Raw(@wording.EOW)</p>
        </div>
    }
    @foreach (var wording in Model.WordingCs)
    {
        <div class="block">              
            <p>@Html.Raw(@wording.EOW)</p>
        </div>
    }

</div>


@using (Ajax.BeginForm("Routing", "Partials", new AjaxOptions { UpdateTargetId = "Target", LoadingElementId = "spinner", HttpMethod = "POST", InsertionMode = InsertionMode.Replace }))
{


            <div id="quick-post" class="block-body form-validation">
                @foreach (var question in Model.Questions)
                {
                    <div class="form-group">
                        <label for="QuestionText">@question.QuestionText</label>
                        <input type="text" class="form-control input-sm input-sm" name="Answer">
                    </div>
                }
                <div class="form-group">
                    <label for="postcode">PostCode</label>
                    <input type="text" class="form-control input-sm validate[required] input-sm" name="postcode" [email protected]["postcode"]>

                </div>

                <div class="form-group">
                    <label>Loss Description</label>
                    <textarea></textarea>
                </div>

                <input type="submit" class="btn btn-primary btn-xs" value="Route">

            </div>

        </div>
    </div>

}

The idea is that some Admin person is able to add questions to the form. (questions are stored in a table) There's a controller that uses the MyViewModel and returns the model that I need to the view.

 public ActionResult EOW()
        {
            QuestionsandWording viewModel = new QuestionsandWording();

            viewModel.Questions = // first query

            viewModel.WordingBs = // second query

            viewModel.WordingCs = // third query

            return View(viewModel);
        }

The problem that I am facing now is passing the data from my form to a controller. The form can have zero to 30 or 40 questions as far as I'm concerned! I feel like I've hit the limit of my knowledge and I'm in serious need of advice.


Solution

  • With the help of cosset and Derek, I managed to find a workaround as follows:

    1) I gave a name to my input element like this:

    <input type="text" name="Answer">
    

    I didn't need to iterate with Answer[i] as suggested on one of the answers as the framework automatically binds all inputs with same name into a List element that my method can take as an argument. Like this:

    public ActionResult Routing(List<string> Answer){} 
    

    2) I also needed to use the value of my label tags in my Routing method and had no clue how to do it. Again, Cosset suggested that I use a hidden field and give it a value of the label text. This worked perfectly.

    <label for="Answer">@question.QuestionText</label>
    <input type="hidden" name="QuestionText" [email protected] />
    

    And the method now looks like this :

    public ActionResult Routing(List<string> Answer, List<string> QuestionText){} 
    

    Now I've got what I needed. To pass all data from my form to the controller (Both labels and inputs) without having to worry about the MyViewModel.

    For the sake of learning, I would quite like to know if there are any other ways of achieving this at all.