Multiple model binding in single view MVC - c#

I'm new to MVC, please help me out for this.
I have to manage the profile of Employee in my application.So i created 3 model
DetailPersonal(contain field- First Name,Middle Name, Last Name, DOB)
DetailAddress(contain field- AddressLine1,AddressLine2,City,State,etc)
DetailContact(contain field-Primary Mobile no.,Secondary Mobile No, Off. No. etc)
Can i create a single view for these models and do ajax posting.
I want to display these in tabs Like Personal || Address || Contact

The cleanest way would be to create a new class with three properties, and use that as your model.
Or, if you don't want to do that, you could use a list of objects:
#model List<object>
#{
var detailPersonal = Model[0] as DetailPersonal;
var detailAddress = Model[1] as DetailAddress;
var detailContact = Model[2] as DetailContact;
}
And pass all three from the controller:
View(new object[] {MyDetailPersonal, MyDetailAddress, MyDetailContact})
But it could be more prone to error.

This situation is very common where you have defined classes that need to be combined before being presented to the user.
Typically, this is handled by using a View Model to consolidate separate classes into something that can be modified by the end user. Translating between your entity objects and your view models can be done in the constructor for a simple application.
I would look at this:
What is ViewModel in MVC?
Also, if you want to introduce more sophistication, I would read up on the repository pattern, and also look up domain layer. Those two subjects deal with the situation you are facing.

Will the user submit the contents of all three models using a single form (a shared submit button)? I think that makes the most sense, unless there are circumstances that make AJAX necessary. If I'm right about that, here's what you would do.
Create a new model with three model-typed properties. Let's call it CustomerModel.
public class CustomerModel
{
[DisplayName("Address")]
public DetailAddress AddressDetails { get; set; }
[DisplayName("Contact information")]
public DetailContact ContactDetails { get; set; }
[DisplayName("Personal information")]
public DetailPersonal PersonalDetails { get; set; }
}
Then create the editor templates in the framework-defined folder. These contain the editable fields for each model.
~/Views/Shared/EditorTemplates/DetailAddress.cshtml
~/Views/Shared/EditorTemplates/DetailContact.cshtml
~/Views/Shared/EditorTemplates/DetailPersonal.cshtml
Then add the editors to your main form. Something like...
#using (Html.BeginForm())
{
<div id="addressDetailsTab">
#Html.LabelFor(model => model.AddressDetails)
#Html.EditorFor(model => model.AddressDetails)
</div>
<div id="contactDetailsTab">
#Html.LabelFor(model => model.ContactDetails)
#Html.EditorFor(model => model.ContactDetails)
</div>
<div id="personalDetailsTab">
#Html.LabelFor(model => model.PersonalDetails)
#Html.EditorFor(model => model.PersonalDetails)
</div>
<input type="submit" value="Submit" />
}

Related

Error in Multiple Models When Used in a VIEW

I'm trying to get access to multiple models in my view.
I created a ViewModel class and its controller and I imported the model to view but I got this error:
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[LivrinhosMVC.Models.Category]', but this
dictionary requires a model item of type 'LivrinhosMVC.Models.ViewModel'.**
ViewModel Class:
public class ViewModel
{
public List<Category> Categories { get; set; }
public List<Ad> Ads { get; set; }
}
ViewModel Controller:
// GET: ViewModel
public ActionResult Index()
{
ViewModel mymodel = new ViewModel();
mymodel.Categories = db.Categories.ToList();
mymodel.Ads = db.Ads.ToList();
return View(mymodel);
}
View:
#model LivrinhosMVC.Models.ViewModel
<div class="container">
<div class="row" style="margin:2em 0">
<div class="col-sm-4">
#Html.Label("Categorias")
<table class="table-condensed">
#foreach (var item in Model.Categories)
{
<tr>
<td>#Html.ActionLink(item.Name, "../Category/Books", new { id = item.ID }, null)</td>
</tr>
}
</table>
</div>
<div class="col-sm-8" style="display:inline">
#Html.TextBox("BookTitle", null, new { placeholder = "Título...", #class = "form-control" })
#Html.DropDownList("Cities", "Portugal")
#Html.ActionLink("Pesquisar", "Books", null, null, new { #class = "btn btn-primary" })
</div>
<div class="row">
#foreach (var item in Model.Ads)
{
<div class="col-sm-3">
#Html.Label(item.Title)
</div>
}
</div>
</div>
</div>
I'm not sure based on your example code why you would be getting that error, it seems to have an issue with #foreach (var item in Model.Categories).
What I can see, and recommend though, is to follow through with the view model approach, but do not attach entities into the view model. View models should be simple POCO classes that only expose enough detail for the view to consume, nothing more. The reason for this is to help boost performance (less data read and transmitted) and boost security. (no data sent to the client you don't expect them to see, such as exposed in debugging tools, and ensure that Entities are not sent back to the server with unintentional edits, again through debugging tools, trusted, and attached and committed to the context.)
I would suggest creating a CategorySummaryViewModel and an AdSummaryViewModel containing just the ID and Name to start. Mark all view models as Serializable. Then when you populate your ViewModel:
[Serializable]
public class AdsPageViewModel
{
public List<CategorySummaryViewModel> Categories { get; set; } = new List<CategorySummaryViewModel>();
public List<AdSummaryViewModel> Ads { get; set; } = new List<AdSummaryViewModel>();
}
public ActionResult Index()
{
var mymodel = new AdsPageViewModel
{
Categories = db.Categories.Select(x=> new CategorySummaryViewModel
{
Id = x.Id,
Name = x.Name // Append other fields if necessary for the view.
}).ToList(),
Ads = db.Ads.Select(x => new AdSummaryViewModel
{
Id = x.Id,
Name = x.Name
}).ToList()
};
return View(mymodel);
}
This will seem like more code/effort than simply passing the entities. You can leverage a tool like Automapper to simplify this, and utilize .ProjectTo<T> to gain the same benefits as above. These benefits include that by using .Select() the EF SQL statement sent to the database, and data coming back from the database only include the fields our view model needs. Less data over the wire = faster, and less memory needed on the app server and client for the request. It also ensures our view can only ever see the fields we want it to see. Someone using F12 in our client can't inspect other FKs and fields that are hidden only because we don't have controls visible on the page. We also ensure that our application does not accept entities back from the client where the enticement will be to attach them to a context and save them. (seems simple, but vulnerable to hackers altering the entity data using those same debugging tools and corrupting the data saved.)
Give that a go with serializable POCO view models to make up the view's data and see if you still get any exception around rendering the child collections. I suspect if there still is an issue there may be a detail from your code that isn't covered by your example here.
Try eagerly load the data you want to send to the view.
Such as:
public ActionResult Index()
{
var model = db.ViewModel
.Include(c => c.Categories);
.Include(c => c.Ads);
return View(model.ToList());
}
And make the view Strogly typed as:
#model IEnumerable<LivrinhosMVC.Models.ViewModel>

Data Binding in ASP.NET MVC

I know it would be a basic question but I'm a newbie to ASP.Net MVC. I have fetched data from database using LINQ but there is an issue. I wanna bind that data with input fields of a customized webform. (I'm using MVC). I wanna populate the input fields of webform with fetched data. I'm using EF Database first approach.
My Controller and view is attached.
Controller ActionMethod
public class HomeController : Controller
{
public ActionResult Index()
{
AutoRTGSEntities_1 dc = new AutoRTGSEntities_1();
//dc.policies.Where(cb => cb.Section_Key.Contains("SenderBIC"));
return View(dc.policies.Where(cb => cb.Policy_Section.Contains("RTGS")).ToList()); //get RTGS policy section data
}
}
View
#model IEnumerable<Swift_MT_103.policy>
#{
ViewBag.Title = "Home Page";
}
<div> #Model{ #Html.TextBoxFor(x => x.data_Value)) } </div>
<div> <input type="text" name="ReceiverBIC" id="ReceiverBIC" /> </div>
Rest is HTML and CSS. Snap is attached.
Here's a very basic example of how to this. Let's say you have following class:
public class User
{
public int Id { get; set; }
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "E-mailaddress")]
public string E-mail { get; set; }
}
In the controller you get the user:
public ActionResult Index(int id)
{
var user = Db.Users.FirstOrDefault(x => x.Id == id);
if(user != null)
{
return View(user);
}
//Return to the 'Error' view as no user was found
return View("Error");
}
You also need a View to show everything on screen. Make it a strongly typed view, this way you can pass a Model to it. This class will hold all data you want to pass to the view. Code of the view:
//This line lets the view know which class represents the model
#model User
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
Using the Razor syntax instead of plain HTML it is very easy to construct and bind your form elements to the corresponding data. In this case the label will show the value of the Display attribute in the User class and the values of the user will be filled in the textboxes.
More reading:
Getting started with ASP.NET MVC 5
ASP.NET MVC Overview
Update:
In case you have a list of objects, you need to enumerate them in the view:
#model IEnumerable<string>
#foreach (var value in Model)
{
<div>#value</div>
}
And if the model is a class and has a property that is a list:
//Let's say a user has lots of names
public class User
{
public int Id { get; set; }
public List<string> Names { get; set; }
}
//View:
#model User
#Html.TextBoxFor(m => m.Id)
#foreach (var name in Model.Names)
{
<div>#name</div>
}
Try to implement a correct ASP.NET MVC architecture. To get this completed, you'll need to use proper Razor (.cshtml type) Syntax in your Views. Best practice:
Create a dedicated ViewModel class in the Model directory. You might call it CustomerCreditTransferViewModel for example. It should contain all Properties you want to display/edit anywhere on the page.
Once you selected your data from your DBContext in your Action, create an instance of CustomerCreditTransferViewModel and populate all fields from the result.
Update your View to use #model CustomerCreditTransferViewModel instead of Swift_MT_103.policy (believe me, this is going to make your live much easier in future)
Copy-paste your raw HTML Code into the page and start looking for all Fields you want to bind, e.g. Text fields (<input type="text" name="accountno" value="" />) and replace them with the Razor Syntax for Data Binding (#Html.TextBoxFor(x => x.AccountNo)). If done correctly, they should be populated now.
Next step is probably the POST. Follow the base MVC Post technique from the Tutorials. Ensure that the Posted Value is of type CustomerCreditTransferViewModel) again, so you can easily validate values and map back to type of Swift_MT_103.policy.

Getting values of input fields in MVC

I'm a bit new to MVC, and maybe I'm just misunderstanding something, but I can't figure out how to do the following in an elegant way:
I have the following Entity that I wan't updated:
Model:
public class Entity
{
[Key]
public int Id { get; set; }
public DateTime Created { get; set; }
public int FieldInt { get; set; }
public DateTime FieldDate { get; set; }
public int FieldOther {get; set; }
}
}
View:
My view displays a bunch textlines with checkboxes attached. The checkboxes are identified by two data-attributes: data-field-int and data-field-date, which is something along the following.
#html.BeginForm("Confirm", "Home", FormMethod.Post) {
...
<input type='checkbox' data-field-int="1" data-field-date="2014/01/01" />
<input type='checkbox' data-field-int="1" data-field-date="2014/02/02" />
<input type='checkbox' data-field-int="1" data-field-date="2014/03/03" />
...
<button id="ConfirmButton" type="submit" class="btn btn-primary">Confirm</button>
}
What I want in the controller is when the ConfirmButton is pressed, create an Entity object for each checkbox that is checked with the value of fieldInt and fieldDate populated with data-field-int and data-field-date attributes respectively.
I can do it by making the controller action take FormCollection as input and by putting a name attribute on the checkboxes with a concatenation of fieldInt and fieldDate and then seperating them in the controller and updating the db. But it seems like there would be a better way, since MVC is so smart with Entity Framework.
I hope you guys can help me understand
Thank you,
Peter
welcome to MVC .
-Using razor engine with model entities is the best practice.
-In the above mentioned code you need to set something like this
#using ( Html.BeginForm("Confirm", "Home", FormMethod.Post))
-As you are new try using strongly typed views with selected templates which generates razor code for you i.e you can analyse deep
-Finally just use model x as parameter to you [HttpPost] action method and convert these entities to you Entity framework entities and save in DB
Additionally :
Data attributes are not included in the data that's posted with the form, so there is no way to read them in your controller action. Try using a hidden field instead
Like
#Html.HiddenFor(m => m.FieldInt) or
<input type="hidden" name="FieldInt" value="1234" />//do similarly for rest
Passing static then #{Model.phoneno = "1234"}
This question consists of two parts:
1.
It is good to specify #model in razor view and use helper methods that take lambda expressions with the model as parameter.
#model MyType
html.Textbox(model => model.FieldOther,...)
Then you create action that takes the model
[HttpPost]
ActionResult MyAction(MyModel model) {
....
}
Mvc will try to create instance of the model and map form fields to the model properties.
2.
You can use entity as model but, believe me, so called Data transfer Objects and/or View Models were created for a reason and as application evolves, single views evolve too to manipulate data from many related database entities.

Should I be using hidden fields to preserve model fields between Edit and Save in ASP.Net MVC?

I'm new to MVC and am attempting to adhere to best practices.
I'm creating an edit/save form for contacts using an existing data project with several classes I need to load and save together on one form.
For the contact, I need to load a Person's name, company details, phone #s, address fields, etc.. Each of these is a separate class in the data project, but I want to edit and save within one view/model. The issue is that I seem to have to put all the necessary PK and FK IDs on my view as Hidden fields, and it feels like there should be a better way to do it...
For my model, I use existing data class objects as the fields:
public class ContactEditModel
{
public Person PersonObjectName { get; set; }
public Company CompanyObjectName { get; set; }
public Address AddressObjectName { get; set; }
....
}
I instantiate an object for each of these and load them within my model, and I want to save any changes on submission of the Edit view.
Since I already have load and save methods for these classes (as well as stored procedures to do the work) in the existing data project, it seemed to make sense to re-use the code rather than specifying all the fields on the model and re-writing code.
However, without declaring all the hidden fields on the view, the IDs (person, company, address, etc.) aren't preserved in the model when saving, thus I have to specify each field I want preserved in a Hidden item.
The hidden fields code example is below:
#Html.HiddenFor(model => model.PersonObjectName.ID)
#Html.HiddenFor(model => model.PersonObjectName.Version)
#Html.HiddenFor(model => model.PersonObjectName.CompanyID)
#Html.HiddenFor(model => model.AddressObjectName.ID)
#Html.HiddenFor(model => model.AddressObjectName.AddressTypeID)
#Html.HiddenFor(model => model.AddressObjectName.Version)
.....
Any ideas on a better way to do this would be greatly appreciated.
Thanks.
The answer to this kind of question is always "it depends" and much of it is based on personal preference, or how you are doing things.
For instance, I prefer not to include all those ID's, but rather have a single parent id which I can then use to lookup the other ID's on POST. This means you only need to save one hidden field (or even just have it be part of the url, so no hidden necessary). In your case, probably the PersonObjectName.ID.
If you'd rather not do another lookup, then you can include those ID's, however you need to consider whether or not this is sensitive information. For instance, what happens if someone uses Fiddler to change the Address id to something else? You now have to add logic to ensure that the user isn't allowed to update addresses that are not linked to his id.
For things like this I normally use TempData.
TempData is basically session, but its only available for one request.
So on the Edit get method I will put whatever IDs I need to store into TempData and then read them out when the form is posted.
You can follows the steps as follows:
Designing the model :
public class ContactEditModel
{
public string PersonObjectName { get; set; }
public string CompanyObjectName { get; set; }
public string AddressObjectName { get; set; }
....
}
Create strongly type views :
#model MyModels.ContactEditModel //Model Namespace
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.PersonObjectName )
#Html.TextBoxFor(m => m.CompanyObjectName )
#Html.TextBoxFor(m => m.AddressObjectName )
#Html.ValidationMessageFor(m => m.Password)
<input type="submit" value="Log In" />
}
Working with Action
public ActionResult Edit(ContactEditModel model)
{
return View(model);
}
[HttpPost]
public ActionResult Edit(ContactEditModel model)
{
// Implementation
// model will have all updated values from UI
return View(user);
}

Set a default value for a dropdownlist from a list coming from another controller

I have this web page which shows the property of an object so that I may edit it, and I populate a DropDownListwith strings coming from another class.
Here's the method I use to populate the DropDownList:
private void PopulateOBJSetDropdownList(object selectedobj = null)
{
List<string> listOBJSetName = m_OBJSetManager.GetListOBJSets().OrderBy(x => x.m_Name)
.Select(x => x.m_Name.ToString())
.Distinct()
.ToList();
ViewBag.objSetID = new SelectList(listOBJSetName );
}
The ViewBagproperty does its job quite well, but the list comes empty when editing the item.
I'm pretty sure it is because of this line:
<div class="editor-label">
#Html.LabelFor(model => model.m_OBJSetID, "Obj Set")
</div>
<div class="editor-field">
#Html.DropDownList("objSetID ", String.Empty)
#Html.ValidationMessageFor(model => model.m_OBJSetID)
</div>
Because the dropdownlist is populated with String.Empty. This comes from a controller of objs.
Basically, I want this DropDownList to show me all the names of the objSets available, but I would also want it to have the correct objSet selected by default when editing an obj.
Does anyone can help? Am I clear enough? Thank you everyone.
i would avoid the viewbag. you might want to create a view model, and pass that instead.
but this can be done with the viewbag as well.
first, on your view, i would change your dropdown to the following
#Html.DropDownListFor(model => model.m_OBJSetID, DDLSelectitemListGoesHere)
if you do a view model, you can contain everything this page needs to use in one class, and send it to the view
public class MyViewModel{
public List<YourModel> theModel { get; set; }
public IEnumerable<SelectListItem> DDLItems { get; set; }
}
then on your view, at the top
#model PROJECTNAME.NAMESPACE.MyViewModel
and you can fill in the drop down like so
#Html.DropDownListFor(model => model.theModel.m_OBJSetID, model.DDLItems)
hopefully one of those will get you through

Categories

Resources