I've been searching all over the web to find an answer for such simple question, but I can't seem to find one.
Suppose we have a Product that has an edit page where we can set name, price and category.
Following the MVC(MVVM) pattern we have:
2 models ProductModel and ProductCategoryModel
ViewModel that holds the product and the categories list (for the dropdown)
View to display the edit page
Beside the above we have the ProductService which handles the CRUD operations
// Model
public class ProductModel
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int CategoryId { get; set; }
}
// Model
public class ProductCategoryModel
{
public int CategoryId { get; set; }
public string Name { get; set; }
}
// ViewModel
public class EditProductViewModel
{
public ProductModel Product { get; set; }
public List<ProductCategoryModel> Categories { get; set; }
}
The question is who is responsible for populating the ViewModel? I though it could be done in the constructor of the view model, however people say it is bad practice. Populating it in the controller also doesn't seems right.
You will map your EditProductViewModel from your ProductModel/ProductCategoryModel in the page controller.
You can then call your action to render your html page and pass your viewModel object.
Something like this :
public class HomeController : Controller
{
private EditProductViewModel viewModel;
public HomeController()
{
this.viewModel = new EditProductViewModel();
InitialiseViewModel();
}
public ActionResult Index()
{
return View("Index", viewModel);
}
private void InitialiseViewModel()
{
ProductCategoryModel productCategoryModel = new ProductCategoryModel();
ProductModel productModel = new ProductModel();
//do your mapping
productModel.Name = "Test mapping";
this.viewModel.Product = productModel;
}
}
Your .cshtml will look like this
#model WebApplication5.ViewModels.EditProductViewModel
<div class="jumbotron">
<h1>ASP.NET</h1>
<p>#Model.Product.Name</p>
<p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
<p>Learn more ยป</p>
</div>
Related
I have a model passed from controller to view in my asp.net mvc5 website. Then I show the dropdownlist using the model and I want to pass an id back when submitting the form. Here is my model :
public class SiteDirectionModel
{
public int id { get; set; }
public string name { get; set; }
}
Then in the model, I use a List<SiteDirectionModel> to which I add new instances of each item I need. I fill up both these lists and then pass my model to the view.
#model List<SiteDirectionModel>
#using (Html.BeginForm("GetSiteRF", "Create", FormMethod.Post))
{
#Html.DropDownListFor(x => x.name,new SelectList(Model.name,"Sites"));
<input type="button" value="Selectionner" class="btn btn-primary"/>
}
Then how to retrieve the ids for each name ? And how to pass it as a parameter to my controller? Such that I would have :
public ActionResult GetSiteRF(int id)
{
int newId = id;
//Call method to searchId ...
return View("CreateADUser");
}
I have given how to bind and get value from dropdown. Please use your own BL in this.
Your model should be like this.
public class Something
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SiteDirectionModel
{
public SelectList MyDropDown { get; set; }
public int SelectedValue { get; set; }
}
You BL should be like this.
public List<Something> GetListofSomething()
{
//your logic.
}
Your Get method should be like this.
public ActionResult MyGetMethod()
{
SiteDirectionModel model = new SiteDirectionModel();
model.MyDropDown = new SelectList(GetListofSomething(), "key_field_name", "value_field_name", "default_value");
}
Then finally HTML
#Html.DropDownListFor(x => x.SelectedValue,Model.MyDropDown)
Okay, so i have my ViewModel and I understand what the controller does, I'm just having difficulty implementing it. I don't know how to code a controller for the ViewModel, i've tried researching it myself and can't find anything.
Here is my viewModel, how would I go about constructing the controller? Not asking you to do it for me, just how to do it
public class ViewOrderViewModel
{
//From ORDER Table
public int OrderId { get; set; }
public System.DateTime OrderDate { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Email { get; set; }
public decimal Total { get; set; }
//from Products
public List<Product> Products { get; set; }
}
UPDATE
public class ViewOrderController : Controller
{
// GET: ViewOrder
public ActionResult ViewOrders()
{
var order = new Order();
var viewModel = GetViewModel(order);
return View(viewModel);
}
public ViewOrderViewModel GetViewModel(Order orderObject)
{
ViewOrderViewModel viewModel = new ViewOrderViewModel();
viewModel.OrderId = orderObject.OrderId;
viewModel.OrderDate = orderObject.OrderDate;
viewModel.FirstName = orderObject.FirstName;
viewModel.LastName = orderObject.LastName;
viewModel.City = orderObject.City;
viewModel.Address = orderObject.Address;
viewModel.Country = orderObject.Country;
viewModel.Email = orderObject.Email;
viewModel.PostalCode = orderObject.PostalCode;
viewModel.Total = orderObject.Total;
return viewModel;
}
}
Still unsure about how to map the List of products in the ViewModel class to the list of products in the db
Typically, your view is going to be "bound" to the ViewModel. It's like saying "Ok, I'm the view for an 'Order' and I only need to worry about the properties that you defined in ViewOrderViewModel".
The controller is not required for that binding to happen. The binding is declared at the top of your view:
Order.cshtml
#Model MyProject.Web.ViewModels.ViewOrderViewModel
<div>
<!-- Html for the view-->
</div>
This allows you to access properties on that model within the view. Razor has some functions that make life easy. For example, if you want to display the OrderId it might look like this:
<span>OrderId: #Model.OrderId </span>
The view doesn't care what values are set for each of those properties, it only cares that the properties exist. Where the controller comes into play is populating those properties with the values you want and then passing the ViewModel to the view:
public ActionResult Order()
{
var viewModel = new ViewOrderViewModel();
// Load data into each property
viewModel.OrderId = 123; // etc..
// Return it to the view. Asp.net knows to return
// it to the Order.cshtml view because the view
// and the controller action share the same name.
return View(viewModel);
}
Edit: In response to your questions in the comments: If you need to populate your ViewModel with values from a different model (such as a database model) you can create a mapper like so:
public ViewOrderViewModel GetViewModel(Order orderObject)
{
ViewOrderViewModel viewModel = new ViewOrderViewModel();
viewModel.OrderId = orderObject.OrderId;
viewModel.FirstName = orderObject.FirstName;
// etc...
return viewModel;
}
and then in your controller you would do something like this:
// var order = new Order()
var viewModel = GetViewModel(order);
I'm trying to add a new item to an existent list in my MVC application, my problem that's I don't know the correct approach to do it.
I've done this so far:
My Customer code:
Controller
public class CustomerController : Controller
{
public CustomerBusiness customerBusiness { get; set; }
public CustomerController()
{
customerBusiness = new CustomerBusiness();
}
//Some code that makes CRUD and more these methods
[HttpGet]
public ActionResult ViewAllJobOfferts(int id)
{
var cust = customerBusiness.GetById(id);
return View(cust.JobOfferts);
}
public ActionResult CreateJobOffert(int id)
{
var cust = customerBusiness.GetById(id);
return View(cust);
}
/* [HttpPost]
public ActionResult CreateJobOffert(JobOffertModel jobOffert)
{
return View();
}*/
}
I have a relationship 1 to n between my entities Customer and JobOffert, and the method ViewAllJobOfferts works fine, but I got stuck when I try to add a new JobOffert.
I have a couple of questions, here we go:
I must to create a controller special to JobOfferts, or control
inside the CustomerController?
When I try to create the view that will submit the form to new
JobOffert I didn't know how to link the customer to this new
JobOffert, f I try create a page using customer model, I do not have the JobOffert attributes and if I create using the JobOffert model, I dont know how make the link between these two objects. how must I do this?
PS.: Here the code of both models:
JobOffert Model
Customer Model
I must to create a controller special to JobOfferts, or control inside
the CustomerController?
Not necessarily, controller like other class should follow SRP (Single Responsibility Principle). In this case as long as CustomerController facilitating information related to Customer, it's completely fine.
When I try to create the view that will submit the form to new JobOffert I didn't know how to link the customer to this new JobOffert, f I try create a page using customer model, I do not have the JobOffert attributes and if I create using the JobOffert model, I dont know how make the link between these two objects. how must I do this?
The link between the customer and JobOffer is as you defined One-to-Many and entities contains references to each other. E.g. You can find all JobOffer for a customer whose Id is 1024 by querying JobOffer table where customerID = 1024. Likewise each JobOffer is traceable by Customer reference in entity class.
Now about creating a new JobOffer for a customer this is how you can go about:
public class CustomerController : Controller
{
public CustomerBusiness customerBusiness { get; set; }
public CustomerController()
{
customerBusiness = new CustomerBusiness();
}
//Some code that makes CRUD and more these methods
[HttpGet]
public ActionResult ViewAllJobOffersForCustomer(int customerId)
{
ICollection<JobOfferModel> model = customerBusiness.GetAllJobOffersByCustomerId(customerId);
return View(model);
}
[HttpGet]
public ActionResult CreateJobOffer()
{
// Blank model object to accept values from user,
// you may like to create a view model based on UI needs.
JobOfferModel jobOfferModel = new JobOfferModel();
return View(jobOfferModel);
}
[HttpPost]
public ActionResult CreateJobOffer(JobOfferModel jobOffer)
{
// You get a filled object here that contains customer id and job offer details
customerBusiness.CreateJobOffer(jobOffer);
return RedirectToAction("ViewAllJobOffersForCustomer", new { customerId = jobOffer.CustomerId });
}
Sample business service class:
public class CustomerBusiness
{
public ICollection<JobOfferModel> GetAllJobOffersByCustomerId(int customerId)
{
// TODO: Fetch job offer details from persistent store
// E.g.
// dataContext.JobOffers.Where(x => x.CustomerId == customerId).ToList();
throw new NotImplementedException();
}
public void CreateJobOffer(JobOfferModel jobOffer)
{
// TODO: Add job offer details in persistent store
// E.g.
// dataContext.JobOffers.Add(jobOffer);
}
}
Modified entity classes:
public class JobOfferModel
{
[Key]
public int Id { get; set; }
public string Description { get; set; }
[Required]
[DefaultValue(false)]
public bool Acepted { get; set; }
[Required]
[DefaultValue(true)]
public bool Active { get; set; }
[Required]
[Column(TypeName = "DateTime2")]
public DateTime JobDate { get; set; }
[ForeignKey("Id")]
public int CustomerId { get; set; }
public virtual CustomerModel Customer { get; set; }
}
public class CustomerModel
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Column(TypeName = "DateTime2")]
public DateTime BirthDate { get; set; }
public int PhoneNumber { get; set; }
public ICollection<JobOfferModel> JobOffert { get; set; }
}
So basically you will have a method in CustomerController that returns empty ViewModel or Model object. On view you will make customerId hidden. So that when form is posted it is mapped to correct customer along with JobOffer details. Once you have model object in HttpPost method you just need to insert an entry in JobOffer table (any persistent store) with customerId associated with it.
There are other nitty gritty but above typical approach will give you a good start I hope. Cheers
I am trying to sort a database table and display the results in a View in MVC.
The query in the Controller returns the sorted results in a console application (which references the same database) but the list displays as unsorted in the View. What am I doing wrong/ missing?
public class HomeController : Controller
{
private SwimTimesEntities db = new SwimTimesEntities();
public ActionResult Index()
{
var query = from s in db.Swims
orderby s.Day
select s;
return View(query.ToList());
}
And the Model is
public partial class Swim
{
public int SwimID { get; set; }
public System.TimeSpan Time { get; set; }
public string Day { get; set; }
public string Details { get; set; }
}
}
(Very) New to C# and MVC, pointers much appreciated.
In your View try using a Model, for sample:
#model List<Swim>
<ul>
#foreach(var item in Model)
{
<li>#item.Day - #item.Detail</li>
}
</ul>
I have a class that requires another class to be specified, but I don't want the MVC ModelState validator to check whether the secondary model is valid. Is this possible?
Here's a brief overview:
My entities look something like this:
public class WidgetType
{
public long Id { get; private set; }
[Required]
public string Name { get; set; }
...
}
public class Widget
{
public long Id { get; private set; }
[Required]
public string Name { get; set; }
[Required]
public WidgetType WidgetType { get; set; }
...
}
I have them encapsulated in a WidgetViewModel class that I'm passing to/from the View like this:
public class WidgetViewModel
{
public Widget Widget { get; set; }
public ICollection<WidgetType> WidgetTypes
{
get
{
return _repository.GetWidgets();
}
}
...
}
My view looks something like this:
...
#Html.DropDownListFor( m => m.Widget.WidgetType.Id, new SelectList( new EquipmentViewModel().EquipmentTypes, "Id", "Name" ) )
...
All of this works except for validation. ModelState.IsValid is always false because "Widget.WidgetType.Name" is required. I need the user to select a WidgetType, but I don't want ModelState to be validated deeper than "Widget.WidgetType.Id" (which should be all that Widget needs for its foreign key?).
Is there a better way to do this? I feel like there should be some way to validate without recursively inspecting deeper into the properties, but I can't find it. What am I missing...?
public class WidgetViewModel
{
[Required]
public string Name { get; set; }
[Required]
public WidgetType WidgetTypeId { get; set; }
public SelectList WidgetTypes
{
get
{
//This should be popuplated in your controller or factory not in the view model
retun new SelectList{ _repository.GetWidgets(),"Id","Name");
}
}
}
In your view
#Html.DropDownListFor( m => m.WidgetTypeId, Model.WidgetTypes)
And in your controller
public ActionResult Create(WidgetViewModel model)
{
Widget widget = new Widget{
Name = model.Name,
WidgetType = yourManager.GetWidgetTypeByID(model.WigetTypeId);
};
yourManager.Create(widget);
//...
}
If all you need in your view is the WidgetID then you don't need to include the entire Widget in the WidgetViewModel. Just have property called WidgetID. View model classes should have only the data the is necessary for the view.
In the controller action method that is called when you submit the form, you can use the WidgetID to fetch the Widget object from the database if it is needed.
http://blog.stevensanderson.com/2010/02/19/partial-validation-in-aspnet-mvc-2/ gives an example of partial validation