Search code examples
formsasp.net-coredropdownrazor-pagesproperty-binding

How to connect page model object property to list of objects (from db) in <select> tag? ASP.NET Razor Pages


Weapon model:

public class Weapon {
        public int Id { get; set; }
        public string Name { get; set; }
        public int BaseDamage { get; set; } // base damage with average attack
        public int MagicDamage { get; set; }
        public int ActionCost { get; set; }
        public int HitChance { get; set; }
    }

Creature model contains some simple properties like Id and also Weapon.

I'm trying to create drop down list with weapons from database and add selected weapon to Creature object when form is submitted by button.

Page model contains Creature object and list of Weapons:

public Creature Creature { get; set; }
public IEnumerable<Weapon> Weapons { get; set; }

OnGet method loads selected Creature and list of Weapons.

public void OnGetDetails(int id, int toggle)        {
            Creature = new GetCreature(_ctx).Get(id);
            LastToggle = toggle;            
            Weapons = new GetWeapons(_ctx).Get();
}

First idea:

<form method="post">
    <input type="hidden" asp-for="Creature.Id"/>
    <select id="weapon" class="form-control bg-secondary text-light" asp-for="Creature.Weapon" asp-items="@Model.Weapons">        
    </select>

    <button type="submit" class="btn btn-outline-warning m-2" asp-page-handler="UpdateWeapon">Wybierz</button>                       
</form>

But asp-items="@Model.Weapons" is not accepted by VS:
CS0266: Cannot implicitly convert type 'System.Collection.Generic.IEnumerable<LastTemple.Models.Weapon>' to 'System.Collections.GenericIEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItems>'. An explicit conversons exist (are you missing a cast?)

Second idea (Updated [previous version had value="@item.Id"]):

<form method="post">
    <input type="hidden" asp-for="Creature.Id"/>
    <select id="weapon" class="form-control bg-secondary text-light" asp-for="Creature.Weapon">
        @foreach (var item in Model.Weapons) {
            <option value="@item">@item.Name - @item.BaseDamage | @item.MagicDamage | @item.ActionCost PA | @item.HitChance%</option>
            }
    </select>

    <button type="submit" class="btn btn-outline-warning m-2" asp-page-handler="UpdateWeapon">Wybierz</button>                       
</form>

Still don't work. Don't throw errors but Creature.Weapon remains null, is not passed from select list.

PostMethod:

public async Task<IActionResult> OnPostUpdateWeaponAsync() {
            var item = _ctx.Creatures.Find(Creature.Id);

            if (item == null)
            {
                return RedirectToPage("Creature");
            }

            if (Creature.Weapon == null)
            {
                return RedirectToPage("Creature");
            }

            await new EditCreature(_ctx).UpdateWeapon(Creature);
                        
            return RedirectToPage("Creature");
        }

Creature Model: https://github.com/Mlorism/LastTemple/blob/master/LastTemple/Models/Creature.cs
Weapon Model: https://github.com/Mlorism/LastTemple/blob/master/LastTemple/Models/Weapon.cs

Page:
https://github.com/Mlorism/LastTemple/blob/master/LastTemple/Pages/Manage/Creature.cshtml.cs
and
https://github.com/Mlorism/LastTemple/blob/master/LastTemple/Pages/Manage/Creature.cshtml


Solution

  • Second idea:

    <form method="post">
        <input type="hidden" asp-for="Creature.Id" />
        <select id="weapon" class="form-control bg-secondary text-light" asp-for="Creature.Weapon">
            @foreach (var item in Model.Weapons)
            {
                <option value="@item.Id">@item.Name - @item.BaseDamage | @item.MagicDamage | @item.ActionCost PA | @item.HitChance%</option>
            }
        </select>
    
        <button type="submit" class="btn btn-outline-warning m-2" asp-page-handler="UpdateWeapon">Wybierz</button>
    </form>
    

    Still don't work. Don't throw errors but Creature.Weapon remains null, is not passed from select list.

    You are binding the weapon Id, so

    change

    asp-for="Creature.Weapon"
    

    to

    asp-for="Creature.Weapon.Id"