How do I use editortemplates in MVC3 for complex types? - asp.net-mvc-3

I have two classes, Vat and Product. Product has a property of IVat. I am trying to use editor templates in MVC to display a dropdown list of all the Vat objects when creating/editing a Product. For the dear life of me I cannot get this working.
I have the following code which displays the dropdown but it does not set the Vat for the Product when the form gets submitted.
Controller:
IList<IVatRate> vatRates = SqlDataRepository.VatRates.Data.GetAllResults();
ViewBag.VatRates = new SelectList(vatRates, "Id", "Description");
Add.cshtml
#Html.EditorFor(model => model.VatRate.Id, "VatSelector", (SelectList)ViewBag.VatRates)
VatSelector.cshtml
#model SelectList
#Html.DropDownList(
String.Empty /* */,
(SelectList)ViewBag.Suppliers,
Model
)
I would be grateful if anyone can shed some light on this or even point me to a good example on the web somewhere...I have been stuck with this for quite a few days now.

I would use strongly typed views and view models as it makes things so much easier rather than ViewBag.
So start with a view model:
public class VatRateViewModel
{
public string SelectedVatRateId { get; set; }
public IEnumerable<IVatRate> Rates { get; set; }
}
then a controller:
public class HomeController: Controller
{
public ActionResult Index()
{
var model = new VatRateViewModel
{
Rates = SqlDataRepository.VatRates.Data.GetAllResults()
};
return View(model);
}
[HttpPost]
public ActionResult Index(VatRateViewModel model)
{
// model.SelectedVatRateId will contain the selected vat rate id
...
}
}
View:
#model VatRateViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(
x => x.SelectedVatRateId,
new SelectList(Model.Rates, "Id", "Description")
)
<input type="submit" value="OK" />
}
And if you wanted to use editor template for the VatRateViewModel you could define one in ~/Views/Shared/EditorTemplates/VatRateViewModel.cshtml:
#model VatRateViewModel
#Html.DropDownListFor(
x => x.SelectedVatRateId,
new SelectList(Model.Rates, "Id", "Description")
)
and then whenever somewhere you have a property of type VatRateViewModel you could simply:
#Html.EditorFor(x => x.SomePropertyOfTypeVatRateViewModel)
which would render the corresponding editor template.

Related

Getting Null value of date in controller from view by using view model

I am new to MVC. I am facing problem to get Date of birth value from view into controller by using view model. I am using view model for getting form values and getting all other textboxes values. But I always get null value for date.
My view model is like this.
public class Student
{
[Required(ErrorMessage = "Date of birth is required")]
[DataType(DataType.Date), DisplayFormat(ApplyFormatInEditMode = true,DataFormatString = "{0:dd/MM/yy}",ConvertEmptyStringToNull=false)]
public DateTime? DateOfBirth { get; set; }
}
My controller which is called after form posting is:
[HttpPost]
public ActionResult StudentPersonalReg(Student stud)
{
DateTime? dateofbirth = stud.DateOfBirth;
return RedirectToAction("Registration");
}
My view is
#model eEducation.Models.UserModel.Student
#Html.TextBoxFor(x => x.DateOfBirth)
#Html.ValidationMessageFor(x => x.DateOfBirth)
Problem is that I always get null value for date in controller.
I have also tried setting DateTime.Now to the viewmodel when I am calling the view from controller.
I am not using strongly typed view.
Please help me in this regard.
I am passing my model to view by controller method
public ViewResult Registration()
{
var db = new eEducationEntities();
List<CountryMaster> queryCountry = db.CountryMasters.ToList();
List<StateMaster> queryState = db.StateMasters.ToList();
Student stds = new Student();
stds.Countries = queryCountry;
stds.States = queryState;
stds.DateOfBirth = DateTime.Now;
return View("~/Views/UserSection/StudentRegistration.cshtml", stds);
}
You need to be using a Html.BeginForm() on your view model. You can even specify the controller action it posts back to.
#model eEducation.Models.UserModel.Student
#using (Html.BeginForm("StudentPersonalReg", "ControllerName")) {
#Html.ValidationSummary(true)
#Html.TextBoxFor(x => x.DateOfBirth)
#Html.ValidationMessageFor(x => x.DateOfBirth)
<p>
<input type="submit" value="Submit" />
</p>
}

how do I build a composite UI in MVC3?

I understand how to use Partial Views, and I understand Ajax.ActionLink and Ajax.BeginForm when it comes to how to set those up in the view. I'm assuming each partial view has it's own controller. I'm thinking bounded context here, as in each partial view could talk to it's own bounded context via its own controller
I guess the piece I'm missing is:
how to have partial views included in a "master view" (or holding view) and have each of these partial views independently post to a separate controller action, and then return to refresh the partial view WITHOUT loading the "master view" or holding view.
the "master" view or holding view still needs to have its own controller, I want to keep the master controller from reloading its view, and let the view that is produced by an action method of the master controller hold a reference to these two partial views.
There are two approaches it seems I can take, one is to use the "Ajax." functionality of MVC3, the other is to use straight-up jQuery and handle all this interaction by hand from the client side.
Is what I'm trying to do possible both ways, or is one way "better suited" to this type of composite ui construction?
So far, the only things I have seen are trivial examples of composite ui construction like a link via an Ajax.ActionLink that refreshes a single on the page, or a form written as an Ajax.BeginForm that repopulates a div with some content from a partial view.
Okay, so I finally have some working code that I think is the right way to do it. Here is what I went with. I have a two simple "entities"; Customer and BillingCustomer. They're really meant to be in separate "bounded contexts", and the classes are super-simple for demostration purposes.
public class Customer
{
public Guid CustomerId { get; set; }
public string Name { get; set; }
}
public class BillingCustomer
{
public Guid CustomerId { get; set; }
public bool IsOverdueForPayment { get; set; }
}
Note that both classes reference CustomerId, which for the sake of this demo, is a GUID.
I started with a simple HomeController that builds a ViewModel that will be utilized by the Index.cshtml file:
public ActionResult Index()
{
var customer = new Customer {
CustomerId = Guid.Empty,
Name = "Mike McCarthy" };
var billingCustomer = new BillingCustomer {
CustomerId = Guid.Empty,
IsOverdueForPayment = true };
var compositeViewModel = new CompositeViewModel {
Customer = customer,
BillingCustomer = billingCustomer };
return View(compositeViewModel);
}
The CompositeViewModel class is just a dumb DTO with a property for each domain entity, since the partial views I'll be calling into in my Index.cshtml file each need to pass their respective domain model into the partial view:
public class CompositeViewModel
{
public BillingCustomer BillingCustomer { get; set; }
public Customer Customer { get; set; }
}
Here is my resulting Index.cshtml file that uses the Index method on the HomeController
#model CompositeViews.ViewModels.CompositeViewModel
<h2>Index - #DateTime.Now.ToString()</h2>
<div id="customerDiv">
#{Html.RenderPartial("_Customer", Model.Customer);}
</div>
<p></p>
<div id="billingCustomerDiv">
#Html.Partial("_BillingCustomer", Model.BillingCustomer)
</div>
A couple things to note here:
the View is using the CompositeViews.ViewModels.CompositeViewModel ViewModel
Html.RenderPartial is used to render the partial view for each
entity, and passes in the appropriate entity. Careful with the
syntax here for the Html.Partial call!
So, here is the _Customer partial view:
#model CompositeViews.Models.Customer
#using (Ajax.BeginForm("Edit", "Customer", new AjaxOptions {
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "customerDiv" }))
{
<fieldset>
<legend>Customer</legend>
#Html.HiddenFor(model => model.CustomerId)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
the important part here is the Ajax.BeginForm call. Note that it's explicitly calling the Edit ActionMethod of the CustomerController. Also note that the UpdateTargetId is set to "customerDiv". This div is NOT in the partial view, but rather in the "parent" view, Index.cshtml.
Below is the _BillingCustomer view
#model CompositeViews.Models.BillingCustomer
#using (Ajax.BeginForm("Edit", "BillingCustomer", new AjaxOptions {
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "billingCustomerDiv" }))
{
<fieldset>
<legend>BillingCustomer</legend>
#Html.HiddenFor(model => model.CustomerId)
<div class="editor-label">
#Html.LabelFor(model => model.IsOverdueForPayment)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.IsOverdueForPayment)
#Html.ValidationMessageFor(model => model.IsOverdueForPayment)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Again, note that UpdateTargetId is set to billingCustomerDiv. This div is located in the Index.cshtml file, not this partial view file.
So, the only thing we haven't looked at yet is the Edit ActionResult on the CustomerController and the BillingCustomerController. Here is the CustomerController
public class CustomerController : Controller
{
[HttpGet]
public PartialViewResult Edit(Guid customerId)
{
var model = new Customer {
CustomerId = Guid.Empty,
Name = "Mike McCarthy"};
return PartialView("_Customer", model);
}
[HttpPost]
public ActionResult Edit(Customer customer)
{
return PartialView("_Customer", customer);
}
}
There is nothing really "happening" in this controller, as the post deals directly with building a composite UI. Notice how we're returning via "PartialView" and specifying the name of the partial view to use, and the required model the view needs to render.
Here is BillingCustomerController
public class BillingCustomerController : Controller
{
[HttpGet]
public PartialViewResult Edit(Guid customerId)
{
var model = new BillingCustomer {
CustomerId = Guid.Empty,
IsOverdueForPayment = true };
return PartialView("_BillingCustomer", model);
}
[HttpPost]
public PartialViewResult Edit(BillingCustomer billingCustomer)
{
return PartialView("_BillingCustomer", billingCustomer);
}
}
Again, the same as CustomerController, except for the fact that it's this controller is dealing with the BillingCustomer entity.
Now when I load up my HomeController's Index ActionResult, I get a screen that looks like this:
Each Save button will do an async postback to the controller the partial view needs to update and talk to in order to get data, all without causing a regular postback for the whole page. You can see the DateTime stamp does NOT change when hitting either save button.
So, that's how I went about building my first composite view using partial views. Since I'm still very new to MVC3, I could still be screwing something up, or doing something in a way that is harder than it needs to be, but this is how I got it working.

Razor view dropdown list for a model class in MVC3

I have two model class in MVC3 one for Services which have those properties
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public int ChildOf { get; set; }
It also have a DB table by Entityframework
Another model is Quata which have those properties
public int ID { get; set; }
public string Sender_Name { get; set; }
public string Description { get; set; }
.....
......
public Services Service_ID { get; set; }
It also have a DB table by Entityframework
I want to create a Razor(C#) view (for Quata) where user can send a quata by fill a html form but where i wanna show a dropdown list with Services ID as dropdown value and Services Name as dropdown text which is also come dynamically from the Services DB table .
My question is how i should create that dynamic dropdown list by #Html.DropDownListFor ? and send the selected data from that dropdown list to a Controller ?
Try this
Controller:
public ActionResult Create()
{
var Services = new Services();
Services.Load(); //load services..
ViewBag.ID = new SelectList(Services.ToList(), "Id", "Name");
return View();
}
[HttpPost]
public ActionResult Create(Quata Quata)
{
//save the data
}
A strong Typed View: (Using Razor)
#model Quata
#using (Html.BeginForm()) {
<fieldset>
<legend>Quata</legend>
<div>
#Html.LabelFor(model => model.Service_ID.ID, "Service")
</div>
<div>
#Html.DropDownList("ID", String.Empty)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
take a look at #Html.DropDownListFor
So say your viewmodel has a list of said Services.
Something that may work for you is the following (you may not need a for loop here, editor is supposed to eliminate that, but I had some weird binding issues).
In your top level view which points at your viewmodel (#model Quata, assuming Quata is your viewmodel) have this code :
#For i = 0 To Model.DropdownListInput.Count - 1
Dim iterator = i
#Html.EditorFor(Function(x) x.DropdownListInput(iterator), "EnumInput")
Next
In your Editor Template (create a subfolder under the view folder this dropdownlist will be in called editor templates and name the template whatever you desire, mine was EnumInput).
In your editor template, which should point at your model for Services (#model Services) have something like the following code (with substitutions for your appropriate variable names):
#<div class="editor-label">
#Html.LabelFor(Function(v) v.value, Model.DisplayName)
</div>
#<div class="editor-field">
#Html.DropDownListFor(Function(v) v.value, New SelectList(Model.ParamEnums, "ValueForScript", "EnumValue"), "--Please Select A Value--")
#Html.ValidationMessageFor(Function(v) v.value)
</div>
Replace the list with your list and the lambda values with yours (#Html.DropDownListFor(x => x.id, New SelectList(x.ServiceList, "ID", "Name"), "--Please Select A Value--") or something like that.
Note that this code is in VB, but it should provide a rough guide.

Sending new order back to MVC controller

using the JQuery sortable, and trying to send the new order back to my controller, but not having a whole lot of luck. My view is:
using (Ajax.BeginForm("EditTickerOrder", new AjaxOptions { InsertionMode = InsertionMode.Replace, HttpMethod = "POST", }))
{
<div id="editableticker">
#Html.HiddenFor(m => m.ProjectGUID)
<ul id="sortablediv">
#foreach (DGI.CoBRA.Tools.BussinessObjects.CollabLibrary.TickerObjects.Ticker t in Model)
{
<li class="ui-state-default" id="#t.pKeyGuid.ToString()">
<p>#Html.CheckBox(t.pKeyGuid.ToString(), t.Display, new { #class = "activechk" })
<span style="font-weight: bold">
#t.Text
</span>
</p>
</li>
}
</ul>
<input type="submit" value="Save New Ticker Order" />
}
and my controller is:
[HttpPost]
public ActionResult EditTickerOrder(Guid ProjectGUID, List<string> items)
{
TickerCollectionModel TickerData = new TickerCollectionModel();
TickerData.ProjectGUID = ProjectGUID;
TickerData.ListAllBySession(ProjectGUID);
return PartialView("TickerList", TickerData);
}
yet the list<string> items is always null. Any ideas?
You are writing foreach loops, most definitely violating the naming conventions for your form input fields that the default model binder expects for working with collections. If you don't respect the established wire format, you cannot expect the default model binder to be able to rehydrate your models in the POST action.
In fact, why don't you use view models and editor templates? They make everything trivial in ASP.NET MVC.
So let's define a view model that will reflect your view requirements (or at least those shown in your question => you could of course enrich it with additional properties that you want to handle):
public class TickerViewModel
{
public Guid Id { get; set; }
public bool IsDisplay { get; set; }
public string Text { get; set; }
}
public class ProjectViewModel
{
public Guid ProjectGUID { get; set; }
public IEnumerable<TickerViewModel> Tickers { get; set; }
}
and then a controller whose responsibility is to query your DAL layer, retrieve a domain model, map the domain model into the view model we defined for this view and pass the view model to the view. Inversely, the POST action receives a view model from the view, maps the view model back into some domain model, passes the domain model to your DAL layer for processing and renders some view or redirects to a success action:
public class HomeController : Controller
{
public ActionResult Index()
{
// TODO: those values come from a data layer of course
var model = new ProjectViewModel
{
ProjectGUID = Guid.NewGuid(),
Tickers = new[]
{
new TickerViewModel { Id = Guid.NewGuid(), Text = "ticker 1" },
new TickerViewModel { Id = Guid.NewGuid(), Text = "ticker 2" },
new TickerViewModel { Id = Guid.NewGuid(), Text = "ticker 3" },
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(ProjectViewModel model)
{
// Everything will be correctly bound here => map the view model
// back into your domain model and pass the domain model to
// your DAL layer for processing ...
return Content("Thanks for submitting");
}
}
a view (it is worth noting that in this example I have used a standard form instead of AJAX but it is trivial to convert it into an AJAX form):
#model ProjectViewModel
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.ProjectGUID)
<div id="editableticker">
<ul id="sortablediv">
#Html.EditorFor(x => x.Tickers)
</ul>
</div>
<button type="submit">OK</button>
}
and finally the corresponding editor template which will automatically be rendered for each element of the Tickers collection (~/Views/Home/EditorTemplates/TickerViewModel.cshtml):
#model TickerViewModel
<li class="ui-state-default">
<p>
#Html.CheckBoxFor(x => x.IsDisplay, new { #class = "activechk" })
#Html.LabelFor(x => x.IsDisplay, Model.Text)
#Html.HiddenFor(x => x.Text)
#Html.HiddenFor(x => x.Id)
</p>
</li>

How to handle Dropdownlist in mvc asp .net

this is my Model1 class
namespace chetan.Models
{
public class Model1
{
public string selectedItem { get; set; }
public IEnumerable<SelectListItem> items { get; set; }
}
}
this is my controller class
public class HomeController : Controller
{
private rikuEntities rk = new rikuEntities();
public ActionResult Index()
{
var model = new Model1
{
items = new[]
{
new SelectListItem { Value = "Theory", Text = "Theory" },
new SelectListItem { Value = "Appliance", Text = "Appliance" },
new SelectListItem { Value = "Lab", Text = "Lab" }
}
}; return View(model);
}
public ActionResult viewToController(Model1 m)
{
string getSelectedName = m.selectedItem;
return Content(getSelectedName);
}
}
this is my view...
#using (Html.BeginForm("viewToController", "Home"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>emp</legend>
<div class="editor-field">
#Html.DropDownListFor(x => x.selectedItem,
new SelectList(Model.items, "Value", "Text"))
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
i want to add a drop downlist and i want to use selected value in viewToController action of homeController. and there is also one error in View page is "an expression tree may not contain dynamic operation" in (x=>x.selectedItem). Please solve my problem .
I don't understnad what you exactly need. You want to dynamicly add items to the drop down from the database?
I'm big fan of jQuery. You can do everything what you want with HTML using jQuery. So if you are looking how to automaticly add items to the drop down, take look at this: How do I add options to a DropDownList using jQuery?

Resources