I'm a newbie to asp.net mvc and I'd like to know if what I do is correct.
I want to create a view for searching people. Here's what I have so far:
The business model class:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
public DateTime DOB { get; set; }
public List<Telephone> Telephones { get; set; }
}
The ViewModel class:
public class SearchPersonViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public string LicencePlate { get; set; }
public string CarMake { get; set; }
public string CarModel { get; set; }
}
The partial view :
#model IEnumerable<MvcApplication2.Models.SearchPersonViewModel>
#foreach (var item in Model)
{
#Html.DisplayFor(m => item.Id)
#Html.DisplayFor(m => item.FullName)
}
The view from which the partial view is called:
#Html.Action("Search", "Person");
*The controller method in the PersonController:
[ChildActionOnly]
public ActionResult Search()
{
List<SearchPersonViewModel> model = new List<SearchPersonViewModel>();
model.Add(new SearchPersonViewModel() { FullName = "test", Id = 3 });
return PartialView("_SearchPerson", model);
}
Now the problem is that the Search method is called whenever the main View is loaded. What I want is to add a search textbox on the mainview for filtering the collection rendered in the partial view. How could I do that ?
This way your partial will render on click only
<script>
(function($){
$('#btn').click(function(){
$('#searchresult').load('#Url.Content("~/Person/Search")');
}
</script>
Make an ajax request to /search and append the data to your page.
<div id = 'searchresult'>
#Html.Action("Search", "Person");
</div>
whenever your want to filter call something like $('#searchresult').load('/search?q=xxx');
You could use 2 ways:
microsoft ajax helpers
jquery
For both of them you need to remove [ChildActionOnly] and #Html.Action("Search", "Person");
Look at this example: Using Ajax.BeginForm with ASP.NET MVC 3 Razor
Related
This question already has answers here:
Multiple models in a view
(12 answers)
Closed 6 years ago.
I am devolaping a 2nd hand item selling like OLX, I have two models
1: Product_model
2: Customer_model
so i want to use the the product description and customer information in a single view.
Models:
[Table("Product")]
public class ProductModel
{
[Key]
public string ProductId { get; set; }
public string ProductName { get; set; }
public decimal ProductPrice { get; set; }
public string ProductDescription { get; set; }
public string ProductCategory { get; set; }
public string ProductAddress { get; set; }
public string ProductImage1 { get; set; }
public string ProductImage2 { get; set; }
public string ProductImage3 { get; set; }
public string CustomerId { get; set; }
// public DateTime ProductSubTime { get; set; }
}
[Table("Customer")]
public class CustomerModel
{
[Key]
[Required(ErrorMessage = "Please provide Customer ID",
public string CustomerFullName { get; set; }
public int CustomerContact { get; set; }
public string CustomerEmail { get; set; }
public string CustomerGender { get; set; }
public string CustomerAddress { get; set; }
}
My controller:
public ActionResult Index()
{
return View(cm.Products.ToList());
}
My view:
#model IEnumerable<WebApplication11.Models.ProductModel>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/MyTemplate.cshtml";
}
<div class="col-md-4"style="border: 2px solid yellow" >
<div class="single-product-widget" style="border: 2px solid black">
<h2 class="product-wid-title">Recently Viewed</h2>
View All
#{ int i = 0;}
#foreach (var item in Model)
{
<div class="single-wid-product" style="border: 2px dashed black">
<img src="~/images/#item.ProductImage1" alt="No Photo" class="product-thumb">
<h2>#Html.DisplayFor(model => item.ProductName)</h2>
</div>
}
<div>
</div>
For understanding purpose i deleted some part of view.
Please guide me accessing both models in particular view.
I tried also some methods but not able to get it.
Thanks in advance...
You can create a view model with 2 properties like following code
public class MyModel
{
public List<ProductModel> Products { get; set; }
public List<CustomerModel> Customers { get; set; }
}
In controller:
public ActionResult Index()
{
var model = new MyModel
{
Products = cm.Products.ToList(),
Customers = cm.Customers.ToList()
};
return View(model);
}
In Veiw
#foreach (var item in Model.Products)
{
#*Write your razor code here*#
}
There are several options to access several models in a particular view. I assume that you just want to show some customer information in page corner or something. Your layout view may have a requirement to include this customer info (but it does not matter anyway).
Most preferable option from my point of view is to use child action.
Create CustomerController
public class CustomerController : Controller {
[ChildActionOnly]
public ViewResult CustomerInfo() {
CustomerModel customer = ...
return PartialView("_CustomerPartial", customer);
}
}
.chstml view will have #Html.Action("CustomerInfo", "Customer") where you want customer info to be displayed.
This way you will have a separate CustomerModel creation logic.
Another option is to use ViewData or ViewBag to store secondary model information like customer info.
Controller code:
public ActionResult Index()
{
var products = cm.Products.ToList();
ViewBag.Customer = ... // get customer
return View(products);
}
View code:
#model IEnumerable<WebApplication11.Models.ProductModel>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/MyTemplate.cshtml";
var customer = (CustomerModel)ViewBag.Customer;
}
#* display customer info *#
#* either { *#
<div>Welcome #customer.CustomerFullName. You email is #customer.CustomerEmail</div>
#* } or { *#
#Html.Partial("_CustomerPartial", customer)
#* } *#
#foreach(var product in Model) {
#* display product info *#
}
Previous option can be changed in a way to use strongly typed model. It is also can be known as view model - usually a class that exists only to store necessary info for the view. In your case these are some customer and products information.
ViewModel:
public class ProductListViewModel {
public CustomerModel Customer { get; set; }
public IEnumerable<ProductModel> Products { get; set; }
}
i have created 2 model classes Mocmodel and mocsubmodel and set navigation property also.for each model id, there will be different submodels for a particular model id. i wanted to create am action link showing count of submodels, when i click on the count, view should display submodel details for each particular modelIDs like below
1220 FXRate count as hyperlink
public class tModel
{
public int ModelID { get; set; }
public string ModelName { get; set; }
public virtual ICollection<tSubModelcs> submodellist { get; set; }
}
public class tSubModelcs
{
public int submodelID { get; set; }
public string submodel { get; set; }
public DateTime launchdate { get; set; }
public int ModelID { get; set; }
}
in my view page i want to display the count of submodel as a link
#foreach (var m in Model)
{
<tr>
<td>#m.ModelID</td>
<td>#m.ModelName</td>
<td>
Html.ActionLink(, "findsubmodels", new { #id = m.ModelID, #class = "linkclick" })
</td>
</tr>
Nothing is clear. Which model are you sending to view ? Post your complete code with action methods. It seems like you are sending IEnumerable of tModel. If this is the case your Actionlink should be like this.
#if(m.submodellist != null)
{
#Html.ActionLink(m.submodellist.Count.ToString(), "findsubmodels",null, new { id = #m.ModelID, #class = "linkclick" })
}
Replace the null with your routevalue if any.
I am trying to generate Two sets of List of checkboxes on a view. It all working apart from Post action. On submit,
ParentViewModel is not binding the ChildViewModel properly
Model. FirstCheckboxList
Model. SecondCheckboxList
Above both are coming as null.
I am not sure what I am missing. Any help on this would be great.
Thanks in advance.
CheckboxItems.cshtml
#model List<CheckboxItem>
#{
for (int i = 0; i < Model.Count(); i++)
{
<div>
#Html.CheckBoxFor(x => x.ElementAt(i).Checked, new { #id = Model.ElementAt(i).Id, onclick = "GetValue()" })
<span id="Padded">#Model.ElementAt(i).Text</span>
</div>
}
}
MainView.cshtml
#Html.BeginForm(){
#Html.EditorFor(m=> m.FirstCheckboxList,"CheckboxItems")
#Html.EditorFor(m=> m.SecondCheckboxList, "CheckboxItems")
}
#Html.TextBoxFor(m => m.FSelected, new Dictionary<string,object>() {{"readonly",true}})
#Html.TextBoxFor(m => m.FUniverse,new Dictionary<string,object>() {{"readonly",true}})
<input type="submit" name="nextBtn" value ="Next" />
}
ParentViewModel
public class ParentViewModel
{
public int PId { get; set; }
public IEnumerable<CheckboxItem> FirstCheckboxList{ get; set; }
public IEnumerable<CheckboxItem> SecondCheckboxList{ get; set; }
public Int64 FSelected { get; set; }
public Int64 FUniverse { get; set; }
}
CheckboxItem : child view model
public class CheckboxItem
{
public int Id { get; set; }
public string Text { get; set; }
public bool Checked { get; set; }
}
controller action
[HttpPost]
public ActionResult MyCheckboxView(int planid, ParentViewModel model, string nextBtn)
{
// do something
return View(Model);
}
Try changing your viewmodel for the ParentViewModel to use a List<CheckboxItem> instead of an IEnumerable<CheckboxItem>:
public class ParentViewModel
{
public int PlanId { get; set; }
public List<CheckboxItem> FirstCheckboxList{ get; set; }
public List<CheckboxItem> SecondCheckboxList{ get; set; }
public Int64 FSelected { get; set; }
public Int64 FUniverse { get; set; }
}
The model binder needs a data structure like a List or an Array so that it can correctly bind elements at specified indexes. IEnumerable is just an interface and doesn't support indexes like this.
Edit
Also, as a side-note, you don't have to bother with the for loop in your EditorTemplate because MVC can do all this for you. Just change the model type to be #model CheckboxItem, remove the loop and get rid of the id attribute so it looks like this:
#model CheckboxItem
#{
<div>
#Html.CheckBoxFor(x => x.Checked, new { onclick = "GetSelectedFrame()" })
<span id="Padded">#Model.Text</span>
</div>
}
}
Also, make sure your EditorFor call doesn't supply the EditorTemplate's name, as this messes up the "MVC Magic" (see this question which explains that it automatically iterates the list without the template name and doesn't with the template name):
#Html.BeginForm(){
#Html.EditorFor(m=> m.FirstCheckboxList)
#Html.EditorFor(m=> m.SecondCheckboxList)
}
Hope someone can help - this has been bugging me for around 2 hours - its probably something simple :)
Kendo UI Grid sends a request to my controller
http://localhost:1418/user/update?UserID=1&UserName=Admin&RoleName=Admin&Email=c.j.hannon%40gmail.com&Active=true&Company%5BCompanyID%5D=1&Company%5BCompanyName%5D=asd
However, the controller class 'Company' isnt bound by the binder? Can any one help my view model and controller action signature are below:
[HttpGet]
public JsonResult Update(UserViewModel model)
{
svcUser.UpdateUser(new UpdateUserRequest() {
UserID=model.UserID,
RoleID = model.RoleName,
Email = model.Email,
Active = model.Active.GetValueOrDefault(false),
UserName = model.UserName
});
return Json("", JsonRequestBehavior.AllowGet);
}
public class UserViewModel
{
public int UserID { get; set; }
public string UserName { get; set; }
public string RoleName { get; set; }
public string Email { get; set; }
public bool? Active { get; set; }
public CompanyViewModel Company { get; set; }
}
Cheers
Craig
A few things. Your immediate problem is that Company is mapped to a complex object not a primitive type. Kendo Grid just does not do this (as of this writing). Just guessing, but you probably want to setup a foreign key binding on the Grid and just pass back the Id of the company from a listbox. This is not as bad as you think and it will immediatly fix your problem and look nice too.
Maybe personal taste but seems to be a convention. Use the suffix ViewModel for the model that is bound to your View and just the suffix Model for your business objects. So a Kendo Grid is always populated with a Model.
Ex.:
public class UserModel
{
public int UserID { get; set; }
public string UserName { get; set; }
public string RoleName { get; set; }
public string Email { get; set; }
public bool? Active { get; set; }
public int CompanyID { get; set; }
}
public class CompanyModel
{
public int ID { get; set; }
public string Name { get; set; }
}
public class UserViewModel
{
public UserModel UserModel { get; set; }
public IList<CompanyModel> Companies { get; set; }
}
public ActionResult UserEdit(string id)
{
var model = new UserViewModel();
model.UserModel = load...
model.Companies = load list...
return View(model);
}
#model UserViewModel
...
column.ForeignKey(fk => fk.CompanyId, Model.Companies, "ID", "Name")
(Razor Notation)
BUT! This is just an example, you are better off Ajax loading the Grid with the IList becuase I assume you have many Users in the Grid at once, though you could server bind off the ViewModel with a List too. But the list of Companies is probably the same every time, so map it to the View just liek this rather than Ajax load it every time you do a row edit. (not always true)
I have the following action method that returns a collection of AdminDetail instances:
public ActionResult DetailData()
{
var vm = _reference.Detail().ToList();
return PartialView("~/Areas/Administration/Views/References/_DetailData.cshtml", vm);
}
Here's my AdminDetail class:
namespace Storage.Models
{
public class AdminDetail
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public string Title { get; set; }
public string Status { get; set; }
public string Type { get; set; }
public string Level { get; set; }
public string Order { get; set; }
public int Row { get; set; }
}
In my razor view what should I put for the model? If I just put the following then it is only for one instance:
#model Storage.Models.AdminDetail
#foreach (var detail in Model.AdminDetails)
{
How can I pass a collection of AdminDetails using my model to the view? I am not sure if viewdata is an option but I would rather not use that as I heard it's not really a good choice.
You could use a collection of AdminDetail as your view model type so that you can loop through the elements:
#model IEnumerable<Storage.Models.AdminDetail>
#foreach (var detail in Model)
{
<div>#detail.Title</div>
...
}
or using a display template you can avoid the loop:
#model IEnumerable<Storage.Models.AdminDetail>
#Html.DisplayForModel()
and inside the corresponding display template which will automatically be rendered for each element of the collection (~/Views/Shared/DisplayTemplates/AdminDetail.cshtml):
#model Storage.Models.AdminDetail
<div>#Html.DisplayFor(x => x.Title)</div>
...
You can set a list as your model - a model in MVC3 can be anything you want. Just set List as the model of the view.
Alternatively, use the ViewBag (although I would not recommend to abuse it as you loose IntelliSense). ViewBag is like a dynamically typed dictionary which is available from both the View and the Controller.
Here's an example:
Controller:
ViewBag.Color = "Blue";
View:
<h1> The color is <%: ViewBag.Color %> </h1>