Im new to MVC.. and started to grasp it. I am wondering whether there's a shorter way to pass parameters from view to mvc controller. I am creating a search box with possible conditions.
here's the sample code in the view
#using (Html.BeginForm("Action", "Controller", FormMethod.Get))
{
<p>
Find by fname: #Html.TextBox("fname", ViewBag.CurrentFilter as string)
<br/>
Find by lname: #Html.TextBox("lname", ViewBag.CurrentFilter as string)
<br/>
By Area Code : #Html.TextBox("AreaCode")
<br/>
#Html.DropDownList("StateCD", new SelectList(ViewBag.State))
<br/>
<input id="Button1" type="submit" value="Search"/>
</p>
}
in my controller
public async Task<ActionResult> Action(string id, string sortorder, string statecd,int? page,string country,string areacode,string city,string zip,string z)
{
}
is there a way to shorten that parameter like as an object or concatenated values?
You can create a class to represent your search filter and use that as the action method parameter type.
public class SearchVm
{
public strng StateCd { set;get;}
public string AreaCode { set;get;}
public string Zip { set;get;}
// Add other needed properties as well
}
and use that as the param
public async Task<ActionResult> Search(SearchVm model)
{
// check model.AreaCode value etc..
// to do : Return something
}
When the form is submitted Default Model binder will be able to map the posted form data to properties of the method parameter object, assuming your form field name's match with the class property names
Related
To recreate the issue I'm having I've set up two simple controller actions, two views and a view model:
MultiForms Action (in the form controller class)
public class FormController : Controller
{
[HttpGet]
public ActionResult MultiForms()
{
return View("MultiForms");
}
// ...
MultiForms.cshtml - Razor View
#Html.Action("MyFormGet", "Form")
Notice in the action method I call the controller method that returns the form partial view.
MyFormGet Action
[HttpGet]
public PartialViewResult MyFormGet()
{
var viewModel = new MyFormViewModel();
ViewData.TemplateInfo.HtmlFieldPrefix = Guid.NewGuid().ToString().Replace("-", "_");
return PartialView("MyForm", viewModel);
}
View Model
public class MyFormViewModel
{
public string TextInput1 { get; set; }
}
MyForm.cshtml - Razor View
#model Mvc5App.Controllers.MyFormViewModel
#using (Html.BeginForm("MyFormPost", "Form", FormMethod.Post))
{
<br />
#Html.TextBoxFor(m => m.TextInput1)
}
When I point my browser at /Form/MultiForms I get the output I expect:
<input type="text" value="" name="e166fa0d_46fe_40d4_a970_73c52a35f224.TextInput1" id="e166fa0d_46fe_40d4_a970_73c52a35f224_TextInput1">
Then I refresh the page and the output becomes this:
<input type="text" value="" name="48edc339_69ad_4b9b_9583_198038beab45.TextInput1">
Where did the id attribute go? Is this a bug in ASPNET MVC5 or have I done something wrong with this setup?
Thanks to #demo I think I figured out when the id doesn't show up...
If the id starts with a digit(or underscore) it will not render. So this GUID will render:
f3b1a447_3786_4472_9dfe_14c3ae8aae24
But this one will not:
1c26ce3d_5c71_408a_aae2_7be414f1d383
The solution for the above seems to be prefixing with something like this:
FOO_1c26ce3d_5c71_408a_aae2_7be414f1d383
And the problems go away.
I am unable to make a simple MVC 3 controller/view/model program work with an ActionResult method that includes the Bind attribute with a Prefix property.
One example that I did try could populated the parameter when I call the action method from the URL.
Here is that example controller followed by its view:
//Controller
//public ActionResult PrefixExample(int number = 0)
public ActionResult PrefixExample([Bind(Prefix="okay")]int? number)
{
return View(number);
}
//View
#model Int32?
#{
ViewBag.Title = "Example";
}
<h2>Example</h2>
#using (Html.BeginForm())
{
if (#Model.HasValue)
{
<label>#Model.Value.ToString()</label>
} else {
<label>#Model.HasValue.ToString()</label>
}
<input type="submit" value="submit" />
}
If I use this url http://localhost/MVCApp/Home/Example?okay=3 the parameter, number, is populated. If I use this url http://localhost/MVCApp/Home/Example?number=3, the parameter isn't populated. Interestingly, with the first url, when I view source, the prefix okay doesn't show up.
If I uncomment the first line of my controller and comment out the second line, the opposite is true: the url with okay won't populate number but the second url using number will populate number in the controller.
I would like to know how to make the following example accept a url and correctly set the "view source" prefix. Here is a possible url http://localhost/MVCApp/Home/SpecificPerson?PersonId=0&FirstName=Joe&LastName=Doe
Note, that if I remove the Bind attribute from the controller method, the above url will work with the MVC app below.
Here is my model/controller/view:
//model:
namespace MVCApp.Models
{
public class Person
{
[HiddenInput(DisplayValue = false)]
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
//controller
namespace MVCApp.Controllers
{
public class HomeController : Controller
{
public ActionResult SpecificPerson([Bind(Prefix = "myPerson")]Person aPerson)
{
return View("SpecificPerson", aPerson);
}
}
}
//view
#model MVCApp.Models.Person
#{
ViewBag.Title = "SpecificPerson";
}
<h2>SpecificPerson</h2>
#Html.EditorForModel();
<br />
#Html.EditorFor(m => m);
I would like to see the above example work. Anyone who could show me why it doesn't work as I expect or what I can do to make it work this way would be greatly appreciated.
Thank you in advance.
I think the EditorForModel brought you a bit off track. If you check the html that is generated by this helper you will see that it's not wrapped in a form. Besides that I think the EditorForModel will not serve you as much as you would like to. You can also get it to work correctly without specifying the Bind prefix.
//model
public class Person
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
//controller
public class HomeController : Controller
{
public ActionResult Index(Person person)
{
if("POST".Equals(Request.HttpMethod))
{
//for example do some validation and redirect
}
return View(person);
}
}
//view
#model Application.Models.Person //only as example use own
#using(Html.BeginForm("Index","Home", FormMethod.POST))
{
#Html.HiddenFor(x=> x.Id)
<div>
#Html.LabelFor(x=> x.FirstName)
#Html.TextBoxFor(x=> x.FirstName)
</div>
<div>
#Html.LabelFor(x=> x.LastName)
#Html.TextBoxFor(x=> x.LastName)
</div>
<input type="submit" value="Do a post request"/>
}
Also if you use a url like /Home/Index?Id=9 and you look the HTML code you will see that there will be a element with input type=hidden and the value of 9. You could also use two actionresults to split your logic with [HttpGet] and [HttpPost] as attribute of your Action.
And as last I recommend you to check out the newer versions of MVC; MVC 5 is already out...
I am making WCF service call using MyViewRequest view fields inside HttpPost ActionHandler. The goal is to show response using partial view, MyViewResponse
In brief I need to achieve these two items-
Disable load of partial view on first load.
Display Response (along with Request) after service call.
MyViewRequest.cshtml
#using (Html.BeginForm())
{
#Html.ValidationSummary(false)
//html code
}
</div>
<div id="dvResponse">
#Html.Partial("MyViewResponse");
</div>
Partial view: MyViewResponse.cshtml
#model MvcApplication3.Models.MyModel
#{
ViewBag.Title = "MyViewResponse";
}
<h2>MyView</h2>
#Html.Label(Model.MyName, "My Name")
This was pretty straight forward in Asp.Net using userControl, But stuck up here, How can we achieve this in MVC3.
I think the best way is to transfer your data using ViewModels. Let's assume you want to have an app something like stackoverflow where you have a question and user can post an answer and it will be shown after the post along with the question.
public class PostViewModel
{
public int ID { set;get;}
public string Text { set;get;}
public List<PostViewModel> Answers { set;get;}
public string NewAnswer { set;get;}
}
in your GET action, you show the question. Get the id from the url and get the Question details from your service/repositary.
public ActionResult Show(int id)
{
var post=new PostViewModel();
post=yourService.GetQuestionFromID(id);
post.Answers=yourService.GetAnswersFromQuestionID(id);
return View(post);
}
Assuming yourService.GetQuestionFromID method returns an object of PostViewModel with the propety values filled. The data can be fetched from your database or via a WCF service call. It is up to you. Also yourService.GetAnswersFromQuestionID method returns a list of PostViewModel to represent the Answers for that question. You may put both these into a single method called GetQuestionWithAnswers. I wrote 2 methods to make it more clear.
Now in your Show view
#model PostViewModel
#Html.LabelFor(x=>x.Text);
#using(Html.Beginform())
{
#Html.HiddenFor(x=>x.ID);
#Html.TextBoxFor(x=>x.NewAnswer)
<input type="submit" />
}
<h3>Answers</h3>
#if(Model.Answers!=null)
{
#Html.Partial("Responses",Model.Answers)
}
And your Partial view will be strongly typed to a collection of PostViewModel
#model List<PostViewModel>
#foreach(var item in Model)
{
<div> #item.Text </div>
}
Handling the postback is simple (HttpPost)
[HttpPost]
public ActionResult Show(PostViewModel model)
{
if(ModelState.IsValid)
{
//get your data from model.NewAnswer property and save to your data base
//or call WCF method to save it.
//After saving, Let's redirect to the GET action (PRG pattern)
return RedirectToAction("Show",new { #id=model.ID});
}
}
I wanna add search functionality in my MVC application. This functionality should be available for all pages. So, I added it into the shared layout.
The only problem I have is that I'm not able to pass the routValues to the Search action in spite of I'm creating a new Form inside the partial view.
Target action:(performs the search)
[HttpPost]
public ActionResult Search(SearchModel keyword)
{
// keyword is always null
return RedirectToAction("SearchResult", keyword.keyword);
}
public class SearchModel { public string Keyword { get; set; } }
The Partial View:
#model DocuLine.Models.SearchModel
#using (Html.BeginForm("Search", "Home", FormMethod.Post))
{
#Html.EditorFor(model => model.Keyword)
<input type="submit" value="Search" />
}
Try
public ActionResult Search(SearchModel model)
Why the class is defined as Keyword and then view SearchResult you pass it as a keyword (lower case first letter)?
1 UpdateModel
You can update the class SearchModel with the method UpdateModel to check if you can make the correct assignment.
2 FormCollection
You can try to receive as parameter in the method Search form data (FormCollection) and check if you get what you require.
Finally, I solve it. The problem is that the SearchModel parameter name is keyword and it should be anything except keyword becuase there's already an html control is rendered with this name.
To solve it, it should only be named with another name:
public ActionResult Search(SearchModel model)
{
// model now has a value.
}
I am new to Asp.net MVC and have no idea as to how can i perform the search. Here's my requirement, please tell me how will you handle this :-
I need to have textbox where user can enter a search query or string. The user then clicks on a button or presses enter to submit it. The string needs to matched with a table's property name.
NOTE:- Querying the data and fetching the result isn't the main point here. All I need to know is how will you take the user input and pass it to a controller action or whatever for further processing. Just tell me how will you read the user input and where will you send it to search.
Asp.Net MVC uses standard HTTP verbs. For the html part, it's a normal html form that points to an url. Server side, that url will be routed to a controller/action which will handle the input and do what is needed.
Let's have a sample. You want to make a search form. First of all, it's a best practice to have search forms use the HTTP GET method instead of POST, so the search results can be bookmarked, linked, indexed, etc. I won't be using Html.BeginForm helper method to make things more clear.
<form method="get" action="#Url.Action("MyAction", "MyController")">
<label for="search">Search</label>
<input type="text" name="search" id="search" />
<button type="submit">Perform search</button>
</form>
That's all the html you need. Now you'll have a controller called "MyController" and the method will be something like this:
[HttpGet]
public ActionResult MyAction(string search)
{
//do whatever you need with the parameter,
//like using it as parameter in Linq to Entities or Linq to Sql, etc.
//Suppose your search result will be put in variable "result".
ViewData.Model = result;
return View();
}
Now the view called "MyAction" will be rendered, and the Model of that view will be your "result". Then you'll display it as you wish.
As always in an ASP.NET MVC application you start by defining a view model which will express the structure and requirements of your view. So far you have talked about a form containing a search input:
public class SearchViewModel
{
[DisplayName("search query *")]
[Required]
public string Query { get; set; }
}
then you write a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new SearchViewModel());
}
[HttpPost]
public ActionResult Index(SearchViewModel model)
{
if (!ModelState.IsValid)
{
// There was a validation error => redisplay the view so
// that the user can fix it
return View(model);
}
// At this stage we know that the model is valid. The model.Query
// property will contain whatever value the user entered in the input
// So here you could search your datastore and return the results
// You haven't explained under what form you need the results so
// depending on that you could add other property to the view model
// which will store those results and populate it here
return View(model);
}
}
and finally a view:
#model SearchViewModel
#using (Html.BeginForm())
{
#Html.LabelFor(x => x.Query)
#Html.EditorFor(x => x.Query)
#Html.ValidationMessageFor(x => x.Query)
<button type="submit">Search</button>
}
This is the best way to do it.
Create a ViewModel
public class SearchViewModel
{
public string Query { get; set; }
}
Create a Controller
public class SearchController : Controller
{
[HttpPost]
public ActionResult Search(SearchViewModel model)
{
// perform search based on model.Query
// return a View with your Data.
}
}
Create the View
// in your view
#using (Html.BeginForm("Search", "SearchController"))
{
#Html.TextBox("Query")
<input type="submit" value="search" />
}
hope this helps