locked
Editor template rows collection values sent null to controller RRS feed

  • Question

  • User-875744750 posted

    hello

    here is my model classes

    public class Money{
        public int StructureId {get; set;}
        // public enum Quarter:byte{ FirstQuarter = 1, SecondQuarter=2, 
        //  ThirdQuarter=3, FourthQuarter=4}
        public Querter Quarter{get; set;}
        public int Year {get; set;}
        public List<TypeMoney> MoneyTypes {get; set;}
    }
    
    public class TypeMoney{
        //public enum Type:byte{ Bill= 1, Coin=2}
        public Type Type{get; set;}
        //public enum Value = {one = 1, tow=2, five=5, ten=10, Etc};
        public Value Value{get; set;}
        public int Number{get; set;}
    
    }

    i want to store the money with their value (the number of money, the type of money: bills or coins and the values of both) for each quarter.

    and i want to append an editor template as row to table dynamicly by jquery, so that when the user want to fill one row , he click on AddMoney button, only one row is appened to table. this row is presented by editor template for each MoneyTypes object (the user will fill typemoney object informations). and he click again on AddMoney button, when he want to fill information in an other row and so on.

    untill he submit all to controller: the money data with its collection of typeMoney objects data.

    for this i have implemented an editor template and i created a partial view _create.cshtml for this editor template so that i can append this partial as row

     my money strongly typed view, that's the main view containe a html table for the list of type Money objects

    In the controller action i have passed a model "money" that contains a collection of type money to view

    My issue is when i submit this form, the list of type money objects that's sent to the controller is evaluated to null

    a data binding is not working because the incorrect name that's why the collection of typeMoney objects est sended null to controller

    How to fix this even when I insert editor template row by row to table by jquery?

    Here is my editor template

    @model ProjectName.TypeMoney
    
    <tr class="insertMoneyTr">
        <td>
            @Html.DropDownListFor(model => model.Type, null, "--selectionnez--", 
     new { @class = "typeMoney form-control" })
        </td>
        <td>
            @Html.DropDownListFor(model => model.Valeur, null, new { @class = 
            "valueMoney form-control" })
    
        </td>
        <td>
            @Html.TextBoxFor(model => model.Numbre, new { @class = "nombre form- 
            control" })
        </td>
    
        <td>
            <button class="deleteMoney btn btn-danger glyphicon glyphicon- 
            remove">
           </button>
        </td>
    </tr>   

    the main view

    @model MyProjectName.Money
    
         @using (Html.BeginForm("Index", "Moneis", FormMethod.Post))
         {
         @Html.LabelFor(model=>model.StructureId , new { @class = "control-label col-md-1" })
                        <div class="col-md-3">
                            @Html.DropDownListFor(model=>model.StructureId, null, "--Selectionnez une structure--", new { @class = "form-control" })
                        </div>
    
                            @Html.LabelFor(model=>model.Quarter, new { @class = "control-label col-md-1" })
                            <div class="col-md-3">
                                @Html.DropDownListFor(model=>model.Quarter, null, "--Selectionnez un trimestre--", new { @class = "form-control" })
                            </div>
    
                            @Html.LabelFor(model=>model.Year, new { @class = "control-label col-md-1" })
                            <div class="col-md-3">
                            @Html.DropDownListFor(model=>model.Year, null, "--Selectionnez une année--", new { @class = "form-control" })
                            </div>
    
                    </div>
    
    
                    <p>
    
                        @Html.ActionLink(" ", "_Create", null, new { @class = "glyphicon glyphicon-plus btn btn-default", style = "background:#ff6a00;color:white", id = "AddMoney" })
                    </p>
                    <div id="listEspecesDiv" class="row">
     <table class="table table-striped" id="especesList">
                            <thead>
    
                                <tr>
                                    <th>Type</th>
    
                                    <th>Value</th>
    
    
                                    <th>Numbre</th>
    
                                    <th>Amount</th>
    
                                    <th></th>
                                </tr>
    
                            </thead>
                            <tbody>
    
                               @*the partial view _create is displayed when click button AddMoney*@ 
    
                            </tbody>
    <div class="row"> <input type="submit" value="Enregistrer" class="btn btn-default pull-right" style="background: #ff6a00; color: white; margin: 10px" /> </div>
    }

    Partial View _create.cshtml

    @model ProjectName.TypeMoney

    @Html.EditorForModel();

    The jquery code

    //the id of button that add editor template is AddMoney
    
    $("#AddMoney").click(function (e) {
                    e.preventDefault();
    
                    $.ajax({
                        url: "Money/_Create",
                        type: 'Get',
                        dataType: 'html',
                        success: function (result) {
                            $("#listEspecesDiv tbody").append(result);
                        }
                    });
    
    
                });

    Friday, January 18, 2019 9:25 PM

All replies

  • User475983607 posted

    The code is very confusing and I can't figure out how the code is indented to function. 

    Every DropDownListFor helpers is has a null select list parameter.  There is no indication where or how the selects are populated. 

    @Html.DropDownListFor(model=>model.Year, null, "--Selectionnez une année--", new { @class = "form-control" })

    The AJAX function updates #listEspecesDiv which does not exist in the code snippets.  You did not post the _Create action.  I'm wondering if _Create is a Partial View? Views and Partial cannot be invoked directly.  This is a standard concept in MVC.  Lastly, it looks like you trying to create a record without sending data. 

    $("#AddMoney").click(function (e) {
                    e.preventDefault();
    
                    $.ajax({
                        url: "Money/_Create",
                        type: 'Get',
                        dataType: 'html',
                        success: function (result) {
                            $("#listEspecesDiv tbody").append(result);
                        }
                    });
    
    
                });

    Maybe go through a few MVC tutorials first.

    https://www.asp.net/mvc/overview/getting-started

    Friday, January 18, 2019 10:06 PM
  • User-875744750 posted

    mgebhard

    Every DropDownListFor helpers is has a null select list parameter.  There is no indication where or how the selects are populated. 

    here's my controller code:

    public ActionResult Index()
    {
         ViewBag.StructureId= new SelectList(GetStructures(), "Id", "Name");
         ViewBag.Year = new SelectList(GetYears());
         ViewBag.Quater =  new SelectList(Enum.GetValue(typeof(Quarter));
    
         return View()
    }
    
    //partial view for Editor template
    public PartialViewResult _Create(Money money)
    {
    	return PartialView(); 
    }
    //save money with list of typeMoney objects 
    [HttpPost]
    public ActionResult Index(Money money)
    {
    	Context.Monies.Add(money);
    	Context.SaveChanges();
    	foreach(var item in money.MoneyTypes){
    		context.MoneyTypes.Add(item);
    		Context.SaveChanges();
    	}
    ViewBag.StructureId= new SelectList(GetStructures(), "Id", "Name");
    ViewBag.Year = new SelectList(GetYears());
    ViewBag.Quater = new SelectList(Enum.GetValue(typeof(Quarter));

    return View() }

    mgebhard

    The AJAX function updates #listEspecesDiv which does not exist in the code snippets.  You did not post the _Create action.  I'm wondering if _Create is a Partial View? Views and Partial cannot be invoked directly.  This is a standard concept in MVC.  Lastly, it looks like you trying to create a record without sending data. 

    a have just append partial view to html table by get request for displaying the rows, not for submit.

    after the user fills this rows by his data  . he submit all the main view data. look BeginForm  in main view  

    Friday, January 18, 2019 10:38 PM
  • User475983607 posted

    here's my controller code:

    public ActionResult Index()
    {
         ViewBag.StructureId= new SelectList(GetStructures(), "Id", "Name");
         ViewBag.Year = new SelectList(GetYears());
         ViewBag.Quater =  new SelectList(Enum.GetValue(typeof(Quarter));
    
         return View()
    }

    I don't understand the code. ViewBag,Year and ViewBag.Quater are not used in any of the View posted in your source code.  The DropDownlistFor specifically sets the select item parameter to null.

    a have just append partial view to html table by get request for displaying the rows, not for submit.

    after the user fills this rows by his data  . he submit all the main view data. look BeginForm  in main view  

    The PartialView is not formatted properly for submitting a collection.  The input names must contain consecutive indexes for the model binder to work properly. This was explained in your other thread.  You'll need to write code to keep track table index row in order to properly craft the 

    Here is an example of the HTML.  I copied this from https://www.learnrazorpages.com/razor-pages/model-binding but the concept is the same in MVC.

    <tr>
        <td>
            <input type="text" name="[0].FirstName" />
        </td>
        <td>
            <input type="text" name="[0].LastName" />
        </td>
        <td>
            <input type="text" name="[0].Email" />
        </td>
    </tr>
    <tr>
        <td>
            <input type="text" name="[1].FirstName" />
        </td>
        <td>
            <input type="text" name="[1].LastName" />
        </td>
        <td>
            <input type="text" name="[1].Email" />
        </td>
    </tr>

    Friday, January 18, 2019 11:25 PM
  • User-875744750 posted

    mgebhard

    I don't understand the code. ViewBag,Year and ViewBag.Quater are not used in any of the View posted in your source code.  The DropDownlistFor specifically sets the select item parameter to null.

    the main view is called Index.sctml. look thz scope of html.beginform

    mgebhard

    Here is an example of the HTML.  I copied this from https://www.learnrazorpages.com/razor-pages/model-binding but the concept is the same in MVC.

    <tr>
        <td>
            <input type="text" name="[0].FirstName" />
        </td>
        <td>
            <input type="text" name="[0].LastName" />
        </td>
        <td>
            <input type="text" name="[0].Email" />
        </td>
    </tr>
    <tr>
        <td>
            <input type="text" name="[1].FirstName" />
        </td>
        <td>
            <input type="text" name="[1].LastName" />
        </td>
        <td>
            <input type="text" name="[1].Email" />
        </td>
    </tr>

    thank you, it rest how apply this in my EditorTemplate so that the modal binder can bind a editor template collection and list of typrMoney object not sent null to controller?

    Saturday, January 19, 2019 12:14 PM
  • User475983607 posted

    the main view is called Index.sctml. look thz scope of html.beginform

    You're comments are very confusing, there is not a single ViewBag.Year or ViewBag.Quater reference in the main View. 

    thank you, it rest how apply this in my EditorTemplate so that the modal binder can bind a editor template collection and list of typrMoney object not sent null to controller?

    We've explained the required format a few times.   It is up to you to design and write appropriate HTML.  I'm not sure what else we can do for you other than point to you the MVC tutorials as it seems you do not understand the basics.

    Saturday, January 19, 2019 1:39 PM
  • User-875744750 posted

    You're comments are very confusing, there is not a single ViewBag.Year or ViewBag.Quater reference in the main View. 

    null in the second argument of dropdwnloist because of if the name of ViewBag dynamic property is the same of the name of the model property they're matched

    i ask a question: can i submit this form with Editor template collection data by ajax jquery?without modify the editor template

    Saturday, January 19, 2019 5:38 PM
  • User475983607 posted

    bensam16

    null in the second argument of dropdwnloist because of if the name of ViewBag dynamic property is the same of the name of the model property they're matched

    Here's a basic example.

        public enum Colors
        {
            Red,
            Green,
            Blue
        };
    
        public class EnumTextVm
        {
            public Colors Color { get; set; }
        }
            [HttpGet]
            public ActionResult EnumTest()
            {          
                return View();
            }
            
            [HttpPost]
            public ActionResult EnumTest(EnumTextVm vm)
            {
                return Json(vm);
            }
    @model MvcDemo.Models.EnumTextVm
    
    @{
        ViewBag.Title = "EnumTest";
    }
    
    <h2>EnumTest</h2>
    
    @using (Html.BeginForm())
    {
    
        <div class="form-horizontal">
            <div class="form-group">
                @Html.LabelFor(model => model.Color, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownListFor(model => model.Color,
                        new SelectList(Enum.GetValues(typeof(MvcDemo.Models.Colors)),
                        new { htmlAttributes = new { @class = "form-control" } }))
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />
                </div>
            </div>
        </div>
    }

    The idea is pretty simple.  The html helper renders a select with the name "Color" that matches the ViewModels property by name and type.

    Your approach will work...

     @Html.DropDownListFor(model => model.Color,
                        null,
                        new { htmlAttributes = new { @class = "form-control" } })
    @model MvcDemo.Models.EnumTextVm
    
    @{
        ViewBag.Title = "EnumTest";
    }
    
    <h2>EnumTest</h2>
    
    @using (Html.BeginForm())
    {
    
        <div class="form-horizontal">
            <div class="form-group">
                @Html.LabelFor(model => model.Color, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownListFor(model => model.Color,
                        null,
                        new { htmlAttributes = new { @class = "form-control" } })
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />
                </div>
            </div>
        </div>
    }

    ... but in my opinion, your approach is very confusing.  It's hard to debug because the model name has to match the ViewBag name.  Plus the approach makes a copy of the enum and passes the enum in the context when you can just reference the type directly.  

    Keep in mind, the following code has a syntax error.  The method is GetValues with an "s" unless you've build a custom extension.  It is very hard to understand code when it has visible syntax errors.  If you've crafted an extension method, then you should explain how the code works.  Otherwise, we have to guess. 

    ViewBag.Quater =  new SelectList(Enum.GetValue(typeof(Quarter));

    bensam16

    i ask a question: can i submit this form with Editor template collection data by ajax jquery?without modify the editor template

    Of course, you can submit data using AJAX. That approach has its design challenges.  One being it is up to you - the developer - to update the DOM using JavaScript.  

    Saturday, January 19, 2019 7:51 PM