c# - How do I manually pass data from view to controller? -
i have view form can edited. view rather complicated. form contract. contract name can edited @ top. contract has many ads, , details each of ads can edited. length of form depends on how many ads contract has. have loop in view displays form fields each ad.
furthermore, there fields in model used determine of ad details, shouldn't saved database (yet must appear as, say, dropdowns in view).
also, there model fields don't need appear in view needed in post controller method in order save database (i'm saving manually), must go through view somehow , passed controller. here's model:
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 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 }
the fields have comment of "save" after them should saved database. ones "appear" must in view not needed in post controller method. ones "needed" needed in post controller method not view.
by way, these model classes don't map one-to-one database tables, they're made several different tables.
as far know don't see how can model binding work this. model that's passed controller has null value ads field of modcontract, example. know how can manually pass want view controller without relying on model binding.
i know might use @html.hiddenfor ids needed in post method not view, reason when tried contract_id , _name, didn't work.
<li data-role="fieldcontain"> <label>contract name</label> @html.hiddenfor(m => m.contract_id) @html.editorfor(m => m.contract_name) </li>
the contract_id returned in post method 0.
let me know if question sounds stupid because impossible or because i'm overcomplicating things, i'm pretty new this.
thanks in advance!
edit
here's view. can't indent right it's readable.
@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"] 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 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 , editions select $(".hid select").closest('.ui-select').hide(); } // called when edit button product 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 default; happens twice; why? } // called when magazine selected function prodchange() { // ajax var url = '@url.action("getadvprodlist", "contract")' + '?prod_id=' + this.value; $.getjson(url, null, function (list) { // adv list dropdown $("#" + nu + "-drdn1 select").empty(); // remove old stuff $("#" + nu + "-drdn1 select").closest('.ui-select').show(); // show dropdown var arr = list.advlist; // array object $.each(arr, function (ind, val) { // add each item in list option of select $("#" + nu + "-drdn1 select").append('<option value=' + val.value + '>' + val.text + '</option>'); }); $("#" + nu + "-drdn1 select").selectmenu('refresh', true); // refresh menu // ed list $("#" + nu + "-drdn2 select").empty(); // remove old stuff $("#" + nu + "-drdn2 select").closest('.ui-select').show(); // show list var lis = list.edlist; // array object $.each(lis, function (ind, val) { // add each item list $("#" + nu + "-drdn2 select").append('<option value=' + val.value + '>' + val.text + '</option>'); }); $("#" + nu + "-drdn2 select").selectmenu('refresh', true); // refresh menu }); }
you have quite few issues there , understandably if have complex form. let me try , summarize problem give best possible solution.
the breakdown
there fields in model...(that) shouldn't saved database (yet must appear as, say, dropdowns in view)
you put these fields in model , treat them read-only. i'll show later how.
there model fields don't need appear in view needed in post controller method in order save database (i'm saving manually)
you don't need that. passing unnecessary data around , introducing on posting. in addition, not allowing users edit them , yet pass client, receive it, , save database.
it exposes security hole in system. example, passing product_name
view, don't want edited, save table. can hack value , end product_name
never expected.
the fields have comment of "save" after them should saved database.
accept these inputs on form. code shown later.
the ones "appear" must in view not needed in post controller method.
as i've mentioned these should read-only fields on viewmodel, code shown later.
the ones "needed" needed in post controller method not view.
you don't need pass around nor query right away. later database when saving-time comes. pseudo-code shown later.
the proposed solution
at point assume understand mentioned above answering points of question. here relevant codes explanation.
public class contractviewmodel { // start:read-only fields. // these fields used 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;} } // use class capture "all 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;} // string? public string name {get;set;} }
you create "master" viewmodel called contractviewmodel
, use on view (of course can have name want). contains fields show information , "input" field capture inputs. flatten representation of entities. "input" field, called inputmodel
flatten representation of entities. inputs viewmodel dispersed , persisted properly.
building model
// method creating contract public actionresult create() { // implement ff methods, whatever method you're using orm, plain ado, etc. var product = getentityfromyourdb(); // may eagerly load (orm) or query separately, it's // adoption simple entity structure: id, name ienumerable<adoption> adoptions = getadoptionsfromdb(); // map entity model // guessing here "product" has following fields. // replace accordingly based on 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(); }; // @ point have need // (1) field can show (and not save) // (2) list of fields can use on drop-down // (3) input fields, ones post return view(model); }
consuming model on view
the example given here solve problem:
as far know don't see how can model binding work this. model that's passed controller has null value ads field of modcontract
never use foreach
on collection razor engine cannot write in way can save back. reason elements written have same name , cannot binded (or bound, think right word in english - binded in programming :). use for-loop
, see in following code.
@model contractviewmodel <h2>modify contract</h2> <p>@model.product_name</p> <p>@model.adv_product</p> @html.hiddenfor(m=>m.contract.contract_id) // reference id 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) // reference id saving @html.textboxfor(m=>m.contract.ads[i].name) @html.dropdownlistfor(m=>m.contract.ads[i].print_ad_option_id, m.printadoptions) }
finally, saving need
in example given below notice used bind
attribute. tells controller bind , our "input" model , inputmodel
. there no need post other values won't need saving or querying, etc. take note if need field, id
(e.g. product id) later on use query product product table, because need save name modads
table include in inputmodel
. have, inputmodel.productid
.
[httppost] public actionresult create([bind(prefix = "contract")]inputmodel model) { // map values flatten model entities // single entity or complex 1 // i'm sure can determine how // example: var modcontract = getcontractfromdb(model.contract_id); modcontract.contract_name = model.contract_name; // rest of mapping here }
conclusion
that closest example can give based on model , trying do. if follow along example, i'm sure solve problem.
Comments
Post a Comment