Passing data from HttpGet to View to HttpPost in MVC [duplicate] - c#

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 4 years ago.
I ran out of options checking why my HttpPost parameter is always null.My Models, View and Controllers are below. In general, I have a model with all details of medication administered to patients (Model 1) below. Then, I created another model with one property which is a list of my first model (Model 2). Model 2 is being passed to the view as shown in the HttpGet action. My HttpPost action accepts a parameter which is a list of Model 1. This list is being passed in my view in the following line which is within the View:
using (Html.BeginForm("ClientChargeInput", "Home", new { #vm = Model.patients.ToList() }, FormMethod.Post, null))
Any feedback?
Model
public class ControlledSubstancesEntity
{
public string facility { get; set; }
public string program_x_rrg_value { get; set; }
public string PATID { get; set; }
//More properties
}
Model being passed to View
public class ControlledSubsViewModel
{
public List<ControlledSubstancesEntity> patients { get; set; }
}
HttpGet Controller Action
[HttpGet]
public ActionResult ClientChargeInput(DateTime adminDate, string Facility)
{
ControlledSubsViewModel vm = new ControlledSubsViewModel();
//Some logic that populates vm
return View(vm);
}
View
#model ControlledSubstancesChargeInput.Models.ControlledSubsViewModel
#{
ViewBag.Title = "ClientChargeInput";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#if (Model != null && Model.patients.Count() > 0)
{
using (Html.BeginForm("ClientChargeInput", "Home", new { #vm = Model.patients.ToList() }, FormMethod.Post, null))
{
<input type="submit" value="Charge Input" id="btnSubmit" class="btn btn-info btn-sm" onclick="PostCharge()" />
#*Fields are shown*#
#foreach (var p in Model.patients)
{
#Html.HiddenFor(model => p.facility)
#Html.HiddenFor(model => p.program_x_rrg_code)
#Html.HiddenFor(model => p.program_x_tx_setting_code)
}
}
}
else
{
#*#Html.Action("ShowReport");*#
}
HttpPost Controller Action
[HttpPost]
public ActionResult ClientChargeInput(List<ControlledSubstancesEntity> vm)
{
//On breakpoint vm is always null
}

You can try to use ControlledSubsViewModel instead of List<ControlledSubstancesEntity> class, then you can use vm.patients to do your logic.
because you use ControlledSubsViewModel in the razor view that pass the parameter format will like ControlledSubsViewModel.
[HttpPost]
public ActionResult ClientChargeInput(ControlledSubsViewModel vm)
{
//vm.patients use this property
}
Because Model.patients is a collection, you can use for loop set input tag (hidden or text) look like this.
#if (Model != null && Model.patients.Count() > 0)
{
using (Html.BeginForm("ClientChargeInput", "Home",FormMethod.Post))
{
<input type="submit" value="Charge Input" id="btnSubmit" class="btn btn-info btn-sm" onclick="PostCharge()" />
for (int i = 0; i < Model.patients.Count; i++)
{
#Html.TextBoxFor(m => Model.patients[i].PATID);
#Html.TextBoxFor(m => Model.patients[i].facility);
#Html.TextBoxFor(m => Model.patients[i].program_x_rrg_value);
}
}
}
else
{
#*#Html.Action("ShowReport");*#
}

You still need to create ControlledSubstancesEntity as hidden-fields even if you do not want to display them on the page.
#using (Html.BeginForm("Index", "Home", FormMethod.Post, null))
{
for (int i = 0; i < Model.patients.Count; i++)
{
#Html.HiddenFor(x => Model.patients[i].facility)
#Html.HiddenFor(x => Model.patients[i].program_x_rrg_value)
#Html.HiddenFor(x => Model.patients[i].PATID)
}
<input type="submit" value="Charge Input" id="btnSubmit"
class="btn btn-info btn-sm" onclick="PostCharge()" />
}
Then use ControlledSubsViewModel as a parameter in HttpPost action method.
(click on the image to view in full screen)

Related

Passing an Object to a controller using BeginForm()

I have a strongly typed view and I'm trying to pass the input from a textbox upon a button click to an action using BeginForm. My code keeps passing a null object to the action method in the controller. How do I pass the object to the controller via the form ?
#using (#Html.BeginForm("GetQueueInfoWorkorder","Home", FormMethod.Post, new { id = Model}))
{
#Html.TextBoxFor(x=> x.ID);
<input type="Submit" value ="Search" class="ui-button-icon-secondary"/>
}
Here is the actionmethod :
[HttpPost]
public ActionResult GetQueueInfoWorkorder(UserResponse id)
{
//Check queue complete
int woNumber = Convert.ToInt32(id);
tb_QueueCompleted completed = db.tb_QueueCompleted.SingleOrDefault(x => x.WorkOrderNumber == woNumber);
if (completed != null)
{
var u = new UserResponse { ID = completed.QueueId.ToString() };
GetLogInfoCompleted(u);
return View("GetLogInfo");
}
//check queue pending
return View();
}
I think you're fairly close, but make these changes & it should work as expected:
Model:
public class UserResponse
{
public int ID { get; set; }
}
View:
#model UserResponse
#using (Html.BeginForm("GetQueueInfoWorkorder", "Home"))
{
#Html.TextBoxFor(x => x.ID);
<input type="Submit" value ="Search" class="ui-button-icon-secondary"/>
}
Action method:
public ActionResult GetQueueInfoWorkorder(UserResponse model)
{
int woNumber = model.ID;
//...
}
if the #model of your view is UserResponse , then on submission of this page the model (UserResponse) will automatically get submitted to the controller. Where have you declared the #model for the view.

Keeping model after form submission

I have the following model used for a quiz, I am trying to submit a form and pass the existing model back to the Action as it has already been initialized in the Index action.
public class QuizModel
{
private List<string> _Responses;
public List<string> Responses
{
get
{
if (_Responses == null)
{
_Responses = new List<string>() { "Response A", "Response B", "Response C", "Response D" };
}
return _Responses;
}
}
public int? SelectedIndex { get; set; }
public string Question { get; set; }
}
With the following View:
<div class="title">Question</div>
<span id="question">#Model.Question</span>
#if (!Model.UserHasAnswered)
{
using (Html.BeginForm("Submit", "Quiz", FormMethod.Post))
{
for (int i = 0; i < Model.Responses.Count; i++)
{
<div class="reponse">#Html.RadioButtonFor(m => m.SelectedIndex, i)#Model.Responses[i]</div>
}
<input type="submit" value="This is the value" />
}
}
else
{
<div id="explanation">#Model.Explanation</div>
}
And Controller...
//
// GET: /Quiz/
public ActionResult Index()
{
QuizModel model = new QuizModel()
{
Question = "This is the question",
Explanation = "This is the explanation",
UserHasAnswered = false
};
return PartialView(model);
}
//
// POST: /Quiz/Submit
[HttpPost]
public ActionResult Submit(QuizModel model)
{
if (ModelState.IsValid)
{
int? selected = model.SelectedIndex;
model.UserHasAnswered = true;
}
return View("Index", model);
}
When the model comes to the Submit action it only contains the SelectedIndex and not Question or Explanation properties. How can I tell my view to pass the original model it received back to the Submit action?
When you first display the index, your Question and Explanation are displayed correctly.
Then you submit the form, and Question and Explanation doesn't make it to the Controller Action.
That is because your FORM doesn't have input fields containing the Question and Explanation.
Add this to your form:
#Html.HiddenFor(x => x.Question)
#Html.HiddenFor(x => x.Explanation)
If the Explanation is editable by the user, instead of adding a Hidden for it do this:
#Html.TextAreaFor(x => x.Explanation)
Remember: All the info you need to send to your controller need to be in INPUTS inside of your FORM.
This way, your view will became:
<div class="title">Question</div>
<span id="question">#Model.Question</span>
#if (!Model.UserHasAnswered)
{
using (Html.BeginForm("Submit", "Quiz", FormMethod.Post))
{
#Html.HiddenFor(x => x.Question)
#Html.HiddenFor(x => x.Explanation)
for (int i = 0; i < Model.Responses.Count; i++)
{
<div class="reponse">#Html.RadioButtonFor(m => m.SelectedIndex, i)#Model.Responses[i]</div>
}
<input type="submit" value="This is the value" />
}
}
else
{
<div id="explanation">#Model.Explanation</div>
}
I believe your index action should be like below in your scenario :
public ActionResult Index(QuizModel model)
{
if(model == null)
{
model = new QuizModel()
{
Question = "This is the question",
Explanation = "This is the explanation",
UserHasAnswered = false
};
}
return PartialView(model);
}
Hope this will help !!

Not able to run another function for another button inside same view

I have got the two buttons in the same view one is working with the data to show in a label in another view and I have written the function for the button2 (adding another value), when I click on the button2 its not showing the data in view ..... rather it's giving error like this ... http:404 Resource not found error
and this is the view
#model MvcSampleApplication.Models.products
#{
ViewBag.Title = "Valuesadd";
}
<h2>Valuesadd</h2>
#using (Html.BeginForm("SubmitValue","EnterValue",FormMethod.Post))
{
<div>
<fieldset>
<legend>Enter Textbox Value</legend>
<div class ="editor-label">
#Html.LabelFor(m => m.EnteredValue)
</div>
<div class="editor-field">
#Html.TextBoxFor(m=>m.EnteredValue)
</div>
<p>
<input type="submit" value="Submit1" />
</p>
</fieldset>
</div>
}
#using (Html.BeginForm("SubmitValue2","EnterValue",FormMethod.Post))
{
<p>
<input type="submit" value="Submit2" />
</p>
}
and this is the controller for
namespace MvcSampleApplication.Controllers
{
public class EnterValueController : Controller
{
[HttpPost]
public ActionResult SubmitValue(MvcSampleApplication.Models.products model)
{
TempData["logindata"] = model.EnteredValue;
return RedirectToAction("submittedvalues" , "SubmitValue2");
// how can we redirect to another view when the button is clicked in one view
}
public ActionResult submittedvalues()
{
var model = new MvcSampleApplication.Models.category();
string data = TempData["logindata"] != null ? TempData["logindata"].ToString() : "";
model.lablvalue = data;
return View(model);
}
// action for second button click
public ActionResult submittedvalues2()
{
var model = new MvcSampleApplication.Models.category();
string data = TempData["logindata"] != null ? TempData["logindata"].ToString() : "";
model.lablvalue = "HIIII"+data;
return View(model);
}
}
}
would you pls suggest any idea ..
Many thanks...
Your form action and action in the controller are not named the same. Also you don't have a HttpPostfor it
#using (Html.BeginForm("SubmitValue2","EnterValue",FormMethod.Post))
{
}
//add this
[HttpPost]
public ActionResult submittedvalues2()
{
var model = SOMETHING;
return View("submittedvalues", model);
}
or
[HttpPost]
public ActionResult submittedvalues2()
{
//Do your post actions and redirect to action
return RedirectToAction("submittedvalues");
}
SubmitValue2 in the form should be submittedvalues2, and add a HttpPost attribute on it

How to convert my simple ASP.NET MVC 4 application to AJAX?

How to I convert my simple MVC4 todo list application to AJAX?
The ideal answer would give me the steps that would lead to a successful conversion of this example to AJAX.
Note: I don't need an AJAX tutorial so much as an understanding of how the ASP.NET MVC architecture supports it.
Side Question: Why does #Html.EditorFor(model => model.TodoItemToCreate) bring back the value that was typed in even though the view model sets with this.TodoItemToCreate = null?
Model
public class TodosViewModel
{
List<string> todoItems;
public List<string> TodoItems
{
get { return this.todoItems ?? (todoItems = new List<string>()); }
}
[Display(Name="What do you need to do?")]
public string TodoItemToCreate { get; set; }
public bool AcceptTodoItem()
{
bool isThereAnItemToAccept = !string.IsNullOrWhiteSpace(this.TodoItemToCreate);
if (isThereAnItemToAccept)
{
this.TodoItems.Add(this.TodoItemToCreate);
this.TodoItemToCreate = null;
}
return isThereAnItemToAccept;
}
}
Controller
public class TodosController : Controller
{
public ActionResult Index()
{
return View(new TodosViewModel());
}
public ActionResult Create(TodosViewModel todosViewModel)
{
todosViewModel.AcceptTodoItem();
return View("Index", todosViewModel);
}
}
Index View
#model Programming.LearnWeb.Models.TodosViewModel
#{
ViewBag.Title = "Todos";
}
#using (Html.BeginForm("Create", "Todos"))
{
#Html.Partial("List")
#Html.LabelFor(model => model.TodoItemToCreate)
#Html.EditorFor(model => model.TodoItemToCreate)
<input type="submit" value="Create" />
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
List View
#model Programming.LearnWeb.Models.TodosViewModel
#{ int i = 0; }
<table>
#foreach (var todoItem in Model.TodoItems)
{
<tr>
<td>
#Html.Hidden("TodoItems[" + i++ + "]", todoItem)
#todoItem
</td>
</tr>
}
</table>
I got this done on my own - the result is at https://github.com/gabrielgreen/Todos.Mvc if anyone is interested or has any comments.
I put a fair amount of effort in and would appreciate any feedback that indicates if I did it right.

Asp:net MVC 3: #Html.EditorFor a subcollection of my model in a template?

I've been stuck a long time to edit a subcollection of my model, the collection of the model was coming null.
I finally found a solution, but I find it a little dirty:
First my tests datas:
Model object:
public class ContainerObject
{
public String Title { get; set; }
public List<ContainedObject> ObjectList { get; set; }
}
Sub collection object:
public class ContainedObject
{
public int Id { get; set; }
public String Text { get; set; }
public Boolean IsSelected { get; set; }
}
Controller method which generate the object
public ActionResult TestForm()
{
return View(new ContainerObject()
{
Title = "This is a sample title",
ObjectList = new List<ContainedObject>()
{
new ContainedObject(){Id=1, IsSelected = true, Text="ObjectOne"},
new ContainedObject(){Id=2, IsSelected = false, Text="ObjectTwo"},
new ContainedObject(){Id=3, IsSelected = true, Text="ObjectThree"},
new ContainedObject(){Id=4, IsSelected = false, Text="ObjectFour"},
}
});
}
Controller which receive the edited object
[HttpPost]
public ActionResult TestFormResult(ContainerObject filledObject)
{
return View();
}
The view
#model WebTestApplication.Models.ContainerObject
#{
ViewBag.Title = "TestForm";
}
#using (Html.BeginForm("TestFormResult","Home", FormMethod.Post)){
#Html.EditorFor(x => x.Title)
Html.RenderPartial("ContainedObject", Model.ObjectList);
<input type="submit" value="Submit"/>
}
The partial view(ContainedObject.cshtml)
#model IEnumerable<WebTestApplication.Models.ContainedObject>
#{
ViewBag.Title = "ContainedObject";
int i = 0;
}
#foreach (WebTestApplication.Models.ContainedObject currentObject in Model)
{
<br />
#Html.Label(currentObject.Text);
#Html.CheckBox("ObjectList[" + i + "].IsSelected", currentObject.IsSelected);
#Html.Hidden("ObjectList[" + i + "].Id", currentObject.Id);
#Html.Hidden("ObjectList[" + i + "].Text", currentObject.Text);
i++;
}
This is actually working, but I've one problem:
I've to generate names myself and specify the property of the container object
I tried to use Html.EditorFor instead of Html.RenderPartial in the view, the problem is that it generate me the name "ObjectList.[0].Id"(with a additional . between the property name and the accessor).
I also tried to use only #Html.EditorFor in the partial view, but it create vars with the name of the object.
If I don't use any template, it works:
#model WebTestApplication.Models.ContainerObject
#{
ViewBag.Title = "TestForm";
}
#using (Html.BeginForm("TestFormResult", "Home", FormMethod.Post))
{
#Html.EditorFor(x => x.Title)
for (int i = 0; i < Model.ObjectList.Count; i++)
{
<br />
#Html.Label(Model.ObjectList[i].Text);
#Html.CheckBoxFor(m => Model.ObjectList[i].IsSelected);
#Html.HiddenFor(m => Model.ObjectList[i].Id);
#Html.HiddenFor(m => Model.ObjectList[i].Text);
}
<br /><input type="submit" value="Submit"/>
}
But here it's a simple template, but in my real case, I will have much more data, and this will be re-used multiple time. So what is my best option?
You can simplify your code by introducing the EditorTemplate. Here is how:
The main view remains pretty much the same except we replaced RenderPartial with EditorFor:
TestForm.cshtml
#model WebTestApplication.Models.ContainerObject
#{
ViewBag.Title = "TestForm";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("TestFormResult", "Home", FormMethod.Post)) {
#Html.EditorFor(m => m.Title)
#Html.EditorFor(m => m.ObjectList);
<input type="submit" value="Submit" />
}
Then create a folder named EditorTemplates under Views/Home (assuming your controller is Home):
and add the following template for the ContainedObject:
ContainedObject.cshtml
#model WebTestApplication.Models.ContainedObject
<p>
#Html.DisplayFor(m => m.Text)
#Html.CheckBoxFor(m => m.IsSelected)
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.Text)
</p>
The editor will automatically iterate through the list of objects rendering the view for each of them. Hope it helps.
I found this thread while looking for something else related. Denis has the correct answer, but I thought I would add some syntax in case anyone else comes across this:
If you have an editor template named "SomeTemplate.cshtml" you can use it for a list of Item as follows in your view:
#for (var i = 0; i < Model.ObjectList.Count(); i++)
{
#Html.EditorFor(m => m.ObjectList[i], "SomeTemplate")
}
Then in your editor template:
#model WebTestApplication.Models.ContainedObject
<br />
#Html.Label(Model.Text);
#Html.CheckBoxFor(m => m.IsSelected);
#Html.HiddenFor(m => m.Id);
#Html.HiddenFor(m => m.Text);

Categories

Resources