How to use one model property in another view model? - asp.net-mvc-4

I have 2 model classes contactdetails.cs and empmodel.cs
I have a view called empdetails.cshtml and the model i am using for this page is empmodel.cs.
I want to use a property Mobile from contactdetails.cs
Can I use like this in mvc?
#Html.TextBoxFor(m=>m.contactdetails.Mobile)

No. Since you are using empmodel for this view you cannot do it.
What you can you do is create a ViewModel with with contactdetails and empmodel and use that ViewModel in your view.
e.g.
public class EmpViewModel
{
public EmpModel Empmodel { get; set; }
public ContactDetails contactdetails { get; set; }
}
And in your view empdetails.cshtml you can use it as follow;
#model EmpViewModel
#Html.TextBoxFor(m => m.contactdetails.Mobile)

Related

Null viewmodel passed to controller

I have a basic 'create' view scaffolded from a domain model, so it is typed to the model
#model TblProduct
<form asp-controller="Product" asp-action="Create">
...
<input asp-for="Artist" class="form-control" />
...
I'm trying to add functionality and use a view model instead, and I'm starting with a very basic viewmodel with only that domain model within it:
public class ProductViewModel
{
public TblProduct P { get; set; }
}
Now I've changed the 'create' view to use the view model instead
#model ProductViewModel
<form asp-controller="Product" asp-action="Create">
...
<input asp-for="P.Artist" class="form-control" />
...
So I expect the model to be valid given that (aside from editing the variable names) I'm populating all the same fields from the form, and effectively no other fields have been added to the model.
An error occurs when I post the form, I pass a ProductViewModel parameter to the create method but on inspection it is null. However ModelState.IsValid is true. So the code tries to write to the db and fails.
public async Task<IActionResult> Create([Bind("ID,Artist,ProductTitle... (long list removed)...] ProductViewModel productAndItems)
{
var prod = productAndItems.P;
if (ModelState.IsValid)
{
_context.Add(prod);
...FAIL
Any idea what I should be checking here - what am I missing?
How do I get the view (typed to a viewmodel) to pass the model data to the controller? And if it's null, how can ModelState.IsValid be true? In the example above I have debugged, the parameter passed in productAndItems is null.
Your current Bind attribute is looking for the following properties ID,Artist,ProductTitle... (White-list) and it's not finding them so therefore it's ignore everything and treating it is as a (Black-list) item.
You can either decorate your ProductViewModel with the Bind attribute as follows:
[Bind(Include = "P")]
public class ProductViewModel
{
public TblProduct P { get; set; }
}
This will of course mean all the properties in the TblProduct will be bound when submitting
If you do not want all of the properties to be bound on submit for TblProduct then you can decorate the TblProduct with the Bind attribute as follows
public class ProductViewModel
{
public TblProduct P { get; set; }
}
[Bind(Include = "ID,Artist,ProductTitle")]
public class TblProduct
{
public int ID { get; set; }
public string Artist { get; set; }
public string ProductTitle { get; set; }
public string ProductSubTitle { get; set; } //we will not include this in our (White-list)
//more props
}
More reading at MSDN
you need to add a name attribute to your form so the controller will pick it up.

asp.net mvc4 create subform to add multiple adresses for user during the registration

In my asp.net mvc4 app I want to allow users to add multiple regions and cities to their account during the registration. I want to add some subform in which would be the dropdownlist for Region and City and the user should be able to add multiple regions and cities during the registration Process. I know how to do this with jquery but I want to use view model for validation and for creation of this registration form but I do not know how to create this view model and how to define this form in view. I am stating my current registration view model and I want to ask if You can help me to modify it so it will work as I need.
public class RegisterUserModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
public string Password { get; set; }
[DataType(DataType.Password)]
public string ConfirmPassword { get; set; }
[Required]
[Display(Name = "Email")]
public string Email { get; set; }
}
Thank you.
You will need to add a collection to your view model that will contain the Regions and Cities. You should create another type to encapsulate these two properties, say Place, so your View Model will look like this:
public class RegisterUserModel
{
// other properties
public List<Place> Places { get; set; }
}
public class Place
{
public string Region { get; set; }
public string City { get; set; }
}
To display the current places in the View Model you simply iterate over them with a foreach and use the helpers to display the Region and City for each one. To add a new Place the key is to name the input correctly so the default Model Binder will treat it as an item in the collection. The default Model Binder uses indexes to do this. For example, the inputs for the first Place in the Places collection should be named like this:
<input name="Places[0].Region" />
<input name="Places[0].City />
The next Place in the collection would be [1] and so on. Since you are familiar with jQuery I will skip how these can be added to the DOM.

Enumerable objects in ViewBag in MVC4

I have the below model say F:
public partial class F
{
[Key, Display(Name = "Id")]
public int FId { get; set; }
public int RId { get; set; }
public int FTId { get; set; }
public string C { get; set; }
public string U { get; set; }
public string D { get; set; }
[ScaffoldColumn(false)]
public System.DateTimeOffset Created { get; set; }
}
In the controller I have to read all the records of 'F' from database and assign those to an enumerable list of records.
For ex:
ViewBag.Cs = enumerable C column items (textbox)
ViewBag.Us= enumerable U column items (textbox)
ViewBag.FTIDs = enumerable FTId column items (this has to be a dropdown)
In my I have to show
#Html.Textbox(Cs);
#Html.Dropdown(FTIDs);
I gave only textbox and dropdows as an example, there could be many other controls like datetimes, checkboxes etc.,
I should be able to written each column as list a in viewbag and show it in MVC View.
Can somebody advise if this achievable and how?
Many thanks...
Don't use a viewbag for something like this - instead strongly bind your view to a model. Only use a view bag if you have something really small to pass.. anything complex you should always use a strongly typed view model, you get intellisence and its must cleaner for unit testing
View Model:
Public class MyViewModel
{
public List<F> MyListOfFObjects { get; set; }
}
Now when you create your view you can bind it to this view model in the popup or if you don't want to recreate it simply add a reference to it at the top of your view like so:
#model <your project>.<folder view model is in>.<view model name>
for example
#model AdventureWorks.Models.EmployeeViewModel.
In your controller you simply create this view model and pass it to your view such as:
public ActionResult Index()
{
MyViewModel vm = new MyViewModel();
// Initialize your view model
// Get all the F objects from the database and populate the list
return View(vm); // now your view will have the view model
}
Now in the view you can iterate through this view model
#foreach(var fObject in Model)
{
#Html.TextBoxFor(m => m.fId)
#Html.TextBoxFor(m => m.rID)
}
Here is a link to a list of the different #Html helpers that you can use btw
http://qkview.com/techbrij/aspnet-mvc-4
Reference for strongly binded views:
http://www.asp.net/mvc/tutorials/views/dynamic-v-strongly-typed-views

MVC Validation on Model in Portable Class Library

I am new to MVC but have worked my way through the validation tutorials and they do exactly what I want to do... but.... my model is in a separate portable class library.
How would I add the validation rules to this non-MVC solution so that my MVC website?
Is it possible please?
Thanks
You can create an interface to that class and use impromptu interface to have your class act as that interface...
Lets say this is the class from the portable library:
public class SomeClass
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Create a cloned interface and specify validation attributes in it:
public interface ISomeClass
{
[Required]
string FirstName { get; set; }
string LastName { get; set; }
}
At the top of your view, pass the interface instead of the class:
#model YourNamespace.Models.ISomeClass
In your controller, do:
return View(instanceOfSomeClass.ActLike<ISomeClass>();
You can find impromptu interface here:
http://code.google.com/p/impromptu-interface/
Since the class and the interface look exactly the same, model binding works as well.
Hope this helps.

How to AccessSimpleMemberShipprovider properties of current user ASP.net MVC4

I have a razor .cshtml view in MVC4 and I want to print a field of my userprofile class. I understand I can get the Username from User.Identity.Name but I don't know how to access the other properties of the currently logged in user in the partial. Do I need to do this in my controller and reference it in my view? If so is there a controller that is available to all views so I am not setting this variable in every controller? Is there a simple way to access the current users properties as defined in the UserProfile model class right in the view? To give some context. I have my model as...
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
//Added to round out requirements for site user profile
public string FirstName { get; set; }
public string LastName { get; set; }
public string Site { get; set; }
}
I need to access the FirstName in the view. If I get it in the controller then I will need to do it in all controllers since this is a page partial for all pages.
I decided to put it in a session variable since it is not critical, sensitive, or effects the stability of the application. In my controller on login or registration I set the session variable with...
var context = new UsersContext();
var curuser = context.UserProfiles.First(p => p.UserName == model.UserName);
Session["FName"] = curuser.FirstName;
I got this from Pro ASP.NET MVC and from this post. And in my Razor view I use this derived from this post.
#HttpContext.Current.Session["FName"].ToString()
In the controller action that is serving the partial view put FirstName in the ViewBag.
If there are more properties that you would like to return then create a ViewModel for them and make the controller action return that.