mvc3 Problem passing data from View to Controller - c#

I am using mvcContrib to generate a grid to allow users to filter data by keying in search data. There are several partial views that are rendered in my Index View:
Here is the partial view that handles the searching:
#model CRMNPS.Models.PagedViewModel<CRMNPS.Models.NPSProcessed>
#using (Html.BeginForm("Index", "Home", FormMethod.Get))
{
<label>
Model Number: #Html.TextBox("searchWord" )
<br /><br />From Date: #Html.EditorFor(m => m.FromDate)
</label>
<label>
<Br /><br />To Date: #Html.EditorFor(m => m.ToDate)
</label>
<label>
<br /><br /> <input class="button" value="Search" type="submit" />
<br />
</label>
}
Here is my Index view:
#model PagedViewModel <CRMNPS.Models.NPSProcessed>
#{
ViewBag.Title = "CRM Processed List";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Processed List</h2>
#{Html.RenderPartial("SearchBox");}
#{Html.RenderPartial("Pager", Model.PagedList);}
#Html.Grid(Model.PagedList).AutoGenerateColumns().Columns(column =>{
column.For(x => Html.ActionQueryLink(x.ModelNumber, "Edit", new { id = x.Id
})).Named("Id").InsertAt(1);
}).Sort(Model.GridSortOptions).Attributes(#class => "grid-style")
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { FromDate = Model.FromDate, ToDate = Model.ToDate, SearchWord = Model.SearchWord }))
{
<p>
<input class="button" value="Export to Excel" type="submit" />
</p>
}
At the bottom of the Index View I have another submit within the Html.BeginForm with a Formmethod.Post.
The Index ActionResult that calls this view passes a viewmodel with the search criteria and a IQueryable object that the mvcContrib uses.
When the user presses the Export to Excel push button I would like to pass the selected values back to the Index actionresult HttpPost controller. (FromDate, ToDate and SearchWord)
The FromDate, ToDate and SearchWord values always come back null.
I am fairly new to MVC so any constructive comments are welcome.
Thanks
Joe

Since they are not in the form that you are posting - (Export to Excel is in a separate form).
The inputs
FromDate, ToDate and SearchWord
Are in the first form (in the partial view). So those values don't show up in the controller (since they are not part of the http post).
If you want to see all these values being passed back to the controller, they should be under one
Html.BeginForm

One way is to put'em all in the same form as MoXplod suggested or you can use some javascript to send search values as query string by hooking the submit event of second form like
$('#excel-form').live('click', function(){
var action = this.action;
var searchString = $('#SearchWord').val();
var toDateString = $('#ToDate').val();
var fromDateString = $('#FromDate').val();
if(action.indexOf('?')<0)
{
action = action+"?SearchWord="+searchString;
}
else
{
action = action+"&SearchWord="+searchString;
}
action = action + "&ToDate="+toDateString + "&FromDate=" + fromDateString;
$(this).attr('action', action);
return true;
});
it will put these values in querystring and make them available in action method. Alternatively, you can use ajax to post these values to controller rather than full regular post back.

Related

Assign a value to ViewBag varible inside the <input> tag

I have cshtml view page with paginations
here view of that page
Once I click any of below number (which is 1 to 10) I should be able to pass that number to POST method of that form
this is the relevant cshtml code snippet to that pagination
#if (Model.Pager.EndPage > 1)
{
<ul class="pagination">
#for (var page = Model.Pager.StartPage; page <= Model.Pager.EndPage; page++)
{
<li class="#(page == Model.Pager.CurrentPage ? "active" : "")">
<input type="submit" value=#page class="btn btn-default" ViewBag.pagenumber=#page/>
</li>
}
</ul>
}
then I try to pass that value like this
#using (Html.BeginForm("method_name", "controller", new { pagenumber = ViewBag.pagenumber} , FormMethod.Post))
{
but pagenumber getting null each time, in this way
EDIT:
[HttpGet]
public ActionResult method_name(int? page,string Product_ID)
{
........
}
[HttpPost]
[ValidateInput(false)]
public ActionResult method_name(AddNewProduct product, string pagenumber)
{
.....
return RedirectToAction("method_name", "controller", new { page = pagenumber});
}
You can do it like
Add class pagerBtn in the pager buttons
<input type="submit" value=#page class="btn btn-default pagerBtn"/>
Make a hidden input field in the form
#using (Html.BeginForm("method_name", "controller" , FormMethod.Post))
{
//Make sure the action parameter same as name of input field
<input type="hidden" name="pagenumber" id="hiddenInput" />
}
Write jquery to get page number
$(document).ready(function(){
$(".pagerBtn").on("click",function(e){
var pageClicked = e.target.value;//Get clicked button page number from attribute value.
$("#hiddenInput").val(pageClicked);//insert clicked value in hidden filed input with name same as controller parameter taking this value.
});
});
in ViewBag value becomes null when redirection occurs.
try to use TempData
<input type="submit" value=#page class="btn btn-default" TempData["pagenumber"]=#page/>
#using (Html.BeginForm("method_name", "controller", new { pagenumber = TempData["pagenumber"]} , FormMethod.Post))
Assign a name tag to each input field. In that way you could retrieve the values in the controller using a FormCollection and don't need the new { pagenumber = ViewBag.pagenumber}:
[HttpPost]
[ValidateInput(false)]
public ActionResult method_name(FormCollection collection){
var inputValue = collection.GetValue("name").AttemptedValue;
return RedirectToAction("method_name", "controller", inputValue);
}

Partial within a partial null exception

I have a MVC form which is more complex than all of my others, utilising three models.
Company -> Base_IP -> RequestedIP which goes ViewModel -> Partial1 -> Partial2
I am using BeginCollectionItem for this has each model has a property list of the the model down from it. IE - Company has a property called baseIps, the BaseIp class has a property called requestedIps, it is requestedIps that is coming back null, the count is there on page render, but is not on submit.
When submitting to the database in the post Create(), I get nulls on the 'requestedIps' property, why is this?
I've added the offending controller and partial code samples below, not the entire thing as it's massive/redundant - any questions, please let me know.
Controller - [HttpGet]Create()
public ActionResult Create()
{
var cmp = new Company
{
contacts = new List<Contact>
{
new Contact { email = "", name = "", telephone = "" }
}, pa_ipv4s = new List<Pa_Ipv4>
{
new Pa_Ipv4
{
ipType = "Pa_IPv4", registedAddress = false, existingNotes = "", numberOfAddresses = 0, returnedAddressSpace = false, additionalInformation = "",
requestedIps = new List<IpAllocation>
{
new IpAllocation { allocationType = "Requested", cidr = "", mask = "", subnet = "" }
}
}
}
};
return View(cmp);
}
Controller - [HttpPost]Create()
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Company cmp) // does not contain properties assigned/added to in view render
{
if (ModelState.IsValid)
{
db.companys.Add(cmp);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(cmp);
}
Create View
#model Company
#using (Html.BeginForm())
{
<div id="editorRowsAsn">
#foreach (var ip in Model.pa_ipv4s)
{
#Html.Partial("Pa_IPv4View", ip)
}
</div>
<br />
<div data-role="main" class="ui-content">
<div data-role="controlgroup" data-type="horizontal">
<input type="submit" class="ui-btn" value="Create" />
</div>
</div>
}
Pa_Ipv4 View
#model Pa_Ipv4
#using (Html.BeginCollectionItem("pa_ipv4s"))
{
#Html.AntiForgeryToken()
<div id="editorRowsRIpM">
#foreach (var item in Model.requestedIps)
{
#Html.Partial("RequestedIpView", item)
}
</div>
#Html.ActionLink("Add", "RequestedManager", null, new { id = "addItemRIpM", #class = "button" }
}
RequestedIpView
#model IpAllocation
<div class="editorRow">
#using (Html.BeginCollectionItem("requestedIps"))
{
<div class="ui-grid-c ui-responsive">
<div class="ui-block-a">
<span>
#Html.TextBoxFor(m => m.subnet, new { #class = "checkFiller" })
</span>
</div>
<div class="ui-block-b">
<span>
#Html.TextBoxFor(m => m.cidr, new { #class = "checkFiller" })
</span>
</div>
<div class="ui-block-c">
<span>
#Html.TextBoxFor(m => m.mask, new { #class = "checkFiller" })
<span class="dltBtn">
<img src="~/Images/DeleteRed.png" style="width: 15px; height: 15px;" />
</span>
</span>
</div>
</div>
}
</div>
You first (outer) partial will be generating correct name attributes that relate to your model (your code does not show any controls in the Pa_Ipv4.cshtml view but I assume you do have some), for example
<input name="pa_ipv4s[xxx-xxx].someProperty ...>
however the inner partial will not because #using (Html.BeginCollectionItem("requestedIps")) will generate
<input name="requestedIps[xxx-xxx].subnet ...>
<input name="requestedIps[xxx-xxx].cidr ...>
where they should be
<input name="pa_ipv4s[xxx-xxx].requestedIps[yyy-yyy].subnet ...>
<input name="pa_ipv4s[xxx-xxx].requestedIps[yyy-yyy].cidr ...>
Normally you can pass the prefix to the partial using additional view data (refer this answer for an example), but unfortunately, you do not have access to the Guid generated by the BeginCollectionItem helper so its not possible to correctly prefix the name attribute.
The articles here and here discuss creating your own helper for handling nested collections.
Other options include using nested for loops and including hidden inputs for the collection indexer which will allow you to delete items from the collection and still be able to bind to your model when you submit the form.
for (int i = 0; i < Model.pa_ipv4s.Count; i++)
{
for(int j = 0; j < Model.pa_ipv4s[i].requestedIps.Count; j++)
{
var name = String.Format("pa_ipv4s[{0}].requestedIps.Index", i);
#Html.TextBoxFor(m => m.pa_ipv4s[i].requestedIps[j].subnet)
#Html.TextBoxFor(m => m.pa_ipv4s[i].requestedIps[j].cidr)
...
<input type="hidden" name="#name" value="#j" />
}
}
However if you also need to dynamically add new items you would need to use javascript to generate the html (refer examples here and here)
If you look at your final markup you will probably have inputs with names like
input name="subnet"
input name="cidr"
input name="mask"
This is how the form collection will appear when the form gets posted. Unfortunately this will not bind to your Company model.
Your fields will need to look like this instead
input name="Company.pa_ipv4s[0].subnet"
input name="Company.pa_ipv4s[0].cidr"
input name="Company.pa_ipv4s[0].mask"
input name="Company.pa_ipv4s[1].subnet"
input name="Company.pa_ipv4s[1].cidr"
input name="Company.pa_ipv4s[1].mask"
There are multiple ways to "fix" this, and each has its own caveats.
One approach is to setup "Editor" views (typically in ~/Views/Shared/EditorTemplates/ClassName.cshtml), and then use #Html.EditorFor(x => x.SomeEnumerable). This will not work well in a scenario in which you need to be able to delete arbitrary items from the middle of a collection; although you can still handle those cases by means of an extra property like ItemIsDeleted that you set (e.g. via javascript).
Setting up a complete example here would be lengthy, but you can also reference this tutorial: http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/
As a start, you would create a simple template like
~/Views/Share/EditorTemplates/Contact.cshtml:
#model yournamespace.Contact
<div>
#Html.LabelFor(c => c.Name)
#Html.TextBoxFor(c => c.Name)
#Html.ValidationMessageFor(c => c.Name)
</div>
<div>
#Html.LabelFor(c => c.Email)
#Html.TextBoxFor(c => c.Email)
#Html.ValidationMessageFor(c => c.Email)
</div>
... other simple non-enumerable properties of `Contact` ...
#Html.EditorFor(c => c.pa_ipv4s) #* uses ~/Views/Shared/EditorTemplates/pa_ipv4s.cshtml *#
In your view to edit/create a Company, you would invoke this as
#Html.EditorFor(company => company.Contacts)
(Just like the EditorTemplate for Company invokes the EditorFor pa_ipv4s.)
When you use EditorFor in this way, MVC will handle the indexing automatically for you. (How you handle adding a new contact/IPv4/etc. here is a little more advanced, but this should get you started.)
MVCContrib also has some helper methods you can use for this, but it's not particularly simple from what I recall, and may tie you down to a particular MVC version.

How to pass textbox from view to it's own controller again and again?

What I'm trying to do is to pass the value of the textbox of this certain view to it's own controller.
The view has only 1 textbox, the textbox for id , then the controller has linq query that search the database that match that id.
So when I run my program , first it would show empty gridview and empty textbox. What I want to do is when I input a text in the textbox and press submit , it would call it's own controller and pass the value of the textbox that contains the id so the linq query will have something to use so it can display a search result.
Did I make sense ? :0 sorry I'm a just a beginner.
You can get that Text box value using form Collection, Foe Ex,your view may look like this
#model MvcMovie.Models.Movie
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm("controllerName","ActionName",FormMethod.Post))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Movie</legend>
<div class="editor-label">
#Html.TextBox("Name",null,New {id="Name"})
</div>
<div class="editor-label">
<input type="submit" value="save" />
</div>
</fieldset>
}
In controller,
[HttpPost]
Public ActionResult MethodName(FormCollection form)
{
string name = form["Name"];
// name contains your textbox value
}
database acces ?
query;
OleDbDataReader readername;
OleDbCommand commandname = new OleDbCommand("Select textBox1.Text=#"+textBox1.Text+" from tablename",connectionname);
connectionname.Open();
readername = commandname.ExecuteReader();
while (readername.Read()) //the result
{
label1.Text = readername[textbox1.Text].ToString();
}
connectionname.Close();

How to Pass Model from view to Controller

I'm having following view page,
#using (Html.BeginForm())
{
<fieldset class="fs">
#foreach (var item in Model.lstTravelReadyEntities)
{
<label class="Detail1"><b>Associate Id : </b>#item.Var_AssoId </label>
<label class="Detail1"><b>Vertical :</b>#item.Var_Vertical</label>
<label class="Detail1"><b>Visa ValidFrom :</b>#item.Dt_VisaValidFrom </label><br /><br />
<label class="Detail2"><b>Associate Name :</b>#item.Var_AssociateName</label>
<label class="Detail2"><b>Account Name :</b>#item.Var_AccountName</label>
<label class="Detail2"><b>Visa ValidDate :</b>#item.Dt_VisaValidTill</label><br /><br />
<label class="Detail3"><b>Grade HR :</b>#item.Var_Grade</label>
<label class="Detail3"><b>Project Name :</b>#item.Var_Project_Desc</label><br />
}
<h2> Response Details</h2><br />
Supervisor Response :<input type="radio" class="radi"
name="radio" value="yes" onclick="javascript:Getfunc(this.value);">Yes
<input type="radio"
name="radio" value="no"
onclick="javascript:Getfunc(this.value)">No
<div id="es"></div>
<input type="submit" id="insert" value="Submit"
name="Submit" onclick="javascript:InsertDetails(item);"/>
</fieldset>
}
I want pass all the values of this view page to the controller as parameters for inserting these values into the new table.How can i Achieve this?
Use #Html helpers for your controls.
Have a look at this blog entry from Scott Gu. It's about MVC2 but still applies to MVC4.
For a more concrete example, have a look at this question regarding #Html.RadioButtonFor().
Also, I would recommend hooking your events using jquery instead of inline onclick= html attributes.
<script type="text/javascript">
$("form radio").click(function(){ // or whatever selector you need
Getfunc($(this)[0].value);
});
</script>
Finaly, you will need to make sure your #Html.BeginForm posts to an [HttpPost]-decorated action on your controller that takes your Model as parameter.
What is the Problem in Existing code ?
There is no Input Type Text Control in the form and that's the reason information is not being sent to server. TextBox like controls forwards the data for sending the information to Controller Action Method.
Corrective Action
Let's say TextBox is not Required in you case. Then, you can place Hidden Fields for those View Model Properties which are required to be sent to Controller Post Action method.
Example
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post))
{
<fieldset class="fs">
#foreach (var item in Model.lstTravelReadyEntities)
{
<label class="Detail1">
<b>Associate Id : </b>#item.Var_AssoId
</label>
#Html.HiddenFor(i=> item.Var_AssoId) //Added Hidden Field to send this to server
<label class="Detail1">
<b>Vertical :</b>#item.Var_Vertical</label>
#Html.HiddenFor(i => item.Var_Vertical) //When post this Hidden Field will send
<label class="Detail1">
<b>Visa ValidFrom :</b>#item.Dt_VisaValidFrom
</label>
#Html.HiddenFor(i => item.Dt_VisaValidFrom)
<br />
}
<h2>
Response Details</h2>
<br />
</fieldset>
}
For explaining point of view, I excluded some of the controls. Now, You can add Hidden Fields for those Properties which are required to be sent to Action Method.
Also you should use View Models instead of Passing Individual parameter to Action Method.
Hope this will help you.
Hi try like this,
View
#using (Html.BeginForm("SaveAudit", "Controller", FormMethod.Post)
{
}
Controller
[HttpPost]
public ActionResult SaveAudit(AuditModel model, FormCollection collection)
{
}

Get html items from view to control

Still kind of new to MVC, so please bear with me. I'm trying to grab some dynamically generated HTML. In this case, list items in my notifyList. I plan on looping through each one in the controller and adding them as database entries. Any help is appreciated, thanks.
View
#model _BaseViewModel
// The form it's within...
#using (Html.BeginForm("Create", "Leaf", FormMethod.Post, new { id = "createForm" }))
<div class="editor-label bottom-area bottom-header">
Notification List:
</div>
<div class="editor-field bottom-area">
<ul id="notifyList"></ul>
</div>
Controller:
[HttpPost]
public ActionResult Create(_BaseViewModel model)
{
// Some loop here
// get html here
db.UserItems.AddObject(model.user);
db.SaveChanges();
//
return RedirectToAction("Index");
}
As far as I understood, you use jQuery to fetch <li/> elements into notifyList. What you need to do here is to generate a hidden input as well. Sample:
$("#btnAppend").click(function() {
for(var i = 0; i < 4; i++) {
var _val = "Foo " + i;
var $li = $("<li/>").text(_val);
var $hidden = #("<input/>").
attr("type", "hidden")
attr("name", "foo").
val(_val);
$hidden.appendTo($li);
$li.appendTo("#notifyList");
}
});
This code will generate following output inside your DOM:
<ul id="notifyList">
<li>Foo 0<input type="hidden" value="Foo 0" name="foo" /></li>
<li>Foo 1<input type="hidden" value="Foo 1" name="foo" /></li>
<li>Foo 2<input type="hidden" value="Foo 2" name="foo" /></li>
<li>Foo 3<input type="hidden" value="Foo 3" name="foo" /></li>
</ul>
When you make a http form post, you can grab the values by the below controller action implementation:
public ActionResult Index(string[] foo) {
foreach(var item in foo) {
//Work with each individual item
}
//continue your code
}
it doesn't work this way. html only exists in the view. the controller has no concept of html (not should it). data sent to the controller comes in 1 of types (GET, POST). there are others, but these are the main to.
get is typically associated with the querystring www.domain.com/mypage.aspx?key=value
where post is the input values from form
<form action="mypage.aspx" method="post">
<input name="key" value="value"/>
<input type="submit" value="click me"/>
</form>
So adding items to a html list won't provide any meaning to the controller. javascript and ajax provide more options on how the data gets sent to the server, but the data is sent, not the markup. and the data is sent as key value pairs.

Categories

Resources