You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core MVC用户职业信息展示、新增与删除功能问题排查

问题:ASP.NET Core MVC编辑页实现职业信息的展示、新增与删除

需求

  • 在ASP.NET Core MVC编辑页面展示用户已录入并存储在数据库的职业信息
  • 支持新增职业信息
  • 支持删除已有职业信息

现有实现状态

  • 控制器:已完成可正常运行的代码,能从数据库获取当前用户的所有职业信息
  • 模型:已定义TutorProfessionAndCost实体类,包含职业相关字段
  • 编辑页面:初始版本无法展示已有信息,但通过JS可新增职业控件
  • JS代码:已实现点击动态新增职业控件的功能,运行正常

尝试的方案及问题

使用for循环遍历用户职业信息渲染页面,能展示并编辑已有信息,但无法新增新的职业信息


解决方案

核心思路是复用动态新增的JS逻辑渲染已有数据,同时保证表单字段命名符合ASP.NET MVC模型绑定规则(集合格式[index].PropertyName),实现展示、新增、删除的统一交互。

步骤说明

  1. 统一已有数据与新增数据的DOM结构,确保两者表单字段命名规则一致
  2. 用Razor循环渲染已有数据,复用JS新增功能的模板结构
  3. 为每个职业条目添加删除按钮,通过事件委托处理动态元素的删除逻辑
  4. 保证表单字段命名满足Professions[@index].XXX格式,让模型绑定正确识别集合数据

完整代码示例

模型代码(TutorProfessionAndCost及视图模型)

// 职业实体类
public class TutorProfessionAndCost
{
    public int Id { get; set; }
    public string ProfessionName { get; set; }
    public decimal HourlyCost { get; set; }
    // 其他职业相关字段
}

// 页面视图模型(封装页面所需全部数据)
public class TutorEditViewModel
{
    public List<TutorProfessionAndCost> Professions { get; set; } = new List<TutorProfessionAndCost>();
    // 其他用户信息字段
}

控制器代码

public IActionResult Edit()
{
    var viewModel = new TutorEditViewModel();
    // 从数据库获取当前用户的职业信息(替换为实际查询逻辑)
    viewModel.Professions = _dbContext.TutorProfessions
        .Where(t => t.UserId == currentUserId)
        .ToList();
    return View(viewModel);
}

[HttpPost]
public IActionResult Edit(TutorEditViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        // 处理职业信息的增删改:删除数据库中不在viewModel里的条目,新增/更新存在的条目
        _dbContext.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(viewModel);
}

视图代码(Edit.cshtml)

@model TutorEditViewModel

<form asp-action="Edit" method="post">
    <!-- 其他用户信息表单字段 -->

    <div id="professions-container">
        <!-- 渲染已有职业信息 -->
        @for (int i = 0; i < Model.Professions.Count; i++)
        {
            <div class="profession-item mb-3">
                <input type="hidden" asp-for="Professions[i].Id" />
                <div class="form-group">
                    <label asp-for="Professions[i].ProfessionName"></label>
                    <input asp-for="Professions[i].ProfessionName" class="form-control" />
                    <span asp-validation-for="Professions[i].ProfessionName" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Professions[i].HourlyCost"></label>
                    <input asp-for="Professions[i].HourlyCost" class="form-control" />
                    <span asp-validation-for="Professions[i].HourlyCost" class="text-danger"></span>
                </div>
                <button type="button" class="btn btn-danger delete-profession">删除</button>
            </div>
        }
    </div>

    <button type="button" id="add-profession" class="btn btn-primary mb-3">新增职业</button>
    <button type="submit" class="btn btn-success">保存</button>
</form>

<!-- 新增职业的模板(隐藏,用于JS克隆) -->
<script type="text/template" id="profession-template">
    <div class="profession-item mb-3">
        <input type="hidden" name="Professions[{index}].Id" value="0" />
        <div class="form-group">
            <label>职业名称</label>
            <input type="text" name="Professions[{index}].ProfessionName" class="form-control" />
        </div>
        <div class="form-group">
            <label>小时费用</label>
            <input type="number" name="Professions[{index}].HourlyCost" class="form-control" />
        </div>
        <button type="button" class="btn btn-danger delete-profession">删除</button>
    </div>
</script>

JS代码(整合新增与删除逻辑)

$(document).ready(function() {
    // 新增职业按钮点击事件
    $('#add-profession').click(function() {
        var container = $('#professions-container');
        // 用当前条目数量作为新索引
        var index = container.children('.profession-item').length;
        // 克隆模板并替换索引占位符
        var template = $('#profession-template').html().replace(/\{index\}/g, index);
        container.append(template);
    });

    // 删除职业按钮点击事件(事件委托,兼容动态生成的元素)
    $('#professions-container').on('click', '.delete-profession', function() {
        $(this).closest('.profession-item').remove();
        // 可选:重新调整剩余条目的索引(非必须,ASP.NET Core支持非连续索引)
        reindexProfessionItems();
    });

    // 重新索引函数(可选,保证索引连续)
    function reindexProfessionItems() {
        $('#professions-container .profession-item').each(function(index) {
            $(this).find('input, select, textarea').each(function() {
                var name = $(this).attr('name').replace(/Professions\[\d+\]/, `Professions[${index}]`);
                $(this).attr('name', name);
            });
        });
    }
});

关键说明

  1. 模型绑定兼容性:Professions[index].PropertyName的命名格式是ASP.NET Core MVC识别集合数据的标准格式,确保表单数据能正确绑定到视图模型的List<TutorProfessionAndCost>属性。
  2. 模板复用:已有数据和新增数据使用完全一致的DOM结构,保证交互逻辑统一。
  3. 事件委托:删除按钮使用事件委托绑定,确保动态生成的条目也能触发删除操作。
  4. 索引灵活性:ASP.NET Core支持非连续索引绑定,若不需要严格连续的索引,可跳过reindexProfessionItems函数,简化逻辑。

内容的提问来源于stack exchange,提问作者Artem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 16:38:30