FormsCollection in Mvc Controller method - any other way of accessing? - asp.net-mvc

I have a form which I want to post to ensure the page refreshes on posting the data (not the ajax way). The problem is really I only want to post the Id of the record and extract that in the controller method. I'm finding that the form is posting everything (I might not be able to resolve that since the same form is used for updating). But I'd like to be able to have the variable pop into the parameter of controller method rather than extracting from the FormCollection. I've tried the various parameters below, but all are being passed null. Any idea what the problem is?
I have the following in my controller method:
public ActionResult Delete(FormCollection collection)
{
var idToDelete = collection["Current.CommissionStructureId"].ToInt32();
}
// tried the following but none of them bind
public ActionResult Delete(int? Current_CommissionStructureId, int? CommissionStructureId, int? Id, int? id)
{
// none of the above are binding (set to null)
}

You should use HttpPost only for deleting of records
#using (Html.BeginForm()) {
<input type="hidden" name="CommissionStructureId" value="#item.CommissionStructureId" />
<p>
<input type="submit" value="Delete" />
</p>
<p>
#Html.ActionLink("Back to List", "Index")
</p>
}
[HttpPost]
public ActionResult Delete(int CommissionStructureId)
{
CommissionStructure commissionStructure = db.CommissionStructures.Find(CommissionStructureId);
db.CommissionStructures.Remove(commissionStructure);
db.SaveChanges();
return RedirectToAction("Index");
}

When your form value is named Current.CommissionStructureId the default modelbinder will bind it only to a class parameter called Current with a property called Id.
So your options are
Create a small class with one property Id and use it as your parameter type
or
Write a custom modelbinder

Related

How to transfer data from a view to a method?

There is a Customer controller, it has the DeleteCustomer action method.
public class CustomerController : Controller
{
[HttpGet]
public IActionResult Index()
{
IEnumerable<CustomerViewModel> customers =
_customerRepository.GetAllCustomers().Select(s => new
CustomerViewModel
{
CustomerId = s.CustomerId,
Name = s.Name,
Adress = s.Adress
});
return View("Index", customers);
}
[HttpPost]
public IActionResult DeleteCustomer(int id)
{
_customerRepository.Delete(id);
return LocalRedirect("~/Customer/Index");
}
}
Here is the link, when clicked, the action method should work, the Id of the user I want to delete should fly into the method. But he writes an error 405. Somewhere I was mistaken I can not understand exactly where. I would be grateful for your help. I think the tag "a" is a Get request. Use #Html.ActionLink()?
<a asp-action="DeleteCustomer" asp-route-id="#item.CustomerId">Delete</a>
The problem is that DeleteCustomer only responds to POST, but HTML links are always requested via GET. However, DeleteCustomer should require a POST, so don't change that. Instead, you need to use a form like:
<form asp-action="DeleteCustomer" method="post">
<input type="hidden" name="id" value="#item.CustomerId" />
<button type="submit">Delete</button>
</form>
Then, if you want the button to look like a link, you can simply style it to look that way. If you're using Bootstrap, you can just apply the btn-link class to it.

MVC HTTP Post input return null

Controller:
public ActionResult MyController()
{
ViewBag.DateNow = DateTime.Now.ToString("yyyy-MM-dd");
}
[HTTPPost]
public ActionResult MyController(string fromDate)
{
ViewBag.DateNow = fromDate;
}
View:
#using (Html.BeginForm("MyController", "Account", FormMethod.Post))
{
//datepicker class: bootstrap-datepicker.js
<input id="fromDate" type="text" class="datepicker" />
<buttontype="submit" value="Search" class="btn btn btn-primary">
Search
</button>
}
What I'm trying to achieve is before POST the data that pass into ViewBag.DateNow is the current date and it successfully bring in to the view. However when I'm trying to fill up the input form with (eg: 2016-05-10) and click on the Search button. But seems like the fromDate string return NullReferenceException. I'm trying out with some solution online but I still can't get it right and that's why I decided to get this posted up. Thanks in advance!
For this to work properly you need to specify the name attribute in your textbox. It needs to be the same value as the input variable in your HTTP post action method, namely fromDate. Currently the id attribute is set to fromDate:
<input id="fromDate" name="fromDate" type="text" value="#ViewBag.DateNow" />
If you do not specify this name attribute then when you post your form fromDate will always be null. Specifying it like above will make sure that fromDate will always have a value (if entered).
I want to go a bit off-topic here, I would like to suggest that you make use of view models for your form submissions. Instead of having individual input variables in your action method you can just have your view model as input parameter.
I wrote an answer as to what view models are here, please go and read it if you have the time:
What is ViewModel in MVC?
Working on your example, I would have a view model that contains just one property, namely FromDate. FromDate will contain the value in your textbox. It is setup as a string because you want to pass it a formatted date value:
public class TestModel
{
public string FromDate { get; set; }
}
This value will be set in your HTTP get action method and the view model will be sent to the view:
public ActionResult Index()
{
TestModel model = new TestModel();
model.FromDate = DateTime.Now.ToString("yyyy-MM-dd");
return View(model);
}
In your view you will accept this view model and create the form accordingly:
#model WebApplication_Test.Models.TestModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.FromDate)
<button type="submit">Search</button>
}
When you submit this form, you need an HTTP post action method to handle the submission. Because the view is bound to the view model, the action method will accept it as an input parameter:
[HttpPost]
public ActionResult Index(TestModel model)
{
// Do what you need to do
string date = model.FromDate;
return View(model);
}
Your way of doing it is also correct. I have just shown you an alternative way to do it. Some day you might have a huge form with many input values, then my approach will be 'cleaner'.
Try this:
1) Replace with [HttpPost] instead of [HTTPPost]
2) You should add name=" " for input like this:
<input id="fromDate" name="fromDate" type="text" class="datepicker" />

Using webforms in MVC

I am learning MVC, following THIS tutorial. (link will take you directly to where i'm stuck). so far I have learnt, there's a controller for every view. Now i have to take input from user through web entry form as mentioned in tutorial. In my project, i have a controller named Default1 and i can run it as localhost:xyz/Default1/Index. it runs perfect.
Then i created a new Controller, named Default2 and bound it to some view to display some data, and it worked perfect as localhost:xyz/Default2/Displaycustomer. the customer information was static (hard coded). and controller is as:
public ViewResult DisplayCustomers()
{
Customer cobj = new Customer();
cobj.Code = "12";
cobj.Name = "Zeeshan";
cobj.Amount = 7000;
return View("DisplayCustomers",cobj);
}
Now i have to take input from User, regarding cutomer iformation, using html page as mentioned in tutorial. so i tried adding a new webform under view folder, and and modified my controller as:
[HttpPost]
public ViewResult DisplayCustomers()
{
Customer cobj = new Customer();
cobj.Code = Request.Form["Id"].ToString();
cobj.Name = Request.Form["Name"].ToString();
cobj.Amount = Convert.ToDouble(Request.Form["Amount"].ToString());
return View("DisplayCustomers",cobj);
}
My Question is: How can i make my project stared, so that it takes input first, and then displays it, using above controller? Did i add the webform at right location? What would be the link to run it? i tried localhost:xyz/Default2/entryform etc. but failed.
(in my entryform.aspx, i have mentioned form action="DisplayCustomer" )
It sounds like what you're missing is an action to just display the form. In otherwords, you just need an action to display a form. That form's POST action should reference your controller's DisplayCustomers action.
So in your controller code:
public class CustomerController : Controller
{
[HttpGet]
public ViewResult New()
{
return View("NewCustomer"); //Our view that contains the new customer form.
}
// Add your code for displaying customers below
}
And in your view, you have code like this
#using(Html.BeginForm("DisplayCustomers", "Customer")) {
<!-- Add your form controls here -->
}
Notice that I'm using the version of the BeginForm helper that specifies the action method and controller to call. This will write the form tag to post back to your DisplayCustomers action. Here is the equivalent HTML:
<form method="POST" action="/Customer/DisplayCustomers">
You would then access your form using the URL http://test.server/Customer/New.
This may not be the best example in the world...but this will at least get you rolling..
url would be:localhost:1234/Home/Customer
the controller
public ActionResult Customer()
{
return View();
}
[HttpPost]
public ActionResult Customer(FormCollection frm)
{
var name = frm["name"].ToString();
var address = frm["address"].ToString();
ViewBag.Name = name;
ViewBag.Address = address;
return View();
}
The view
<div>
#using (Html.BeginForm())
{
<input type="text" name="name" id="name" />
<input type="text" name="address" id="address"/>
<input type="submit" name="submit" value="submit" />
<input type="text" name="namedisplay" value='#ViewBag.Name'/>
<input type="text" name="addressdisplay" value='#ViewBag.Address'/>
}
</div>

passing value from view to controller in MVC

This is my view
<form method="post" action="/LoadCustomerAndDisplay/Search">
<fieldset>
<legend>Customer Book</legend>
<%= Html.Label("Name") %>
<%: Html.TextBox("Name") %>
<br />
<br />
<div>
<input type="submit" value="Sign" />
</div>
</fieldset>
</form>
This is my controller...
public ActionResult Search()
{
CustomerModels objCustomer = new CustomerModels();
var dataval = objCustomer.getData();
return View(dataval);
}
How can i get the value of Name textbox in the controller and pass it to the the getData like this....
var dataval = objCustomer.getData(ViewData['Name']);
this i put...showing error on fname....missing adding directive....what's the issue now...
<% Html.BeginForm("Search", "LoadCustomerAndDisplay");%>
<%: Html.TextBoxFor(m => m.fname) %>
<p>
<button type="submit">
Save</button></p>
<% Html.EndForm();%>
Use strongly typed view. In your GET action method, pass an object of your ViewModel to the view and use the HTML helper methods to create the input elements. When you submit the form, due to MVC model binding, you will get the values as the property values of the ViewModel in the POST action method.
Your GET action can stay same
public ActionResult Search()
{
CustomerModels objCustomer = new CustomerModels();
var dataval = objCustomer.getData();
// Assuming this method returns the CustomerViewModel object
//and we will pass that to the view.
return View(dataval);
}
so your View will be like
#model CustomerViewModel
#using (Html.BeginForm())
{
#Html.LabelFor(x=>x.Name)
#Html.TextBoxFor(x=>x.Name)
<input type="submit" value="Save" />
}
And have a POST action method to handle this
[HttpPost]
public ActionResult Search(CustomerViewModel model)
{
if(ModelState.IsValid)
{
string name= model.Name;
// you may save and redirect here (PRG pattern)
}
return View(model);
}
Assuming your objCustomer.getData() method in your GET Action method returns an object of CustomerViewModel which has a Name property like this
public class CustomerViewModel
{
public string Name { set;get;}
//other properties as needed
}
You can add a parameter to your Search action that accepts an object of Type CustomerModels. That way when you post something back to the controller, the model binder will take the data from the form and generate an object of type CustomerModels which you can then use in your action to work with. For that you need to do two things:
Your view should receive a model of type CustomerModels
Your action should be something like this public ActionResult Search(CustomerModels model)
If you don't want to change your view, that is, you don't want to pass model to your page, you could try and use TryUpdateModel inside your controller, or pass FormCollection object to your Search action and then query that collection.

ASP.NET MVC - Dynamic action and parameter for a form

I'm working on a bit of MVC where I'm needing to dynamically route a form to a certain action and parameter combination. So far, I've got this:
PageViewModel
{
public string Action {get;set;}
public string Parameter {get;set;}
/*... other properties for the form */
}
PageController
{
public ViewResult MyAction(string myParamterName) {
return View("CommonView",
new PageViewModel{Action="MyAction", Parameter="myParameterName"));
}
public ViewResult YourAction(string yourParamterName) {
return View("CommonView",
new PageViewModel{Action="YourAction", Parameter="yourParameterName"));
}
/* ... and about 15 more of these */
}
CommonView.aspx:
<%-- ... --%>
<% using (Html.BeginForm(Model.Action,"PageController",FormMethod.Get)) {%>
<%=Html.TextBox(Model.Parameter)%>
<input id="submit" type="submit" value="Submit" />
<%}%>
<%-- ... --%>
This works, but it's got a lot of strings floating around to tell it where to go.
What I'd like to have is a type-safe way of defining the form parameters inside the view, but I'm a bit lost on how to accomplish this. Perhaps something that looks like this -
<% using (Html.BeginForm<PageController>(Model.??ExpressionToGetAction??)) {%>
<%=Html.TextBox(Model.??ExpressionToGetParameter??)%>
<input id="submit" type="submit" value="Submit" />
<%}%>
Or, is there a way to get the action and parameter used to generate this view, perhaps from route data?
Or should there be a custom routing scheme that can handle all of this automagically?
So, what I'm really wanting is the most elegant and type-safe way to accomplish this. Thanks!
EDIT
As Josh points out, the form will submit back to the action. This trims the code somewhat :
PageViewModel
{
public string ParameterName {get;set;}
/*... other properties for the form */
}
PageController
{
public ViewResult MyAction(string myParamterName) {
return View("CommonView",
new PageViewModel{ParameterName ="myParameterName"));
}
public ViewResult YourAction(string yourParamterName) {
return View("CommonView",
new PageViewModel{ParameterName ="yourParameterName"));
}
/* ... and about 15 more of these */
}
CommonView.aspx:
<%-- ... --%>
<% using (Html.BeginForm(FormMethod.Get)) {%>
<%=Html.TextBox(Model.ParameterName)%>
<input id="submit" type="submit" value="Submit" />
<%}%>
<%-- ... --%>
It is still unclear how to have the textbox bind a parameter by name back to the action from which the view was created without explicitly specifying it.
Or, is there a way to get the action and parameter used to generate this view
If you leave the action and controller portion of the BeginForm arguments empty, it will to post back to where it came from. You can have two action with the same name, one decorated as HttpGet and the other HttpPost, as long as they have different parameters. Usually the get has one or none, and the post has several or a model bind.

Resources