簡體   English   中英

如何手動將數據從視圖傳遞到控制器?

[英]How do I manually pass data from view to controller?

我有一個可以編輯的表單視圖。 該視圖相當復雜。 該表格是一份合同。 合同名稱可以在頂部進行編輯。 合同中有很多廣告,並且每個廣告的詳細信息都可以修改。 表格的長度取決於合同中有多少個廣告。 我在視圖中有一個for循環,可顯示每個廣告的所有表單字段。

此外,模型中的某些字段用於確定某些廣告詳細信息,但不應將其保存到數據庫中(但它們必須在視圖中顯示為下拉列表)。

另外,有些模型字段不需要顯示在視圖中,但在POST控制器方法中是必需的,以便正確保存數據庫(我是手動保存),因此它們必須以某種方式遍歷視圖並被傳遞回控制器。 這是我的模型:

public class ModContract
{
    public int contract_id; // pk; needed
    public string contract_name { get; set; } // save
    public List<ModAds> ads { get; set; }
}

public class ModAds
{
    public int contr_ad_id; // pk; needed

    public string name { get; set; } // save

    public string print_product_id { get; set; } // used for product_name
    public string product_name { get; set; } // appear

    public string print_ad_option_id { get; set; } // save
    public string adv_product { get; set; } // appear

    public List<string> editions { get; set; } // save


    public double freq_disc { get; set; } // save
    public double other_dis_dol { get; set; } // save
    public double? other_dis_per { get; set; } // save
    public string non_cash_note { get; set; } // save
    public double non_cash_cons { get; set; } // save
}

注釋為“保存”的字段應保存到數據庫中。 帶有“出現”的內容必須在視圖中,但POST控制器方法中不需要。 POST控制器方法中需要“需要”的內容,而視圖則不需要。

順便說一下,這些模型類不會與數據庫表一對一地映射,它們是由幾個不同的表組成的。

據我所知,我還看不到如何獲得模型綁定來使用它。 例如,傳遞回控制器的模型的ModContract的ads字段的值為空。 我想知道如何在不依賴模型綁定的情況下,將視圖中所需的內容手動傳遞回控制器。

我知道我可以使用@ Html.HiddenFor作為POST方法中所需的ID,但不能使用視圖,但是由於某種原因,當我使用contract_id和_name嘗試此操作時,它沒有用。

<li data-role="fieldcontain">
        <label>Contract Name</label>
        @Html.HiddenFor(m => m.contract_id)
        @Html.EditorFor(m => m.contract_name)
</li>

在POST方法中返回的contract_id為0。

讓我知道如果我的問題聽起來很愚蠢,是因為這是不可能的,或者是因為我過於復雜,那么我對這一切還是很陌生的。

提前致謝!

編輯

這是視圖。 我無法使其縮進正確,但希望它是可讀的。

@model oulookmediaweb.Models.ModContract

@{
    ViewBag.Title = "ModifyContract";
}

@{
    var num = 1;
}

<h2>Modify Contract</h2>

@using (Html.BeginForm("ModifyContract", "Contract", FormMethod.Post, htmlAttributes: new {      data_ajax = "false" }))
{
    @Html.ValidationSummary();
    <ul data-role="listview" data-inset="true">

        <li data-role="fieldcontain">
            <label>Contract Name</label>
            @Html.HiddenFor(m => m.contract_id)
            @Html.EditorFor(m => m.contract_name)
        </li>

    </ul>

    <div>
    @foreach (var ad in Model.ads)
    {
        <div id="@num">
            <ul data-role="listview" data-inset="true">
                <li data-role="list-divider">@ad.name</li>
                <li data-role="fieldcontain">
                    <label><strong>Product Name</strong></label>
                    <div>@ad.product_name</div>
                    <div id="@num-drdn0" hidden="true">@Html.DropDownListFor(m => ad.print_product_id, ViewData["products_list"] as SelectList)</div>
                    <input id="@num-editbutton" type="button" onclick="edit(@num)" value="Edit" />
                </li>

                <li data-role="fieldcontain">
                    <label><strong>Advertising Product</strong></label>
                    <div>@ad.adv_product</div>
                    <div id="@num-drdn1" class="hid">
                        <select></select>
                    </div>
                </li>

                <li data-role="fieldcontain">
                    <label><strong>Editions to run in:</strong></label>
                    @foreach (var ed in ad.editions)
                    {
                        <div>@ed</div>
                    }
                    <div id="@num-drdn2" class="hid">
                        <select multiple="multiple" data-native-menu="false"></select>
                    </div>
                </li>

                <li data-role="fieldcontain">
                    <label><strong>Frequency Discount (%)</strong></label>
                    <div>@Html.EditorFor(m => ad.freq_disc)</div>
                </li>

                <li data-role="fieldcontain">
                    <label><strong>Other Discount ($)</strong></label>
                    <div>@Html.EditorFor(m => ad.other_dis_dol)</div>
                </li>

                <li data-role="fieldcontain">
                    <label><strong>Other Discount (%)</strong></label>
                    <div>@Html.EditorFor(m => ad.other_dis_per)</div>
                </li>

                <li data-role="fieldcontain">
                    <label><strong>Non Cash Note</strong></label>
                    <div>@Html.EditorFor(m => ad.non_cash_note)</div>
                </li>

                <li data-role="fieldcontain">
                    <label><strong>Non Cash Consideration</strong></label>
                    <div>@Html.EditorFor(m => ad.non_cash_cons)</div>
                </li>

            </ul>
            @{num++;}
        </div>
    }
</div>

<ul data-role="listview" data-inset="true">
    <li data-role="fieldcontain">
        <input type="submit" data-theme="e" value="Submit" />
    </li>
</ul>

}

<script type="text/javascript">
var nu;
window.onload = function () {
    // hide adv prods and editions select for now
    $(".hid select").closest('.ui-select').hide();
}

// called when the edit button for product is clicked
function edit(num) {
    nu = num;
    $("#" + nu + "-drdn0").show(); // show dropdown
    $("#" + nu + "-editbutton").closest('.ui-btn').hide(); // hide edit button; '.ui-btn'? WTF?

    // remove current product selection div
    // remove adv product selection div
    // remove editions div


    $("#" + nu + "-drdn0 select").change(prodChange); // on select change
    $("#" + nu + "-drdn0 select").trigger("change");  // trigger for default; happens twice; WHY?
}

// called when a magazine is selected
function prodChange() {
    // ajax
    var url = '@Url.Action("GetAdvProdList", "Contract")' + '?prod_id=' + this.value;

    $.getJSON(url, null, function (list) {
        // for adv list dropdown
        $("#" + nu + "-drdn1 select").empty(); // remove old stuff
        $("#" + nu + "-drdn1 select").closest('.ui-select').show(); // show dropdown
        var arr = list.advlist; // get the array from object

        $.each(arr, function (ind, val) {
            // add each item in list as an option of select
            $("#" + nu + "-drdn1 select").append('<option value=' + val.Value + '>' + val.Text + '</option>');
        });
        $("#" + nu + "-drdn1 select").selectmenu('refresh', true); // refresh menu

        // for ed list
        $("#" + nu + "-drdn2 select").empty(); // remove old stuff
        $("#" + nu + "-drdn2 select").closest('.ui-select').show(); // show list
        var lis = list.edlist; // get the array from object

        $.each(lis, function (ind, val) {
            // add each item to list
            $("#" + nu + "-drdn2 select").append('<option value=' + val.Value + '>' + val.Text + '</option>');
        });
        $("#" + nu + "-drdn2 select").selectmenu('refresh', true); // refresh menu
    });
}

您那里有很多問題,如果表單很復雜,這是可以理解的。 因此,讓我嘗試總結您的問題,以提供最佳解決方案。

細目分類

模型中有一些字段...本身不應該保存到數據庫中(但是它們必須在視圖中顯示為下拉列表)

您將這些字段放入模型中,並將其視為只讀 稍后再說明。

有一些模型字段不需要顯示在視圖中,但在POST控制器方法中是必需的,以便正確保存數據庫(我正在手動保存)

您不需要這樣做。 您正在傳遞不必要的數據,並且正在引入過帳。 此外,您不允許用戶對其進行編輯,但是您將其傳遞給客戶端,接收它並將其保存回數據庫。

它甚至暴露了系統中的安全漏洞。 例如,您要將product_name傳遞給視圖,不希望對其進行編輯,但是將其保存到另一個表中。 有人可以輕松破解該價值,而您最終可能會獲得一個您從未想到的product_name

注釋為“保存”的字段應保存到數據庫中。

接受這些作為您表單上的輸入。 代碼將在稍后顯示。

帶有“出現”的內容必須在視圖中,但POST控制器方法中不需要。

正如我已經提到的,這些應該是您的viewmodel上的只讀字段,稍后將顯示代碼。

POST控制器方法中需要“需要”的內容,而視圖則不需要。

您無需傳遞此信息,也無需立即對其進行查詢。 節省時間以后,可以從數據庫中獲取它。 偽代碼稍后顯示。

擬議的解決方案

在這一點上,我認為您已經通過回答問題的某些點來理解了我上面提到的內容。 以下是與這些說明相關的代碼。

public class ContractViewModel {
    // start:read-only fields. 
    // These are the fields that will be used as read-only
    public string product_name { get; set; }
    public string adv_product { get; set; }
    public IEnumerable<SelectListItem> PrintAdOptions { get; set; }
    // end:read-only fields.
    public InputModel Contract {get;set;}    
}
// you use this class to capture "all your inputs"
public class InputModel {
    public int contract_id {get;set;}
    public string contract_name { get; set; }
    public IEnumerable<InputSubModel> ads {get;set;}
}    
public class InputSubModel {
    public int contr_ad_id {get;set;}
    public string print_ad_option_id {get;set;} // is this really a string?
    public string name {get;set;}
}

您將創建一個名為ContractViewModel的“主”視圖模型,並在視圖上使用它(當然,您可以使用任何想要的名稱)。 它包含用於顯示信息的字段和用於捕獲所有輸入的“輸入”字段。 它是所有實體的扁平表示。 稱為InputModel的“輸入”字段是所有實體的另一個扁平表示。 該視圖模型的輸入將被分散並正確保留。

建立模型

// method for creating a contract
public ActionResult Create() {
    // implement the ff methods, whatever method you're using ORM, plain ADO, etc.
    var product = getEntityFromYourDb();
    // you may eagerly load this (ORM) or query it separately, it's up to you
    // AdOption is a simple entity with structure: Id, Name
    IEnumerable<AdOption> adOptions = getAdOptionsFromDb();


    // map entity to model
    // I am guessing here that "product" has the following fields.
    // Just replace this accordingly based on you entities
    var model = new ContractViewModel{
        product_name = product.Name,
        adv_product = product.AdvProduct,
        PrintAdOptions = aOptions.Select(x=> 
             new SelectListItem{ Value = x.Id, Text = x.Name })     
        Contract  = getEntitiesFromDbAndMapToModel();
    };


    // at this point you have everything you need
    // (1) a field that you can just show (and not save)
    // (2) a list of fields that you can use on a drop-down
    // (3) input fields, the ONLY ones that you will POST
    return View(model);
}

在視圖上使用模型

此處給出的示例也解決了此問題:

據我所知,我還看不到如何獲得模型綁定來使用它。 傳回控制器的模型的ModContract廣告字段的值為空

切勿在集合上使用foreach ,因為剃刀引擎無法以可以將其保存回去的方式正確寫入它。 這樣做的原因是所寫的元素具有相同的名稱,並且不能正確地綁定(或綁定,我認為這是英語中的正確單詞-在編程中綁定:)。 始終使用for-loop ,請在以下代碼中查看。

@model ContractViewModel

<h2>Modify Contract</h2>
<p>@Model.product_name</p>
<p>@Model.adv_product</p>

@Html.HiddenFor(m=>m.Contract.contract_id) // your reference Id for saving
@Html.TextBoxFor(m=>m.Contract.contract_name)

@for(var i=0;i<Model.Contract.ads.Count();i++){
    @Html.HiddenFor(m=>m.Contract.ads[i].contr_ad_id) // your reference Id for saving
    @Html.TextBoxFor(m=>m.Contract.ads[i].name)
    @Html.DropdownListFor(m=>m.Contract.ads[i].print_ad_option_id, m.PrintAdOptions)
}

最后,節省您所需的一切

在下面給出的示例中,您將注意到我們使用了Bind屬性。 這告訴控制器僅綁定並獲取我們的“輸入”模型,即InputModel 無需回傳保存或查詢等不需要的所有其他值。因此請注意,如果您需要一個字段,請說出一個id (例如產品ID),以備日后使用從產品表中查詢產品, 因為您需要將其名稱保存到ModAds表中,然后將其包含在InputModel 這樣您將擁有InputModel.ProductId

[HttpPost]
public ActionResult Create([Bind(Prefix = "Contract")]InputModel model) {
    // map back the values from the flatten model into your entities
    // it could be a single entity or a complex one
    // but I'm sure you can easily determine how to do it
    // as an example:
    var modContract = getContractFromDb(model.contract_id);
    modContract.contract_name = model.contract_name;
    // do the rest of the mapping here
}

結論

這是我可以根據您的模型和您要執行的操作提供的最接近的示例。 如果您仔細遵循該示例,我相信它將解決您的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM