locked
EF model binding to a select option complex model RRS feed

  • Question

  • User1347924431 posted

    Hello,

    I'm trying to add a selection option to my model, but I can't seem to get it working.
    I have two models:

    - Computer
    - Display

    Because we use multiple displays of the same kind I don't want to create unique displays bound to the computer.
    However a computer should always have at least one display.
    The displays can also be unbound without having a computer (spare)


    Computer:

        public class Computer
        {
            public Computer()
            {
                Displays = new HashSet<Display>();
            }
            public int ID { get; set; }
            public virtual ICollection<Display> Displays { get; set; }
        }
    }
    

    Display:

        public class Display
        {
            public int ID { get; set; }
            public string Brand { get; set; }
        }

    I used something like this for the view which gives me 3 display fields: (I'd rather have an add button but this is a work in progress)

                @for (var i = 0; i < 3; i++)
                {
                    <div class="form-group">
                        <label asp-for="Computer.Displays" class="control-label"></label>
                        <select asp-for="Computer.Displays" class="form-control"
                                asp-items="@Model.Displays">
                            <option value="">-- Select display --</option>
                        </select>
                    </div>
                }

    Create controller:

    private readonly StickyLockWeb.Data.StickyLockWebAssetContext _context; 
    
           public CreateModel(AContext context)
            {
                _context = context;
            }
    
            public SelectList Displays { get; set; }
    
            public IActionResult OnGet()
            {
                Displays = new SelectList(_context.Display, nameof(Display.ID), nameof(Display.Model));
                return Page();
            }
    
            [BindProperty]
            public Computer Computer { get; set; }
    
            public async Task<IActionResult> OnPostAsync()
            {
                _context.Computer.Add(Computer);
                await _context.SaveChangesAsync();
    
                return RedirectToPage("./Index");
            }
        }

    It does read all displays and I'm able to select each of them, however it doesn't seem to get saved.
    Any ideas how to achieve this?

    Thank you!

    Tuesday, May 11, 2021 2:18 PM

All replies

  • User475983607 posted

    The input names must be indexed for the model binder to identify a collection.

    https://www.learnrazorpages.com/razor-pages/model-binding

    Tuesday, May 11, 2021 2:44 PM
  • User-2054057000 posted

    Put a breakpoint on your line given below:

    await _context.SaveChangesAsync();

    Then find out if your property called "Computer" is having the value which you entered in the text boxes. If not then your model binding is not working. 

    Moreover - If you are getting any errors then provide them to us.

    Tuesday, May 11, 2021 3:54 PM
  • User1347924431 posted

    I assume you mean this part:

        @page
        @model CreateModel
        @{
        }
        <form method="post">
            <input asp-for="Order.Customer" /><br />
            <input asp-for="Order.OrderItems[0].Item" /><br>
            <input asp-for="Order.OrderItems[0].Price" /><br>
            <input type="submit"/>
        </form>

    But how does that work for a  select?

    Tuesday, May 11, 2021 4:25 PM
  • User1347924431 posted

    Everything works fine the Computer entity is created successfully with all attributes however the Display collection is null.

    Tuesday, May 11, 2021 4:26 PM
  • User-474980206 posted

    a select only posts back its selected value (typically an id). the option list is not posted, so must be recreated on post back. typically you bind the select post back value to a single field. in essence its a textbox that posts the selected option's value rather than allowing the user to type a value.

     

    Tuesday, May 11, 2021 5:23 PM
  • User1686398519 posted

    Hi Carlovdv, 

    You need to set the input name correctly.You also need to add a hidden input to store the text of the selected drop-down list.

    I modified your code, you can refer to it.

    xxx.cshtml

    <form asp-page="Index3" method="post">
        @for (var i = 0; i < 3; i++)
        {
            <div class="form-group">
                <label asp-for="Computer.Displays" class="control-label"></label>
                <input name="Computer.Displays[@i].Brand" hidden />
                <select name="Computer.Displays[@i].ID" class="form-control"
                        asp-items="@Model.Displays">
                    <option value="">-- Select display --</option>
                </select>
            </div>
        }
        <button type="submit">submit</button>
    </form>
    @section scripts{
        <script>
            $("form").on("change", "select[name*='ID']", function () {
                $(this).siblings("input[name*='Brand']").val($(this).children("option:selected").text())
            });
        </script>
    }

    Here is the result. 

    Best Regards,

    YihuiSun

    Wednesday, May 12, 2021 8:08 AM