summarizing duplicate line items in shopping cart with MVC/EF - asp.net-mvc

I am currently working on creating a simple shopping cart where line items are being displayed based on a call to a table. Primarily I am taking advantage of basic CRUD here, so I am reading a table, filtered out userID and checking whether a orderID has been assigned or not (to avoid redisplaying ordered items in the shopping cart).
All fine, all working, but for esthetic reasons I would like to handle cases where the same product (same ProductID, same ProductName, but i.e. different quantity) is being summarized in one position (order quantity A + order quantity B, etc) rather than having multiple line items with different quantities.
Side note: I am offering subscriptions as well as single orders (differentiated by a Boolean in the table), so please don't let that irritate here.
the Model for LineItems looks as follows:
public class LineItems
{
public int ID { get; set; }
public string UserID { get; set; }
public int ProductID { get; set; }
public string ProductName { get; set; }
//[Range(1, int.MaxValue, ErrorMessage = "Naja... Menge 0 lohnt sich nicht zu liefern...")]
public int SubscriptionQuantity { get; set; }
public string SubscriptionCadenceCategory { get; set; }
public int SubscriptionCadenceValue { get; set; }
public decimal SubscriptionPrice { get; set; }
public bool IsSingleOrder { get; set; }
//[Range(1, int.MaxValue, ErrorMessage = "Naja... Menge 0 lohnt sich nicht zu liefern...")]
public int SingleOrderQuantity { get; set; }
public decimal SingleOrderPrice { get; set; }
public decimal TotalPrice { get; set; }
public int OrderNumber { get; set; }
public DateTime UpdatedTimeStampUTC { get; set; }
public string UpdatedLatitude { get; set; }
public string UpdatedLongitude { get; set; }
public string UpdatedLocation { get; set; }
}
and the View:
<div id="shoppingCart" class="productTableSection row">
#foreach (var item in Model)
{
if (item.IsSingleOrder == false)
{
<div id="shoppingCartSubscriptionLineItemArea" class=" tableArea col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-1 col-md-10 col-lg-offset-2 col-lg-8">
#Html.HiddenFor(modelItem => item.ID, new { #class = "tableField col-xs-12 col-sm-12 col-md-12 col-lg-12" })
<a id="shoppingCartSubscriptionRemoveLink" class="tableField col-xs-1 col-sm-1 col-md-1 col-lg-1" href="#">
<i id="shoppingCartSubscriptionRemove" class="fas fa-trash-alt"></i>
</a>
<a id="shoppingCartSubscriptionLineItemLink" class="tableField col-xs-10 col-sm-10 col-md-10 col-lg-10" href="#Url.Action("ProductSubscription", "freshNclean", new { id = item.ID })">
<div id="shoppingCartSubscriptionProductNameField" class="tableField col-xs-7 col-sm-8 col-md-9 col-lg-9">
#Html.DisplayFor(modelItem => item.ProductName)
</div>
<div id="shoppingCartSubscriptionProductPriceField" class="tableField col-xs-5 col-sm-4 col-md-3 col-lg-3">
CHF #Html.DisplayFor(modelItem => item.SubscriptionPrice)
</div>
<div id="shoppingCartSubscriptionProductQuantityField" class="tableField col-xs-4 col-sm-4 col-md-5 col-lg-5">
#Html.DisplayFor(modelItem => item.SubscriptionQuantity) x
</div>
<div id="shoppingCartSubscriptionCadenceValueField" class="tableField col-xs-3 col-sm-2 col-md-2 col-lg-1">
alle #Html.DisplayFor(modelItem => item.SubscriptionCadenceValue)
</div>
<div id="shoppingCartSubscriptionCadenceCategoryField" class="tableField col-xs-5 col-sm-6 col-md-5 col-lg-6">
#Html.DisplayFor(modelItem => item.SubscriptionCadenceCategory)
</div>
<div id="shoppingCartSubscriptionTotalPriceField" class="tableField col-xs-12 col-sm-12 col-md-12 col-lg-12">
CHF #Html.DisplayFor(modelItem => item.TotalPrice)
</div>
</a>
<a id="shoppingCartSubscriptionEditLink" class="tableField col-xs-1 col-sm-1 col-md-1 col-lg-1" href="#">
<i id="shoppingCartSubscriptionEdit" class="fas fa-edit"></i>
</a>
</div>
}
else
{
<div id="shoppingCartSingleOrderLineItemArea" class=" tableArea col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-1 col-md-10 col-lg-offset-2 col-lg-8">
#Html.HiddenFor(modelItem => item.ID, new { #class = "tableField col-xs-12 col-sm-12 col-md-12 col-lg-12" })
<a id="shoppingCartSingleOrderRemoveLink" class="tableField col-xs-1 col-sm-1 col-md-1 col-lg-1" href="#">
<i id="shoppingCartSingleOrderRemove" class="fas fa-trash-alt"></i>
</a>
<a id="shoppingCartSingleOrderLineItemLink" class="tableField col-xs-10 col-sm-10 col-md-10 col-lg-10" href="#Url.Action("ProductSingleOrder", "freshNclean", new { id = item.ID })">
<div id="shoppingCartSingleOrderProductNameField" class="tableField col-xs-7 col-sm-8 col-md-9 col-lg-9">
#Html.DisplayFor(modelItem => item.ProductName)
</div>
<div id="shoppingCartSingleOrderProductPriceField" class="tableField col-xs-5 col-sm-4 col-md-3 col-lg-3">
CHF #Html.DisplayFor(modelItem => item.SingleOrderPrice)
</div>
<div id="shoppingCartSingleOrderProductQuantityField" class="tableField col-xs-12 col-sm-12 col-md-12 col-lg-12">
#Html.DisplayFor(modelItem => item.SingleOrderQuantity) x
</div>
<div id="shoppingCartSingleOrderTotalPriceField" class="tableField col-xs-12 col-sm-12 col-md-12 col-lg-12">
CHF #Html.DisplayFor(modelItem => item.TotalPrice)
</div>
</a>
<a id="shoppingCartSingleOrderEditLink" class="tableField col-xs-1 col-sm-1 col-md-1 col-lg-1" href="#">
<i id="shoppingCartSingleOrderEdit" class="fas fa-edit"></i>
</a>
</div>
}
}
</div>
finally the Controller:
// GET: /freshNclean/ShoppingCart
[Authorize]
public ActionResult ShoppingCart(Orders model)
{
// define variables
var userID = User.Identity.GetUserId();
DateTime nowUTC = DateTime.Now.ToUniversalTime();
DateTime nowLocal = DateTime.Now.ToLocalTime();
// track user activity: get method is restricted to activity name and timestamp
var LOADED = new UserActivities
{
UserID = userID,
ActivityName = "ShoppingCart_Loaded",
ActivityTimeStampUTC = nowUTC,
ActivityLatitude = "n/a",
ActivityLongitude = "n/a",
ActivityLocation = "n/a"
};
DATADB.UserActivityList.Add(LOADED);
DATADB.SaveChanges();
return View(DATADB.LineItemList.Where(x => x.UserID == userID).Where(x => x.OrderNumber == 0).ToList());
}

I finally figured it out myself - not really. What I did is I changed the approach of writing to the shopping cart. But the end result is working.

Related

How to make your button on a form using asp.net-mvc work?

I have a button, it does not seem to create new users to my database. What it does it only inherits user validaton to my Login method and need some guidance to this please and thanks. Below is the logic what i am trying to do. What i want to do my create button must be able to create new users if not exist to the database.
Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateModel objSubmit)
{
ViewBag.Msg = "Details submitted successfully";
return View(objSubmit);
}
// This is for login, and its hits this method each time.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(Login login)
{
if (ModelState.IsValid)
{
bool success = WebSecurity.Login(login.username, login.password, false);
var UserID = GetUserID_By_UserName(login.username);
var LoginType = GetRoleBy_UserID(Convert.ToString(UserID));
if (success == true)
{
if (string.IsNullOrEmpty(Convert.ToString(LoginType)))
{
ModelState.AddModelError("Error", "Rights to User are not Provide Contact to Admin");
return View(login);
}
else
{
Session["Name"] = login.username;
Session["UserID"] = UserID;
Session["LoginType"] = LoginType;
if (Roles.IsUserInRole(login.username, "Admin"))
{
return RedirectToAction("AdminDashboard", "Dashboard");
}
else
{
return RedirectToAction("UserDashboard", "Dashboard");
}
}
}
else
{
ModelState.AddModelError("Error", "Please enter valid Username and Password");
return View(login);
}
}
else
{
ModelState.AddModelError("Error", "Please enter Username and Password");
return View(login);
}
}
Model:
namespace eNtsaPortalWebsiteProject.Models
{
public class CreateModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string password { get; set; }
[Required]
public string username { get; set; }
}
}
// View for login
<div data-="mainContent">
<section class="container">
<div class="logo col-sm-12 text-center col-md-12"> <img alt="" src="~/Images/eNtsa.png" /></div>
<div class="clearfix"></div>
<div class="container">
<div class="row">
<div id="MyWizard" class="formArea LRmargin">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div id="divMessage" class="text-center col-md-12 col-md-offset-12 alert-success">
#Html.ValidationSummary()
</div>
<div class="col-md-12 col-md-offset-10 col-xs-12">
<div class="loginPage panel-info">
<div class="form-group"><span class=""><i class="glyphicon glyphicon-user">Username:</i></span>
#Html.TextBoxFor(model => model.username, new { #class = "form-control text-center", autocomplete = "off" })
#Html.ValidationMessageFor(model => model.username)
</div>
<div class="form-group">
<span class=""><i class="glyphicon glyphicon-lock">Password:</i></span>
#Html.PasswordFor(model => model.password, new { #class = "form-control text-center", autocomplete = "off" })
#Html.ValidationMessageFor(model => model.password)
</div>
</div>
<div class="form-group">
<input id="BtnLogin" type="submit" class="btn btn-success btn-pressure" name="BtnLogin" value="Login" />
<input type ="Submit" class="btn btn-info btn-pressure" name="BtnCreate" value="Create" />
</div>
</div>
}
<div class="clear"></div>
</div>
</div>
</div>
</section>
</div>
View for creating user:
<div class="mainContent">
<section class="container">
<div class="logo col-sm-12 text-center col-md-10">
<img alt="" src="~/Images/eNtsa.png"/>
</div>
<div class="container">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div id="divMessage" class="text-center col-md-12 col-md-offset-12 alert-success">
#Html.ValidationSummary()
</div>
<div class="col-md-12 col-md-offset-10 col-xs-12">
<div class="glyphicon-registration-mark">
<div class="form-group"><span class=""><i class="glyphicon glyphicon-user">Username:</i></span>
#Html.TextBoxFor(model=>model.username, new {#class ="form-control text-center", automplete="off" })
#Html.ValidationMessageFor(model=>model.username)
</div>
<div class="form-group">
<span class=""><i class="glyphicon glyphicon-lock">Password:</i></span>
#Html.PasswordFor(model=>model.password, new {#class = "form-control text-center", autocomplete="off" })
#Html.ValidationMessageFor(model=>model.password)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-success btn-pressure" name="BtnSubmit" value="Submit"/>
</div>
</div>
}
</div>
</section>
</div>
The button is working - that isn't the problem that you're having.
You can have multiple buttons to submit the form but they will return to the same place, either:
a) the controller/action specified in the "action" property of the form
b) if no action is specified then the default location - in your case there isn't one directly specified so it is posting back to the default location.
(see: How to link HTML5 form action to Controller ActionResult method in ASP.NET MVC 4)
The easiest way to accomplish what you're trying to do would be refactor your controller and branch the logic depending on what the value is of the submit button.
(see: MVC razor form with multiple different submit buttons?
and How to handle two submit buttons on MVC view)
This will require some refactoring of the code that you have written, but it is the most straightforward way of achieving what you're trying to do.
In very basic terms it would look something like this:
Model:
namespace eNtsaPortalWebsiteProject.Models
{
public class LoginCreateModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string password { get; set; }
[Required]
public string username { get; set; }
public string btnSubmit { get; set; } // both buttons will have the same name on your form, with different values ("Create" or "Login")
}
}
Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginCreateModel objSubmit)
{
if (objSubmit.btnSubmit == "Create")
{
// Handle creation logic here
}
if (objSubmit.btnSubmit == "Login")
{
// Handle login logic here
}
return View(objSubmit);
}

Search filter using multiple fields showing error in ASP.NET MVC with Entitiy Framework

I am trying to apply search filter in ASP.NET MVC using multiple fields for which I have used view models. I have reached close to it but it is showing this error:
The model item passed into the dictionary is of type 'System.Data.Entity.DbSet`1[HMS.Models.tblPatient]', but this dictionary requires a model item of type 'HMS.ViewModels.SearchViewModel'
I don't know what I am doing wrong.
Here is my code:
SearchController.cs:
public ActionResult Index(SearchViewModel searchModel)
{
var search = new SearchDAL();
var model = search.GetSearchResults(searchModel);
return View(model);
}
ViewModel.cs:
public class SearchViewModel
{
public SearchViewModel()
{
PatientsSearch = new List<SearchResult>();
}
public int? Patient_ID { set; get; }
public string Patient_Name { set; get; }
public string Patient_Address { set; get; }
public string Contact_Number { set; get; }
public int Age { set; get; }
public string Gender { set; get; }
public List<SearchResult> PatientsSearch { set; get; }
}
public class SearchResult
{
public int? Patient_ID { set; get; }
public string Patient_Name { set; get; }
public string Patient_Address { set; get; }
public string Contact_Number { set; get; }
public int Age { set; get; }
public string Gender { set; get; }
}
SearchDAL.cs:
public class SearchDAL
{
private HMS_DBEntity Context;
public SearchDAL()
{
Context = new HMS_DBEntity();
}
public IQueryable<tblPatient> GetSearchResults(SearchViewModel searchModel)
{
var result = Context.tblPatients.AsQueryable();
if (searchModel != null)
{
if (searchModel.Patient_ID.HasValue)
result = result.Where(x => x.Patient_id == searchModel.Patient_ID);
if (!string.IsNullOrEmpty(searchModel.Patient_Name))
result = result.Where(x => x.Patient_Name.Contains(searchModel.Patient_Name));
if (!string.IsNullOrEmpty(searchModel.Patient_Address))
result = result.Where(x => x.Patient_address.Contains(searchModel.Patient_Address));
if (!string.IsNullOrEmpty(searchModel.Contact_Number))
result = result.Where(x => x.Contact_no.Contains(searchModel.Contact_Number));
}
return result;
}
}
Index.cshtml:
#using HMS.ViewModels
#model HMS.ViewModels.SearchViewModel
#*#model HMS.Models.tblPatient*#
#{
ViewBag.Title = "Index";
}
<section class="content">
#using (Html.BeginForm("Index", "Search", FormMethod.Get))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(false, "", new { #class = "text-danger" })
<div class="container-fluid">
<div class="block-header">
<h2>Patients Record</h2>
</div>
<div class="row clearfix">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="card">
<div class="body">
<div class="row clearfix">
<div class="col-sm-6 col-md-6 col-lg-6">
<div class="form-group">
<div class="form-line">
#Html.TextBoxFor(x => x.Patient_ID, new { #type = "Text", #class = "form-control", #id = "PatientID", #placeholder = "Patiend ID" })
</div>
</div>
</div>
<div class="col-sm-6 col-md-6 col-lg-6">
<div class="form-group">
<div class="form-line">
#Html.TextBoxFor(x => x.Patient_Name, new { #type = "Text", #class = "form-control", #id = "PatientName", #placeholder = "Patiend Name" })
</div>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-sm-6 col-md-6 col-lg-6">
<div class="form-group">
<div class="form-line">
#Html.TextBoxFor(x => x.Patient_Address, new { #type = "Text", #class = "form-control", #id = "PatientAddress", #placeholder = "Patient Address" })
</div>
</div>
</div>
<div class="col-sm-6 col-md-6 col-lg-6">
<div class="form-group">
<div class="form-line">
#Html.TextBoxFor(x => x.Contact_Number, new { #type = "Text", #class = "form-control", #id = "ContactNo", #placeholder = "Contact Number" })
</div>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-sm-6 col-md-6 col-lg-6">
<input type="submit" id="Submit" class="btn btn-raised g-bg-cyan waves-effect" value="Search" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
}
<div class="row clearfix">
<div class="container-fluid">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="card">
<div class="body table-responsive">
<table class="table table-bordered table-striped table-hover js-basic-example dataTable">
<tr>
<th>
#Html.DisplayNameFor(model => model.Patient_Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Patient_Address)
</th>
<th>
#Html.DisplayNameFor(model => model.Contact_Number)
</th>
<th>
#Html.DisplayNameFor(model => model.Age)
</th>
<th>
#Html.DisplayNameFor(model => model.Gender)
</th>
<th></th>
</tr>
#{
if (Model.PatientsSearch != null && Model.PatientsSearch.Count > 0)
{
foreach (var item in Model.PatientsSearch)
{
<tr>
<td>#item.Patient_Name</td>
<td>#item.Patient_Address</td>
<td>#item.Contact_Number</td>
<td>#item.Age</td>
<td>#item.Gender</td>
</tr>
}
}
}
</table>
</div>
The error message is clear. Your model defined in view Index.cshtml is
#model HMS.ViewModels.SearchViewModel
But the data you pass to the view is result of GetSearchResults, which is System.Data.Entity.DbSet`1[HMS.Models.tblPatient]
var model = search.GetSearchResults(searchModel);
return View(model);
I think you know how to make it works now.
It's a type mismatch issue at:
return View(model);
So, inside GetSearchResults method, make following change while returning the result object:
result = new List<SearchViewModel>(result);
return result;
And, change your return type of GetSearchResults() method from IQueryable to List
public List<SearchViewModel> GetSearchResults(SearchViewModel searchModel)

MVC Core. Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions

I am passing in my view this model
public class BlogViewModel
{
public List<CommentModel> commentModels { get; set; }
public BlogPostLayoutModel blogPostLayoutModel { get; set; }
public CommentModel commentModel { get; set; }
public int pageNumber { get; set; }
}
CommentModel class
public class CommentModel
{
public int IDComment { get; set; }
public int IDPost { get; set; }
[Required()]
public string Username { get; set; }
[Required()]
public string Content { get; set; }
public static CommentModel CommentToCommentModel(Comment comment)
{
CommentModel commentModel = new CommentModel();
commentModel.IDComment = comment.IDComment;
commentModel.IDPost = comment.IDPost;
commentModel.Username = comment.Username;
commentModel.Content = comment.Content;
return commentModel;
}
public static List<CommentModel> CommentsToCommentModels(List<Comment> comments)
{
List<CommentModel> commentModels = new List<CommentModel>();
foreach (var comment in comments)
{
CommentModel commentModel = new CommentModel();
commentModel.IDComment = comment.IDComment;
commentModel.IDPost = comment.IDPost;
commentModel.Username = comment.Username;
commentModel.Content = comment.Content;
commentModels.Add(commentModel);
}
return commentModels;
}
}
And my view, where the error is thrown (fifth line)
<form asp-action="AddComment">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#{ var pageNumber = Model.pageNumber;
#Html.HiddenFor(x => pageNumber)
int IDPost = Model.blogPostLayoutModel.IDPost;
#Html.HiddenFor(x => x.commentModel.IDPost == IDPost)
}
<div class="row">
<div class="form-group col-md-4">
<label asp-for="commentModel.Username" class="control-label"></label>
<input asp-for="commentModel.Username" class="form-control" />
<span asp-validation-for="commentModel.Username" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="form-group col-md-12">
<label class="control-label">Comment</label>
<textarea asp-for="commentModel.Content" class="form-control"></textarea>
<span asp-validation-for="commentModel.Content" class="text-danger"></span>
</div>
<div class="form-group col-md-4">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</form>
I have searched for the error, but seems like it's mostly people trying to return a value from a method and getting told to pass the value to a local variable and then put that local variable inside the tag helper, but that doesn't seem to be the case here.
And also blogPostLayoutModel.IDPost is defined as
public int IDPost { get; set; }
EDIT: My commentModel was null, so that was the problem.
Working form
<form asp-action="AddComment">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#{
#Html.HiddenFor(x => Model.pageNumber)
Model.commentModel.IDPost = Model.blogPostLayoutModel.IDPost;
#Html.HiddenFor(x => x.commentModel.IDPost)
}
<div class="row">
<div class="form-group col-md-4">
<label asp-for="commentModel.Username" class="control-label"></label>
<input asp-for="commentModel.Username" class="form-control" />
<span asp-validation-for="commentModel.Username" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="form-group col-md-12">
<label class="control-label">Comment</label>
<textarea asp-for="commentModel.Content" class="form-control"></textarea>
<span asp-validation-for="commentModel.Content" class="text-danger"></span>
</div>
<div class="form-group col-md-4">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</form>

SelectListItem properties in view model are not passed back from view to controller

I have this View Model:
public class UserViewModel
{
public string ID { get; set; }
[Required]
[Display(Name = "Nombre")]
public string Nombre { get; set; }
[Required]
[Display(Name = "Login")]
public string Login { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Contraseña")]
public string Password { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "E-mail")]
public string Email { get; set; }
[DataType(DataType.PhoneNumber)]
[Display(Name = "Teléfono")]
public string PhoneNumber { get; set; }
[Display(Name = "Ciudad")]
public System.Web.Mvc.SelectListItem City { get; set; }
[Display(Name = "Empresas")]
public IEnumerable<System.Web.Mvc.SelectListItem> Empresas { get; set; }
[Required]
[Display(Name = "Perfil")]
public string Role { get; set; }
[Display(Name = "Está Vigente")]
public bool Vigente { get; set; }
}
the problem I am having is that when I select something in City and Empresas in the form (they are both SELECT fields), they are not passed to controller in UserViewModel parameter:
public JsonResult EditUser(UserViewModel model)
{
.....
}
Only other properties are passed.
What is the right way to manage this?
EDIT:
this is part of the view:
#using (Html.BeginForm("EditUser", "Account", new { area = "Security" }, FormMethod.Post, new { #class = "form-horizontal form-label-left", role = "form", novalidate = "novalidate", id = "frmUsuario" }))
{
var id = Model == null ? String.Empty : Model.ID;
<div class="errores col-md-12 col-sm-12 col-xs-12" style="display: none">
<div class='validation-summary-errors alert alert-danger alert-white rounded' data-valmsg-summary="true">
<div class="icon">
<i class="fa fa-times-circle"></i>
</div>
<p>Debe completar los campos marcados en forma correcta.</p>
</div>
</div>
#Html.AntiForgeryToken();
<input type="hidden" value="#id" id="id" name="id" />
<div class="item col-md-12 col-sm-12 col-xs-12 form-group has-feedback">
#Html.TextBoxFor(m => m.Nombre, new { #class = "form-control has-feedback-left", placeholder = "Nombre", required = "required" })
<span class="fa fa-user form-control-feedback left" aria-hidden="true"></span>
</div>
<div class="item col-md-6 col-sm-6 col-xs-12 form-group has-feedback">
#Html.TextBoxFor(m => m.Login, new { #class = "form-control has-feedback-left", placeholder = "Login", required = "required" })
<span class="fa fa-sign-in form-control-feedback left" aria-hidden="true"></span>
</div>
<div class="item col-md-6 col-sm-6 col-xs-12 form-group has-feedback">
#{
//var requerido = String.IsNullOrEmpty(userId) ? "required" : String.Empty;
var requerido = Model == null || String.IsNullOrEmpty(Model.ID);
object htmlAttributes = null;
if (requerido)
{
htmlAttributes = new { #class = "form-control has-feedback-left", placeholder = "Contraseña", required = "required" };
}
else
{
htmlAttributes = new { #class = "form-control has-feedback-left", placeholder = "Contraseña" };
}
}
<!-- Para evitar que los password managers llenen los campos -->
<input type="text" id="hidUser" style="display: none" />
<!-- Para evitar que los password managers llenen los campos -->
<input type="password" id="hidPassword" style="display: none" />
#Html.PasswordFor(m => m.Password, htmlAttributes)
<span class="fa fa-key form-control-feedback left" aria-hidden="true"></span>
</div>
<div class="item col-md-6 col-sm-6 col-xs-12 form-group has-feedback">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control has-feedback-left", placeholder = "E-mail", required = "required" })
<span class="fa fa-envelope form-control-feedback left" aria-hidden="true"></span>
</div>
<div class="item col-md-6 col-sm-6 col-xs-12 form-group has-feedback">
#Html.TextBoxFor(m => m.PhoneNumber, new { #class = "form-control has-feedback-left", placeholder = "Teléfono" })
<span class="fa fa-phone form-control-feedback left" aria-hidden="true"></span>
</div>
<div class="item col-md-12 col-sm-12 col-xs-12 form-group">
#Html.DropDownListFor(m => m.City, new SelectList(new List<SelectListItem>()), new { style = "width: 100%" })
</div>
<div class="item col-md-12 col-sm-12 col-xs-12 form-group">
#Html.DropDownListFor(m => m.Role, new SelectList(new List<SelectListItem>()), new { style = "width: 100%" })
</div>
<div class="item col-md-12 col-sm-12 col-xs-12 form-group">
#Html.DropDownListFor(m => m.Empresas, new SelectList(new List<SelectListItem>()), new { style = "width: 100%", multiple = "multiple" })
</div>
<div class="item col-md-12 col-sm-12 col-xs-12 form-group">
Está Vigente
#Html.CheckBoxFor(m => m.Vigente, new { #class = "flat" })
</div>
}
Please change the type of City Property in UserViewModal
public string City { get; set; }
Then it will return selected option value to controller for e.g
<select
<option value="1">Delhi </option>
<option value="2">Surat </option>
</select>
if you select Delhi then it will assign value 1 to property
I wonder there's show nothing in your dropdown.
In your view model, it should contain at least two properties, such as AvailableCities and City.
public List<SelectListItem> AvailableCities { get;set; }
public string City { get;set; }
AvailableCities contains all cities which should show in dropdow. And the City is using for getting the value user selected.
In your view,
#Html.DropDownListFor(m => m.City, Model.AvailableCities, new { #class = "form-control" })
For now, you should see the dropdown shawn and which could get the selected value in your action.

Models in viewmodel gave me null error while they are'nt null

I'm developing a Asp.net MVC 5 webApplication with Razor Engine. I have a layout that shows some data from this models: (Footers , FooterMenus , SocialNetworks) from db , and I have a view named register.cshtml that shows a Form page to add user . I want to add layout to register.cshtml but I don't know how write a ViewModel for this . I wrote these codes below but Footers , FooterMenu , SocialNetworks shows anything because of this code in RegisterVM:
public RegisterVM()
{
//Initialize these properties to empty list.
this.Footers = new List<Footer>();
this.FooterMenus = new List<FooterMenu>();
this.SocialNetworks = new List<SocialNetwork>();
this.Users = new List<User>();
}
If I remove this code , it gave me an compiler error and says models are null. How should I solve these ?!
I'm working for 3 days on this error :(
RegisterVM.cs
public class RegisterVM
{
public int UserID { get; set; }
public string UserEmail { get; set; }
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserPassWord { get; set; }
public string UserCellPhone { get; set; }
public string UserTell { get; set; }
public string UserImage { get; set; }
public string UserAddress { get; set; }
public Nullable<byte> UserStatus { get; set; }
public Nullable<System.DateTime> UserBirthDate { get; set; }
public string UserGender { get; set; }
public List<SocialNetwork> SocialNetworks { get; set; }
public List<Footer> Footers { get; set; }
public List<FooterMenu> FooterMenus { get; set; }
public List<User> Users { get; set; }
public RegisterVM()
{
//Initialize these properties to empty list.
this.Footers = new List<Footer>();
this.FooterMenus = new List<FooterMenu>();
this.SocialNetworks = new List<SocialNetwork>();
this.Users = new List<User>();
}
}
Controller :
[HttpGet]
public ActionResult Register()
{
RegisterVM vm = new RegisterVM();
vm.UserAddress = "";
vm.UserBirthDate = DateTime.Now;
vm.UserCellPhone = "";
vm.UserEmail = "";
vm.UserFirstName = "";
vm.UserGender = "";
vm.UserID = 1;
vm.UserImage = "";
vm.UserLastName = "";
vm.UserPassWord = "";
vm.UserStatus = 1;
vm.UserTell = "";
return View(vm);
}
[HttpPost]
public ActionResult Register(User user)
{
UserRepositories bluser = new UserRepositories();
if(ModelState.IsValid)
{
if(bluser.Add(user))
{
//Succsess
}
else
{
//un Succsess
}
}
else
{
//error
}
return View();
}
RegisterLayout.cshtml
#model NP1.ViewModels.RegisterVM
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - My ASP.NET Application</title>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#RenderSection("styles", false)
</head>
<body style="width: 100% !important; padding: 0px; overflow-x: hidden;">
//menu is here //
<div>
#RenderBody()
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", false)
</div>
<div>
<footer class="footer text-center FooterFont hidden-xs" style="bottom: 0;overflow:hidden; text-align: center; color: GrayText; clear: both; margin-bottom: -30px; background-color: #191919 !important; padding-top: 20px;">
<div class=" text-center" style="background-color:#191919 !important; padding-bottom:20px;width:100%;text-align:center;">
<ul style="text-align: center; background-color: #191919; list-style-type: none; display: inline-block; vertical-align: top;" class="list-group col-lg-4 col-md-4 col-xs-12 col-sm-4">
<li class="list-group-item">
#foreach (var item in Model.Footers)
{
<ul style="text-align: center; list-style-type: none; background-color: #191919;">
<li class="list-group-item">
<a class="aFooter" href="#item.FooterLink">
<span>#item.FooterName</span>
</a>
</li>
</ul>
}
</li>
</ul>
<ul style="border-right: 1px graytext solid; border-left: 1px graytext solid; text-align: center; list-style-type: none; display: inline-block; vertical-align: top;background-color:#191919;" class="list-group col-lg-4 col-md-4 col-xs-12 col-sm-4">
<li class="list-group-item">
#foreach (var item in Model.FooterMenus)
{
<ul style="text-align:center;list-style-type:none;">
<li class="list-group-item">
<a class="aFooter" href="#item.FooterMenuLink">
<span>#item.FooterMenuName</span>
</a>
</li>
</ul>
}
</li>
</ul>
<ul style="text-align: center; list-style-type: none; display: inline-block; vertical-align: top;" class="list-group col-lg-4 col-md-4 col-xs-12 col-sm-4">
<li class="list-group-item">
#foreach (var item in Model.SocialNetworks)
{
<ul style="text-align:center;list-style-type:none;padding-top:15px;">
<li>
<a class="aFooter" href="#item.SocialLink">
<img class="img-responsive center-block socialIcon" src="#Url.Content(item.SocialIcon.ToString())" />
</a>
</li>
</ul>
}
</li>
</ul>
</div>
</footer>
<footer class="footer text-center FooterFont visible-xs" style="bottom: 0;overflow:hidden; text-align: center; color: GrayText; clear: both; margin-bottom: -30px; background-color: #191919 !important; padding-top: 20px;">
<div class=" text-center" style="background-color:#191919 !important; padding-bottom:20px;width:100%;text-align:center;">
<ul style="text-align: center; list-style-type: none; display: inline-block; vertical-align: top;" class="list-group col-lg-4 col-md-4 col-xs-6 col-sm-4">
<li class="list-group-item">
#foreach (var item in Model.Footers)
{
<ul style="text-align:center;list-style-type:none;">
<li class="list-group-item">
<a class="aFooter" href="#item.FooterLink">
<span>#item.FooterName</span>
</a>
</li>
</ul>
}
</li>
</ul>
<ul style=" text-align: center; list-style-type: none; display: inline-block; vertical-align: top;" class="list-group col-lg-4 col-md-4 col-xs-6 col-sm-4">
<li class="list-group-item">
#foreach (var item in Model.FooterMenus)
{
<ul style="text-align:center;list-style-type:none;">
<li class="list-group-item">
<a class="aFooter" href="#item.FooterMenuLink">
<span>#item.FooterMenuName</span>
</a>
</li>
</ul>
}
</li>
</ul>
<ul style="text-align: center; list-style-type: none; vertical-align: top;">
<li>
#foreach (var item in Model.SocialNetworks)
{
<ul class="list-inline" style="text-align:center;list-style-type:none;">
<li class="col-xs-3">
<a style="padding:3px;" class="aFooter" href="#item.SocialLink">
<img class="img-responsive center-block socialIcon" src="#Url.Content(item.SocialIcon.ToString())" />
</a>
</li>
</ul>
}
</li>
</ul>
</div>
</footer>
</div>
Register.cshtml
#model NP1.ViewModels.RegisterVM
#{
ViewBag.Title = "register";
Layout = "~/Views/Shared/_RegisterLayout.cshtml";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.UserEmail, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserEmail)
#Html.ValidationMessageFor(model => model.UserEmail)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserFirstName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserFirstName)
#Html.ValidationMessageFor(model => model.UserFirstName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserLastName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserLastName)
#Html.ValidationMessageFor(model => model.UserLastName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserPassWord, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserPassWord)
#Html.ValidationMessageFor(model => model.UserPassWord)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserCellPhone, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserCellPhone)
#Html.ValidationMessageFor(model => model.UserCellPhone)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserTell, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserTell)
#Html.ValidationMessageFor(model => model.UserTell)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserImage, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserImage)
#Html.ValidationMessageFor(model => model.UserImage)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserAddress, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserAddress)
#Html.ValidationMessageFor(model => model.UserAddress)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserBirthDate, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserBirthDate)
#Html.ValidationMessageFor(model => model.UserBirthDate)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserGender, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserGender)
#Html.ValidationMessageFor(model => model.UserGender)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
If you are using C#6 or higher you can use default properties
//default properties in C#6
public class RegisterVM
{
public int UserID { get; set; } =1;
public string UserEmail { get; set; } ="";
public string UserFirstName { get; set; } ="";
public string UserLastName { get; set; } ="";
public string UserPassWord { get; set; } ="";
public string UserCellPhone { get; set; } ="";
public string UserTell { get; set; } ="";
public string UserImage { get; set; } ="";
public string UserAddress { get; set; } ="";
public Nullable<byte> UserStatus { get; set; }
public Nullable<System.DateTime> UserBirthDate { get; set; } = DateTime.Now;
public string UserGender { get; set; } ="";
public List<SocialNetwork> SocialNetworks { get; set; }
public List<Footer> Footers { get; set; }
public List<FooterMenu> FooterMenus { get; set; }
public List<User> Users { get; set; }
public RegisterVM()
{
this.Footers = new List<Footer>();
this.FooterMenus = new List<FooterMenu>();
this.SocialNetworks = new List<SocialNetwork>();
this.Users = new List<User>();
}
}
However the main issue is you are not mapping the viewmodel to the database model.
You are also receiving your database model in the post instead of the viewwmodel.
Controller:
[HttpGet]
public ActionResult Register()
{
RegisterVM vm = new RegisterVM();
return View(vm);
}
[HttpPost]
public ActionResult Register(RegisterVM vm)
{
UserRepositories bluser = new UserRepositories();
if(ModelState.IsValid)
{
User user = new User();
user.Id=vm.UserID;
user.FirstName=vm.UserFirstName;
user.UserLastName=vm.UserLastName;
//etc
if(bluser.Add(user))
{
//Succsess
}
else
{
//un Succsess
}
}
else
{
//error
}
return View();
}

Resources