HTML表数据未在模型中更新

时间:2014-03-21 04:07:22

标签: c# jquery asp.net-mvc razor html-helper

我有一个ViewModel,其中包含两个条件列表 - BuyConditionsSellConditions - 加上一些属性 - Name等。列表使用视图中的表格显示。 jQuery允许对表进行操作 - 向表添加条件(从购买条件/销售条件DDL')并从表中删除条件。

我的问题是,当模型发布回控制器时,条件列表不会在模型中更新。

可能指向该问题的一点是,当模型返回到视图时(由于ModelStat.IsValid失败),Markets DDL中的数据仍然存在,但是买入和卖出条件中的数据DDL& #39; s没有。

我无法在网上找到一个例子来弄清楚我出错的地方。有人这么做过吗?

视图模型:

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")
}

1 个答案:

答案 0 :(得分:1)

由于以下代码,您BuyConditionsSellConditions为空的原因

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

这会将ALL渲染为

<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也是一样的规则。