模型中的HTML表数据没有更新

本文关键字:更新 数据 HTML 模型 | 更新日期: 2023-09-27 17:51:13

我有一个ViewModel,其中包含两个条件列表- BuyConditionsSellConditions -加上几个属性- Name等。列表使用视图中的表显示。jQuery允许对表进行操作——向表中添加条件(来自Buy Condition/Sell Condition DDL)并从表中删除条件。

我的问题是,当它被发布回控制器时,模型中的条件列表没有更新。

可能指出问题的是,当模型返回到视图时(由于ModelStat.IsValid失败),市场DDL中的数据仍然存在,但买卖条件DDL中的数据不存在。

我在网上找不到一个例子来找出我错在哪里。有人做过吗?

ViewModel:

public class StrategyViewModel
{
    public string ID { get; set; }
    [Display(Name = "Strategy Name")]
    public string StrategyName { get; set; }
    [Display(Name = "Market")]
    public string SelectedMarketID { get; set; }
    [Display(Name = "Asset Type")]
    public string SelectedShareTypeID { get; set; }
    [Display(Name = "Share")]
    public string SelectedShareID { get; set; }
    public bool Active { get; set; }
    public IEnumerable<Market> Markets { get; set; }              // top level of three cascading DDL's - the other two populated via JQuery
    public IEnumerable<Condition> BuyConditionList { get; set; }  // used to populate DDL
    public IEnumerable<Condition> SellConditionList { get; set; } // used to populate DDL 
    public List<BuyCondition> BuyConditions { get; set; }         // list of Buy Conditions
    public List<SellCondition> SellConditions { get; set; }       // list of Sell Conditions
    AppRepository repository = new AppRepository();
    public StrategyViewModel()
    {
        // populate lists
        Markets = ListUtils.AddDefaultOptionToMarketList( repository.GetMarkets(), -1, "Select a Market" ).AsEnumerable();
        BuyConditionList = repository.GetConditions();
        SellConditionList = repository.GetConditions();
        BuyConditions = new List<BuyCondition>();
        SellConditions = new List<SellCondition>();
    }
}

控制器:

 public ActionResult Create()
    {
        StrategyViewModel model = new StrategyViewModel();
        return View(model);
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "User, Admin")]
    public ActionResult Create(StrategyViewModel model)
    {
        // for debugging
        var errorList = ModelState.Values.SelectMany(v => v.Errors);
        if (ModelState.IsValid)
        {
            var user = repository.GetCurrentUser(User.Identity.GetUserId());
            var strategy = new Strategy();
            strategy.StrategyName = model.StrategyName;
            strategy.ShareID = Convert.ToInt32(model.SelectedShareID);
            strategy.BuyConditions = model.BuyConditions.ToList();
            strategy.SellConditions = model.SellConditions.ToList();
            strategy.Active = model.Active;
            int strategyID = repository.AddStrategy(user, strategy);
            return RedirectToAction("Index");
        }
        return View(model);
    }

视图:

@model ShareTrigger.Models.StrategyViewModel
@{
ViewBag.Title = "Create";
}
@{Html.EnableUnobtrusiveJavaScript(true);}

<script type="text/javascript">
$(document).ready(function () {
    $(function () {
        $('#SelectedMarketID').change(function () {
            var selectedMarketID = $(this).val();
            $.getJSON('@Url.Action("ShareTypes")', { marketId: selectedMarketID }, function (shareTypes) {
                var shareTypesSelect = $('#SelectedShareTypeID');
                shareTypesSelect.empty();
                $.each(shareTypes, function (index, shareType) {
                    shareTypesSelect.append($('<option/>').attr('value', shareType.Value).text(shareType.Text));
                });
                $('#SelectedShareTypeID').trigger("change");
            });
        });
        $('#SelectedShareTypeID').change(function () {
            var selectedShareTypeId = $(this).val();
            var selectedMarketID = $('#SelectedMarketID').val();
            $.getJSON('@Url.Action("Shares")', { shareTypeId: selectedShareTypeId, marketID: selectedMarketID }, function (shares) {
                var sharesSelect = $('#SelectedShareID');
                sharesSelect.empty();
                $.each(shares, function (index, share) {
                    sharesSelect.append($('<option/>').attr('value', share.Value).text(share.Text));
                });
            });
        });
    });
    $('#AddBuyCondition').click(function () {
        var conditionID = +$("#BuyConditionList").val();
        if (conditionID != -2) {
            conditionID = +$("#BuyConditionList").val();
            var conditionText = $("#BuyConditionList").find('option:selected').text();
            $("tr:contains('Add')").remove();
            $('#BCDropDownRow').before('<tr class="bcrow"><td class="BuyConditionCell" data-conditionID="' + conditionID + '"><input data-val="true" data-val-number="The field ConditionID must be a number." data-val-required="The ConditionID field is required." id="item_ConditionID" name="item.ConditionID" type="hidden" value="' + conditionID + '">' + conditionText + '</td><td><button class="RemoveBuyCondition type="button" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-minus"></span></button></td></tr>');
            $("#BuyConditionList").find('option:selected').remove();
            var rows = $('#BuyConditionList option').size();
            if (rows == 0) { $("#BuyConditionList").append('<option value="-2">No more conditions to select</option>'); }
        }
    });
    $('#BuyConditionsTable').on('click', '.RemoveBuyCondition', function () {
        var conditionID = +$(this).parent().parent().find('.BuyConditionCell').data('conditionid');
        var conditionText = $(this).parent().parent().find('.BuyConditionCell').text();
        $(this).closest('.bcrow').remove();
        $('#BuyConditionList option[value="-2"]').remove();
        $("#BuyConditionList").append('<option value="' + conditionID + '">' + conditionText + '</option>');
        var options = $('#BuyConditionList option');
        var arr = options.map(function (_, o) { return { t: $(o).text(), v: o.value }; }).get();
        arr.sort(function (o1, o2) { return o1.t > o2.t ? 1 : o1.t < o2.t ? -1 : 0; });
        options.each(function (i, o) {
            o.value = arr[i].v;
            $(o).text(arr[i].t);
        });
    });

    $('#AddSellCondition').click(function () {
        var conditionID = +$("#SellConditionList").val();
        if (conditionID != -2) {
            conditionID = +$("#SellConditionList").val();
            var conditionText = $("#SellConditionList").find('option:selected').text();
            $("tr:contains('Add')").remove();
            $('#SCDropDownRow').before('<tr class="scrow"><td class="SellConditionCell" data-conditionID="' + conditionID + '"><input id="item_ConditionID" name="item.ConditionID" type="hidden" value="' + conditionID + '">' + conditionText + '</td><td><button class="RemoveSellCondition type="button" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-minus"></span></button></td></tr>');
            $("#SellConditionList").find('option:selected').remove();
            var rows = $('#SellConditionList option').size();
            if (rows == 0) { $("#SellConditionList").append('<option value="-2">No more conditions to select</option>'); }
        }
    });
    $('#SellConditionsTable').on('click', '.RemoveSellCondition', function () {
        var conditionID = +$(this).parent().parent().find('.SellConditionCell').data('conditionid');
        var conditionText = $(this).parent().parent().find('.SellConditionCell').text();
        $(this).closest('.scrow').remove();
        $('#SellConditionList option[value="-2"]').remove();
        $("#SellConditionList").append('<option value="' + conditionID + '">' + conditionText + '</option>');
        var options = $('#SellConditionList option');
        var arr = options.map(function (_, o) { return { t: $(o).text(), v: o.value }; }).get();
        arr.sort(function (o1, o2) { return o1.t > o2.t ? 1 : o1.t < o2.t ? -1 : 0; });
        options.each(function (i, o) {
            o.value = arr[i].v;
            $(o).text(arr[i].t);
        });
    });
});
</script>
<h2>Create Strategy</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
    <hr />
    @Html.ValidationSummary(true)
    <div class="form-group">
        @Html.LabelFor(model => model.StrategyName, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.StrategyName)
            @Html.ValidationMessageFor(model => model.StrategyName)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(model => model.SelectedMarketID, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(x => x.SelectedMarketID, new SelectList(Model.Markets, "MarketId", "MarketCode"))
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(model => model.SelectedShareTypeID, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(x => x.SelectedShareTypeID, Enumerable.Empty<SelectListItem>(), "Select an Asset Type")
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(model => model.SelectedMarketID, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(x => x.SelectedShareID, Enumerable.Empty<SelectListItem>(), "Select a Share")
        </div>
    </div>
    <div>
        &nbsp;
    </div>
    <div class="col-md-10">
        <table class="table" id="BuyConditionsTable">
            <tr>
                <th>
                    @Html.DisplayName("Buy Conditions")
                </th>
                <th></th>
            </tr>
            @foreach (var item in Model.BuyConditions)
            {
                <tr>
                    <td>
                        @Html.HiddenFor(modelItem => item.ConditionID)
                        @Html.DisplayFor(modelItem => item.ConditionName)
                    </td>
                    <td></td>
                </tr>
            }
            <tr id="BCDropDownRow">
                <td>
                    <button id="AddBuyCondition" type="button" class="btn btn-default btn-xs">
                        <span class="glyphicon glyphicon-plus"></span>
                    </button>
                    &nbsp;
                    @Html.DropDownListFor(x => x.BuyConditionList, new SelectList(Model.BuyConditionList, "ConditionID", "ConditionName"))
                </td>
                <td></td>
            </tr>
        </table>
    </div>
    <div>
        &nbsp;
    </div>
    <div class="col-md-10">
        <table class="table" id="SellConditionsTable">
            <tr>
                <th>
                    @Html.DisplayName("Sell Conditions")
                </th>
                <th></th>
            </tr>
            @foreach (var item in Model.SellConditions)
            {
                <tr>
                    <td>
                        @Html.HiddenFor(modelItem => item.ConditionID)
                        @Html.DisplayFor(modelItem => item.ConditionName)
                    </td>
                    <td></td>
                </tr>
            }
            <tr id="SCDropDownRow">
                <td>
                    <button id="AddSellCondition" type="button" class="btn btn-default btn-xs">
                        <span class="glyphicon glyphicon-plus"></span>
                    </button> &nbsp;
                    @Html.DropDownListFor(x => x.SellConditionList, new SelectList(Model.SellConditionList, "ConditionID", "ConditionName"))
                </td>
                <td></td>
            </tr>
        </table>
    </div>
    <div class="form-group">
        <div class="col-md-offset-9 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
}

模型中的HTML表数据没有更新

BuyConditionsSellConditions为空的原因是以下代码

@Html.HiddenFor(modelItem => item.ConditionID)

这将显示所有

<input type="hidden" id="item_ConditionID" name="item.ConditionID" />

由于命名错误,无法在控制器动作Create中解决。

应该是

@Html.HiddenFor(x => x.SellConditions[index].ConditionID)
这将使控件呈现为(如果index为0)
<input type="hidden" id="SellConditions_0__ConditionID" name="SellConditions[0].ConditionID" />
因此,foreach块应该如下所示
@foreach (int index = 0; index < Model.SellConditions.Count; index++)
   {
        <tr>
            <td>
                @Html.HiddenFor(x => x.SellConditions[index].ConditionID)
                @Html.DisplayFor(x => x.SellConditions[index].ConditionName)
            </td>
            <td></td>
        </tr>
   }

同样的规则也适用于BuyConditions