I am trying to create a search page, which searches the details of the user based on the Username. My problem is I am not able to create a strongly typed text box for the search box. I created a Model view and in spite of that I am unable to fix my issue. My View is not able to even compile properly, I am guessing I am going wrong with the Model which binds the view to make it strongly typed. I wish to have 2 text boxes for username and phone number, if the user enters anything inside either of the text box it should return the matching user profile.
This is the View Model:
public class UserSearchViewModel
{
public string userName { get; set; }
public string phoneNum { get; set; }
public IEnumerable<User> user { get; set; }
}
Action method:
public ActionResult Search(UserSearchViewModel mod)
{
IEnumerable<User> u1 = null;
u1 = db.Users.Where(p => p.UserName.Contains(mod.userName) || p.PhoneNum.Contains(mod.phoneNum));
return View(u1);
}
View:
#model HindiMovie.Models.UserSearchViewModel
#using( Html.BeginForm("Search", "User", FormMethod.Get))
{
#Html.TextBox("UserName")
}
<table>
<tr>
<th>#Html.DisplayNameFor(model => model.UserName)</th>
<th>#Html.DisplayNameFor(model => model.FirstName)</th>
<th>#Html.DisplayNameFor(model => model.LastName)</th>
<th>#Html.DisplayNameFor(model => model.PhoneNum)</th>
<th></th>
</tr>
#foreach (var item in Model.user) {
<tr>
<td>#Html.DisplayFor(modelItem => item.FirstName)</td>
<td>#Html.DisplayFor(modelItem => item.LastName)</td>
<td>#Html.DisplayFor(modelItem => item.UserName)</td>
</tr>
}
</table>
A way to go would be to create a wrapper class
public class UserSearchViewModel
{
public string UserName {get;set;}
public string PhoneNumber {get;set;}
public IEnumerable<User> Users {get;set;}
}
The model would be UserSearchViewModel instead of IEnumerable and your foreach would loop through Model.Users instead Model.
This and this are a couple of articles detailing the use of ViewModels (an arbitrary class that exists solely to provide data for a view) vs. using your Enity/Database models directly in the view.
Inside the form element, use
#Html.TextBoxFor(m => m.userName )
#Html.TextBoxFor(m => m.phoneNum)
But the reason you view wont compile is because you model does not contain a properties UserName, FirstName etc so you cannot use #Html.DisplayNameFor(m => m.UserName) in your table headings.
Either hard code them
<th>User name</th>
or use
<th>#Html.DisplayNameFor(m => m.user.FirstOrDefault().UserName)</th>
Note that the collection does not need to contain any items for this to work.
Related
In my code I cannot read a nested object value on form post.
Wrog way to edit List property in one Object:
#{
var contatore = 0;
foreach (var item in Model.Movimenti)
{
var movimento = item;
<tr>
<td align="left">
#*Imposto gli Hidden per tutte le proprietà che devo recuperare al post*#
#Html.HiddenFor(x => movimento.Prodotto.Descrizione, "Movimenti[" + contatore + "].Prodotto.Descrizione")
#Html.DisplayFor(x => movimento.Prodotto.Descrizione, "Movimenti[" + contatore + "].Prodotto.Descrizione")
</td>
<td>#Html.EditorFor(x => movimento.Aum, "CurrencyDisabled", "Movimenti[" + contatore + "].AUM")</td>
</tr>
contatore++;
}
}
This is the correct way to edit List property in one Object:
The code:
#using AI.Business.Models
#model Operazione
#{ ViewBag.Title = "Simulatore"; }
#using (Html.BeginForm("CreaOperazione", "Operativita", FormMethod.Post))
{
// Imposto gli Hidden per tutte le proprietà che devo recuperare al post
#Html.HiddenFor(x => x.RapportoModel.TipoRapportoId)
<table width="100%" class="display" id="Simulatore" cellspacing="0">
<thead>
<tr>
<th class="dt-head-left">Linea</th>
<th>AUM</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(x => x.Movimenti)
</tbody>
</table>
<button id="btnSalva" name="btnSalva" type="submit" style="float: right;">Salva Operazione</button>
}
With the editor assuggested:
#model AI.Business.Models.Movimento
<tr>
<td align="left">
#Html.HiddenFor(x => x.Prodotto.Descrizione)
#Html.DisplayFor(x => x.Prodotto.Descrizione)</td>
<td>#Html.EditorFor(x => x.Aum, "CurrencyDisabled")</td>
And this is my object:
public class Movimento
{
public int Id { get; set; }
public ProdottoModel Prodotto { get; set; }
public decimal Aum { get; set; }
}
And the Object Prodotto:
public class ProdottoModel
{
[Key]
public int ID { get; set; }
public string Descrizione { get; set; }
}
In my Actionresult the property Descrizione is null:
[HttpPost]
public ActionResult CreaOperazione(Operazione operazione)
{
if (ModelState.IsValid)
{
// Do something
}
else
ImpostaErrore(ModelState);
return View("PaginaSimulatore", operazione);
}
Open the images:
At my first access to the page the property Prodotto.Descrizione is populated
When i raise the form post event this property was sent with a null value
I'm not sure how you're getting any of this to work, but it's a total fluke. HiddenFor, for example, has no parameter that let's you specify the name value for the field. Instead, where you're trying to do that, the parameter is actually for htmlAttributes, which expects either an anonymous object or IDictionary. The only reason you aren't getting errors is because string is technically an object, but it will never do anything in this context.
The same goes for the rest of your helper calls. With EditorFor, in particular, the second param where you're passing "CurrencyDisabled", is for specifying the editor template that should be used, and the third param is for additionalViewData, which just appends items to ViewData within the context of the editor template.
Long and short, none of this works how you think it does. Plainly and simply, if you need to work with a collection, you need to use for rather than foreach. The expression that you pass to the *For family of helpers is not just about identifying a property however you can get to it; it must be a bindable expression, i.e. something Razor can use to create a name for the form field that will line up to something on your model on post. In order for that to happen, the names must be something like Movimenti[N].Prodotto.Descrizione, and the only way to get that is to call the helper like:
#Html.HiddenFor(m => m.Movimenti[i].Prodotto.Descrizione)
Where i would be the iterator from your for loop.
I am just trying to pass a List and display it dynamically in a table in the View. I have a Homepage Model and Homepage controller and the variables are being set right, but I can't figure out how to pass it to the view.
My model looks like this:
public class HomePageModel
{
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "ExtNum")]
public string ExtNum { get; set; }
[Display(Name = "PhoneDisplay")]
public List<PhoneDisplay> PhoneDisplay { get; set; }
}
and this is the controller:
public ActionResult Homepage(HomePageModel HpModel)
{
ViewBag.Welcome = "Welcome: ";
ViewBag.FirstName = HpModel.FirstName;
ViewBag.LastName = HpModel.LastName;
ViewBag.Extlbl = "Extension: ";
ViewBag.Ext = HpModel.ExtNum;
ViewBag.Todaylbl = "Today:";
ViewBag.Today = DateTime.Now;
DBOps ops = new DBOps();
HpModel.PhoneDisplay = ops.getDisplayInfo(HpModel.ExtNum);
return View(HpModel);
}
PhoneDisplay is a list that contains a line index, a description string and a 4 digit number. Each user will have at least 1 item in this list and maximum 6. I was able to pass the other parameters and display them in the view but I can't find a way to pass the list and display that dynamically.
EDIT
I made it this far but still can't find the list items.
#model AxlMVC.Models.HomePageModel
<table>
<caption style="font-weight:bold">Your Phone Information</caption>
<tr>
<th>Line Index</th>
<th>Display</th>
<th>Extension Number</th>
</tr>
#{
foreach (var item in Model.PhoneDisplay) //problems here
{
<tr>
<td>
#Html.Display(item.numplanindex)
</td>
<td>
#Html.Display(item.display)
</td>
<td>
#Html.Display(item.dnorpattern)
</td>
</tr>
}
}
</table>
EDIT
I debugged the cshtml file and the items in the foreach loop are being passed just fine too, but the table is not showing on the page and neither are the items all I can see is the caption and the headers for each column
Html.Display displays "data from the ViewData dictionary or from a model" as stated on MSDN. What it means is that it searches for the key in the ViewData dictionary with the value you pass in or a property in the Model with the specified name. E.g. Display("test") would search ViewData for the "test" key and the Model for the property named test. Since you are passing in property values that cannot work. Your options are:
Output the value directly, #item.numplanindex. This will output a string representation of the value.
Use Display, although this is not recommended. You could do Display("PhoneDisplay[1].numplanindex") to display numplanindex property of the second item in list.
Use DisplayFor, like DisplayFor(model => item.numplanindex). This is a strongly typed version of Display. It will either displays a string representation of the value or a template for the type, if you have one. You can also manage how the output is displayed via Data Annotations, e.g. DisplayFormatAttribute.
Use DisplayTextFor, like DisplayTextFor(model => item.numplanindex). This method outputs the string representation of the value.
Since you already have data annotations on the model, you could modify your view like this:
#model AxlMVC.Models.HomePageModel
<table>
<caption class="tableCaption">Your Phone Information</caption>
<tr>
<th>#Html.DisplayNameFor(model => model.PhoneDisplay[0].numplanindex)</th>
<th>#Html.DisplayNameFor(model => model.PhoneDisplay[0].display)</th>
<th>#Html.DisplayNameFor(model => model.PhoneDisplay[0].dnorpattern)</th>
</tr>
#{
foreach (var item in Model.PhoneDisplay)
{
<tr>
<td>#Html.DisplayTextFor(model => item.numplanindex)</td>
<td>#Html.DisplayTextFor(model => item.display)</td>
<td>#Html.DisplayTextFor(model => item.dnorpattern)</td>
</tr>
}
}
</table>
The line #Html.DisplayNameFor(model => model.PhoneDisplay[0].numplanindex) also works if PhoneDisplay contains no items. Only property metadata is collected, expression as such is not executed.
I have a newbie question, which I have tried to understand for the past few days. Hopefully someone can be kind enough to help me understand the programming flow.
Assuming I have a model, the information is stored in the database:
public class Student
{
public int studentID { get; set; }
public string studentName { get; set; }
public strin studentGrade {get; set; }
}
public class StudentDBContext : DbContext
{
public DbSet<Student> Students { get; set; }
}
and I want to display it into the view, with additional checkbox so I can select which students to be promoted into the next grade. I read that one way to do it is by putting into view model:
public class StudentViewModel
{
public bool promoted { get; set; }
public Student stu { get; set; }
}
But I am stuck on is this the way to do it? and if yes, how do you put into the view where it will display all the students with a checkbox next to it. Afterwards, I want to update all the grade for the students whose checkboxes are ticked. For example:
Student A, Student B, Student D promoted from Grade 1 to Grade 2. So I want to display the students, tick Student A, B and D and submit to update the Grade.
Step by step example will be much appreciated.
Update 1:
Controller:
[HttpGet]
public ViewResult CheckBox()
{
var studentViewModels = db.Students.Select(m => new StudentViewModel()
{
stu = m
}).ToList();
return View(studentViewModels);
}
[HttpPost]
public ActionResult CheckBox(IList<studentViewModel> list)
{
foreach (var stuUpdate in list.Where(m => m.promoted))
{
var stuRow = db.Students.Find(stuUpdate.stu.studentID);
stuRow.studentName = stuRow.studentName + "1";
db.Entry(stuRow).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("CheckBox");
}
return RedirectToAction("CheckBox");
}
View:
#model IList<School.ViewModels.StudentViewModel>
#using (Html.BeginForm())
{
<table>
<tr>
<th>
</th>
<th>
student ID
</th>
<th>
student name
</th>
<th>
student grade
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.CheckBoxFor(modelItem => item.promoted)
#Html.HiddenFor(modelItem => item.stu.studentID)
</td>
<td>
#Html.DisplayFor(modelItem => item.stu.studentID)
</td>
<td>
#Html.DisplayFor(modelItem => item.stu.studentName)
</td>
<td>
#Html.DisplayFor(modelItem => item.stu.studentGrade)
</td>
</tr>
}
</table>
<input type="submit" value="save" />
}
However currently hit by the following error:
Value cannot be null.
Parameter name: source
Source Error:
foreach (var stuUpdate in list.Where(m => m.promoted))
A very basic "step by step" (done in SO, so I probably did a few mistakes, but you've got the idea).
You have always a few ways to do these kind of things, so... just really take it as a sample, and find other examples to get other ideas.
well, first, in your controller, you will have a GET action (to see the list).
[HttpGet]
public ViewResult StudentList() {
//retrieve all students. With the Select, we create a new instance of StudentViewModel for each student.
//assuming StudentDbContext being a property of your controller, if it's not, you can instantiate a new one (in a using clause)
var studentViewModels = StudentDbContext.Students
.Select(m => new StudentViewModel() {
stu = m
//we don't say nothing about promoted :
//it will be there as "false" by default, which is probably what we want.
}).ToList();
//now we've got a list of StudentViewModel. This will be the model of our view
return View(studentViewModels);
}
Then we've got a view, StudentList.cshtml
in this view, we will display a table, with a line for each student : the studentId (hidden in this case), the name (display only), the grade (display only), and a checkbox.
We need a for loop (not a foreach) to get fine model binding.
#model IList<StudentViewModel>
#using (Html.BeginForm()) {
<table>
<tr>
<th>Student name</th>
<th>Student grade</th>
<th>Promote</th>
</tr>
#for (var i = 0; i < Model.Count(); i++) {
<tr>
<td>#Html.HiddenFor(m => Model[i].Student.studentID)
#Html.DisplayFor(m => Model[i].Student.studentName)
</td>
<td>#Html.DisplayFor(m => Model[i]Student.studentGrade)</td>
<td>#Html.CheckBoxFor(m => Model[i].promoted)</td>
</tr>
}
</table>
<input type="submit" value="save" />
}
This form will lead to another POST action (same name as the GET one, depending of what you have in your Html.BeginForm)
[HttpPost]
public ActionResult StudentList(IList<StudentViewModel> list) {
//we treat only the lines where checkbox has been checked
foreach (var studentViewModel in list.Where(m => m.promoted) {
var student = StudentDBContext.GetById(studentViewModel.Student.studentID);//get student entity instance from context
student.studentGrade ="<new value>";
StudentDBContext.SaveChanges();//save changes, you must have such a method somewhere.
}
return Action("StudentList");
}
Little detail :
Try to respect some really basic "usual" practices : for example in c#, Properties should begin by an uppercase letter (so StudentGrade, StudentName, Promoted, etc).
I have my view models :
public class POReceiptViewModel
{
public virtual int PONumber { get; set; }
public virtual string VendorCode { get; set; }
public virtual IList<POReceiptItemViewModel> POReceiptItems { get; set; }
public POReceiptViewModel()
{
POReceiptItems = new List<POReceiptItemViewModel>();
}
}
public class POReceiptItemViewModel
{
public virtual string ItemCode { get; set; }
public virtual string ItemDesription { get; set; }
public virtual decimal OrderedQuantity { get; set; }
public virtual decimal ReceivedQuantity { get; set; }
public virtual DateTime ReceivedDate { get; set; }
public POReceiptItemViewModel()
{
ReceivedDate = DateTime.Now;
}
}
Then my controller has two actions, one get and one post:
public ActionResult CreatePOReceipt(int poNumber)
{
PurchaseOrder po = PurchasingService.GetPurchaseOrder(poNumber);
POReceiptViewModel poReceiptViewModel = ModelBuilder.POToPOReceiptViewModel(po);
return View("CreatePOReceipt", poReceiptViewModel);
}
[HttpPost]
public ActionResult CreatePOReceipt(POReceiptViewModel poReceiptViewModel)
{
// Here the problem goes. The items in the poReceiptViewModel.POReceiptItems has lost. the count became zero.
return View("Index");
}
And in my View, I can display the model properly and by using #Html.HiddenFor<> I can persist view model data as I wanted to. But not on the List<> navigation property.
#model POReceiptViewModel
#using (Html.BeginForm())
{
<fieldset>
<legend>Purchase Order</legend>
<label>For PO # :</label>
#Html.HiddenFor(m => m.PONumber)
#Html.DisplayTextFor(m => m.PONumber)
<label>Vendor Code :</label>
#Html.HiddenFor(m => m.VendorCode)
#Html.DisplayTextFor(m => m.VendorCode)
</fieldset>
<fieldset>
<legend>Received Items</legend>
<table class="tbl" id="tbl">
<thead>
<tr>
<th>Item Code</th><th>Item Description</th><th>OrderedQuantity</th><th>Received Quantity</th><th>Received Date</th>
</tr>
</thead>
<tbody>
#Html.HiddenFor(m => m.POReceiptItems) // I'm not really sure if this is valid
#if (Model.POReceiptItems.Count > 0)
{
foreach (var item in Model.POReceiptItems)
{
<tr>
<td>#Html.DisplayTextFor(i => item.ItemCode)</td>#Html.HiddenFor(i => item.ItemCode)
<td>#Html.DisplayTextFor(i => item.ItemDesription)</td>#Html.HiddenFor(i => item.ItemDesription)
<td>#Html.DisplayTextFor(i => item.OrderedQuantity)</td>#Html.HiddenFor(i => item.OrderedQuantity)
<td>#Html.TextBoxFor(i => item.ReceivedQuantity)</td>
<td>#Html.TextBoxFor(i => item.ReceivedDate)</td>
</tr>
}
}
</tbody>
</table>
</fieldset>
<input type="submit" name="Received" value="Received" />
}
PROBLEM:
POReceiptItems lost when the form submitted. As much as possible I don't want to use TempData["POReceiptItems"] = Model.POReceiptItems but even if I use it, the value entered into ReceivedQuantity and ReceivedDate are not save into the TempData.
Thanks in advance!
try
#for (int i = 0; i < Model.POReceiptItems.Count(); i++)
{
<tr>
<td>#Html.DisplayTextFor(m => m.POReceiptItems[i].ItemCode)</td>#Html.HiddenFor(m => m.POReceiptItems[i].ItemCode)
<td>#Html.DisplayTextFor(m => m.POReceiptItems[i].ItemDesription)</td>#Html.HiddenFor(m => m.POReceiptItems.ItemDesription) <td>#Html.DisplayTextFor(m => m.POReceiptItems[i].OrderedQuantity)</td>#Html.HiddenFor(m => m.POReceiptItems[i].OrderedQuantity)
<td>#Html.TextBoxFor(m => m.POReceiptItems[i].ReceivedQuantity)</td>
<td>#Html.TextBoxFor(m => m.POReceiptItems[i].ReceivedDate)</td>
</tr>
}
also read this blog post to understand how model binding to a list works
You lose your list because MVC don't handle the List the way you think.
You should use BeginCollectionItem look at this post
I had a similar problem, the "List" attribute returned without values(count = 0), I tried different ways and answers and nither works.
Then I tried by myself and now it is working, this is my solution:
I send an object with some normal attributes and a "List", after that I used the normal attributes and my "list" in a For.
In my controller (Post ActionResult), in the parameters section I added two parameters, my original object and my "List" as second parameter and it works!!!
I hope this helps you and others with similar problems.
I've just started to get into using ViewModels. Can you guys check out this code to see if I'm following best practice? Is there anything out of the ordinary? Would you do the validation differently?
Sorry if code is lengthy (there's so many parts to it). I've tried to make it as easy to understand as possible.
Thanks!
Model
public class CustomerModel
{
[Required(ErrorMessage="Primer nombre!")]
public string FirstName { get; set; }
[Required(ErrorMessage="Segundo nombre!")]
public string LastName { get; set; }
[Required(ErrorMessage="Edad")]
public int? Age { get; set; }
public string State { get; set; }
public string CountryID { get; set; }
[Required(ErrorMessage="Phone Number")]
public string PhoneNumber { get; set; }
}
ViewModel
public class CustomerViewModel
{
public CustomerModel Customer { get; set; }
public string Phone1a { get; set; }
public string Phone1b { get; set; }
public string Phone1c { get; set; }
}
Controller
public ActionResult Index()
{
CustomerViewModel Customer = new CustomerViewModel()
{
Customer = new CustomerModel(),
};
return View(Customer);
}
[HttpPost]
public ActionResult Index(CustomerViewModel c)
{
//ModelState.Add("Customer.PhoneNumber", ModelState["Phone1a"]);
// Let's manually bind the phone number fields to the PhoneNumber properties in
// Customer object.
c.Customer.PhoneNumber = c.Phone1a + c.Phone1b + c.Phone1c;
// Let's check that it's not empty and that it's a valid phone number (logic not listed here)
if (!String.IsNullOrEmpty(c.Customer.PhoneNumber))
{
// Let's remove the fact that there was an error!
ModelState["Customer.PhoneNumber"].Errors.Clear();
} // Else keep the error there.
if (ModelState.IsValid)
{
Response.Write("<H1 style'background-color:white;color:black'>VALIDATED</H1>");
}
return View("Index", c);
}
}
View
#model MVVM1.Models.CustomerViewModel
#using (Html.BeginForm("Index", "Detail"))
{
<table border="1" cellpadding="1" cellspacing="1">
<tr>
<td>#Html.LabelFor(m => m.Customer.FirstName)</td>
<td>
#Html.TextBoxFor(m => m.Customer.FirstName)
#Html.ValidationMessageFor(m => m.Customer.FirstName)
</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.Customer.LastName)</td>
<td>
#Html.TextBoxFor(m => m.Customer.LastName)
#Html.ValidationMessageFor(m => m.Customer.LastName)
</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.Customer.Age)</td>
<td>
#Html.TextBoxFor(m => m.Customer.Age)
#Html.ValidationMessageFor(m => m.Customer.Age)
</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.Customer.PhoneNumber)</td>
<td width="350">
#Html.TextBoxFor(m => m.Phone1a, new { size="4", maxlength="3" })
#Html.TextBoxFor(m => m.Phone1b)
#Html.TextBoxFor(m => m.Phone1c)
<div>
#Html.ValidationMessageFor(m => m.Customer.PhoneNumber)
</div>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Submit" /></td>
</tr>
</table>
}
One thing that jumps out at me is this:
if (ModelState.IsValid)
{
Response.Write("<H1 style'background-color:white;color:black'>VALIDATED</H1>");
}
return View("Index", c);
Remember that view models are good for passing data to your controller AND back to your model. I recommend you add an IsValid property to your view model and then setting that to true instead of calling Response.Write. Then simply add this to the top of your partial view:
#if (Model.IsValid)
{
<H1 style'background-color:white;color:black'>VALIDATED</H1>
}
You can also get to ModelState in your view but some would argue that isn't a best practice. However, if you don't want to add a property to your model for something you can just see in your view you can just do this:
#if (ViewData.ModelState.IsValid)
Another nitpicky thing is that MVC validation attributes are typically used for validation on the UI. This validation can be reused in other areas but in some cases is sub-optimal. Also, you may not always be able to modify your domain models. Therefore, to keep all of my UI validation in one place I usually wrap my domain models in my view models so you get something like this:
public class CustomerViewModel
{
public CustomerModel Customer { get; set; }
[Required(ErrorMessage="Primer nombre!")]
public string FirstName
{
get { return Customer.FirstName; }
set { Customer.FirstName = value; }
}
...
This may seem redundant and isn't always worth the effort but it is a good practice to consider when using Entity Framework domain models or other classes which are difficult or impossible to modify.
I'm just getting the hang of MVC myself, but I researched this same topic yesterday and came to the conclusion that one should not directly include a model object in the ViewModel. So my understanding is that it would be a bad practice to include your CustomerModel directly in the CustomerViewModel.
Instead, you want to list out each of the properties from CustomerModel that you want to include in your ViewModel. Then you either want to manually map the data from CustomerModel to the CustomerViewModel or use a tool like AutoMapper which does it automatically with a line of code like this inside of your action method:
public ViewResult Example()
{
// Populate/retrieve yourCustomer here
Customer yourCustomer = new CustomerModel();
var model = Mapper.Map<CustomerModel, CustomerViewModel>(yourCustomer);
return View(model);
}
In this case, Mapper.Map will return a CustomerViewModel that you can pass to your View.
You will also need to include the following in your Application_Start method:
Mapper.CreateMap<CustomerModel, CustomerViewModel>();
In general I found AutoMapper pretty easy to get to work. It's automatic when the field names match, if they don't or you have a nested Object, you can specify those mappings in the CreateMap line. So if your CustomerModel uses an Address object instead of individual properties, you would do this:
Mapper.CreateMap<CustomerModel, CustomerViewModel>()
.ForMember(dest => dest.StreetAddress, opt => opt.MapFrom(src => src.Address.Street));
Please anyone correct me if I'm wrong as I'm just getting my head around MVC as well.
I would say your ViewModel implementation is pretty standard. You are using the ViewModel to act as the intermediate object between your View, and your Domain Model. Which is good practice.
The only thing I'd be weary about is how you handle Model errors, and also your ViewModel should have some attributes. For instance, you might want to use the RegularExpressionAttribute Class:
public class CustomerViewModel
{
public CustomerModel Customer { get; set; }
[RegularExpression(#"^\d{3}$")]
public string Phone1a { get; set; }
[RegularExpression(#"^\d{3}$")]
public string Phone1b { get; set; }
[RegularExpression(#"^\d{4}$")]
public string Phone1c { get; set; }
}