Strange behaviour of ASP.NET MVC - c#

I have the following model:
public class EditUserViewModel : AddEditUserViewModelPartial
{
public string OldUsername { get; set; }
public int UserId { get; set; }
public bool? NewPasswordGenerated { get; set; }
}
public class AddEditUserViewModelPartial
{
[Required]
[Display(Name = "Username/Email")]
public string UserName { get; set; }
[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; }
....
public class AddEditUserPartial
{
public TypeOfForm Type { get; set; }
public AddEditUserViewModelPartial Model { get; set; }
}
public enum TypeOfForm
{
ADD,
EDIT
}
Partial Name:
#model CHFN.Models.AddEditUserPartial
<div class="form-group">
#Html.LabelFor(m => m.Model.UserName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Model.UserName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Model.UserName)
</div>
</div>
....
Edit User:
#model CHFN.Models.EditUserViewModel
#Html.AntiForgeryToken()
<h4>Edit the account.</h4>
<hr />
#Html.HiddenFor(p => p.OldUsername)
#Html.HiddenFor(p => p.UserId)
#Html.HiddenFor(p => p.NewPasswordGenerated)
#Html.ValidationSummary(true)
#Html.Partial("PartialAddEditUser",
new CHFN.Models.AddEditUserPartial()
{
Type = CHFN.Core.TypeOfForm.EDIT,
Model = new CHFN.Models.AddEditUserViewModelPartial() { UserName = Model.UserName, Fullname = Model.Fullname, Roles = Model.Roles, Password = Model.Password, ConfirmPassword = Model.ConfirmPassword }
})
to EditUser (post) is went an empty OldUsername, UserId, NewPasswordGenerated. And, more surprised for me, if I remove Html.Partial("PartialAddEditUser",...) - then OldUsername, UserId, NewPasswordGenerated is not empty. Why it happens?

The problem seems to be that you are using different models for the main view and the partial view.
Consider the following line in your partial view:
#Html.LabelFor(m => m.Model.UserName, ...)
When you post the data back to an action that expect (I assume) EditUserViewModel as the input model, MVC will try to find a property named Model on EditUserViewModel (which is not there.), and set the UserName property on that.
The solution may be to simple not use the AddEditUserPartial class at all. The partial call may then look simply like this:
#Html.Partial("PartialAddEditUser", Model);
The partial view could then be simplified to the following (notice we use the exact same model, and thus get rid of the extra .Model):
#model CHFN.Models.EditUserViewModel
<div class="form-group">
#Html.LabelFor(m => m.UserName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.UserName)
</div>
</div>
....

Related

Use two models in one form (view) - ASP.NET MVC

In my form, which I created in a view, the user can press add or search.
If the "add" button is pressed, a different model should be used in the background than with the "search" option. The add model is validated but otherwise does not differ from the search model.
By clicking "search" the user shouldn't be forced to fill in all fields.
Code
Model - AddModel
[Key]
public int Id { get; set; }
[Required]
[Display(Name = "Name")]
[StringLength(200, MinimumLength = 1, ErrorMessage = "Not Allowed")]
public string Name { get; set; }
[Required]
[Display(Name = "Place")]
[RegularExpression(#"^[\w ]*$", ErrorMessage = "Not Allowed")]
public string Place { get; set; }
Model - SearchModel
public int Id { get; set; }
public string Name { get; set; }
public string Place{ get; set; }
Controller
[HttpPost, ValidateAntiForgeryToken]
public IActionResult Add(AddModel p) {
if (ModelState.IsValid) {
_ = InsertData(p);
ModelState.Clear();
return RedirectToAction("Add", new { Success = true });
}
return View();
}
public IActionResult Select(SearchModel p)
{
Task.WaitAll(SelectData(p));
return View(per); // per => list of selected data
}
View
#model **AddModel**
#if (ViewBag.success)
{
...
}
<form method="POST">
<div class="form-group">
#Html.LabelFor(m => m.Name, new { })
#Html.EditorFor(m => m.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(m => m.Name, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Place, new { })
#Html.EditorFor(m => m.Place, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(m => m.Place, "", new { #class = "text-danger" })
</div>
<input asp-action="Add" type="submit" class="btn btn-outline-primary" value="Add" />
<input asp-action="Select" type="submit" class="btn btn-outline-success" value="Search" />
</form>
The AddModel is still used in the View, but I would like to specify in the controller which model I would like to use. So if you press "search" the SearchModel and with "add" the AddModel should be used. I've already tried it with dynamic, but then it came to problems with the #html helpers.
Does somebody has any idea?
Would appreciate ;)
I think what you are looking to do is called a ViewModel, this should help : https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-3

Update ViewModel after dynamically updating the view

I am trying to define ViewModels that faithfully represent the view (to make strict use of that concept).
Some of the elements of the ViewModel are updated dynamically. The problem I have, is that when I do the Post, the ViewModel returns without the elements that were updated dynamically.
The update is done through jQuery, when an event is performed. An action is invoked through Url.Action, and a Div is updated.
I made an example to clarify the scenario. An application that only stores a location (state and city). For this I have three ViewModels: one to represent the States in a SelectList, one to represent the Cities in a SelectList, and finally one to represent the Location (formed by the two ViewModel that I mentioned first).
Models:
public class State
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
public class City
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int StateId { get; set; }
public virtual State State { get; set; }
}
ViewModels:
public class CitySelectListViewModel
{
public CitySelectListViewModel() { }
public CitySelectListViewModel(IEnumerable<Models.City> cities)
{
this.Cities = cities;
}
[Display(Name = "Cities")]
[Required]
public int? SelectedCityId { get; set; }
public IEnumerable<City> Cities { get; }
}
public class StateSelectListViewModel
{
public StateSelectListViewModel() { }
public StateSelectListViewModel(IEnumerable<State> states)
{
this.States = states;
}
[Display(Name = "States")]
[Required]
public int? SelectedStateId { get; set; }
public IEnumerable<State> States { get; }
}
public class LocationCreateViewModel
{
public LocationCreateViewModel() { }
public LocationCreateViewModel(ICollection<State> states)
{
this.StateSelectListViewModels = new StateSelectListViewModel(states);
this.CitySelectListViewModel = new CitySelectListViewModel();
}
public StateSelectListViewModel StateSelectListViewModels { set; get; }
public CitySelectListViewModel CitySelectListViewModel { set; get; }
}
Location [Controller]:
public class LocationController : Controller
{
private DALDbContext db = new DALDbContext();
// GET: Location/Create
public ActionResult Create()
{
LocationCreateViewModel locationCreateViewModel = new LocationCreateViewModel(db.States.ToList());
return View(locationCreateViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(LocationCreateViewModel pLocationCreateViewModel)
{
if (ModelState.IsValid)
{
//db.States.Add(state);
//db.SaveChanges();
return RedirectToAction("Index", "Home");
}
LocationCreateViewModel locationCreateViewModel = new LocationCreateViewModel(db.States.ToList());
return View(locationCreateViewModel);
}
public ActionResult CitySelectList(int? stateId)
{
CitySelectListViewModel citySelectListViewModel = new CitySelectListViewModel(db.Cities.Where(c => c.StateId == stateId).ToList());
return View(citySelectListViewModel);
}
}
Create [View]:
#model ViewModelExample.ViewModels.LocationCreateViewModel
....
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>State</h4>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.StateSelectListViewModels.SelectedStateId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.StateSelectListViewModels.SelectedStateId, new SelectList(Model.StateSelectListViewModels.States, "Id", "Name"), "Select a State", htmlAttributes: new { #class = "form-control", #id = "StateSelectList" })
#Html.ValidationMessageFor(model => model.StateSelectListViewModels.SelectedStateId, "", new { #class = "text-danger" })
</div>
</div>
<div id="CityContainer">
#Html.Action("CitySelectList")
</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>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(function () {
// Fill City DropDownList
$('#StateSelectList').change(function () {
var selectedStateId = this.value;
$('#CityContainer').load('#Url.Action("CitySelectList")?stateId=' + selectedStateId);
});
});
</script>
}
CitySelectList [View]:
#model ViewModelExample.ViewModels.CitySelectListViewModel
....
<div class="form-group">
#Html.LabelFor(model => model.SelectedCityId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedCityId, new SelectList(Model.Cities, "Id", "Name"), "Select a City", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.SelectedCityId, "", new { #class = "text-danger" })
</div>
</div>
I will show the execution of my example, and I will show the problem through the inspection of the ViewModel that I receive after the Post:
I select a State and a City, and I press Create.
I inspect the ViewModel received after the Post. We can see how CitySelectListViewModel is null, and what I want is to bring the last ViewModel that was updated through jQuery.
I admit that I have provided a long example, but it is the only way I found to explain what I need. Thanks in advance.
VS-Project of the example
I'ts because you are preventing the modelBinder to accurately bind to LocationCreateViewModel in your Create action when replacing the inner HTML of <div id="CityContainer"> (thats what you do with $('#CityContainer').load(...). You instruct the model binder to bind to
#model ViewModelExample.ViewModels.CitySelectListViewModel and as a result you get this HTML for the city select list:
One way of solving this is modifying CitySelectList.cshtml to:
#model ViewModelExample.ViewModels.LocationCreateViewModel
#{
Layout = null;
}
<div class="form-group">
#Html.LabelFor(model => model.CitySelectListViewModel.SelectedCityId,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model =>
model.CitySelectListViewModel.SelectedCityId, new
SelectList(Model.CitySelectListViewModel.Cities, "Id", "Name"), "Select a City", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CitySelectListViewModel.SelectedCityId, "", new { #class = "text-danger" })
</div>
</div>
and your CitySelectList action to:
public ActionResult CitySelectList(int? stateId)
{
LocationCreateViewModel locationCreateViewModel = new LocationCreateViewModel();
locationCreateViewModel.CitySelectListViewModel = new CitySelectListViewModel(db.Cities.Where(c => c.StateId == stateId).ToList());
return View(locationCreateViewModel);
}
But I would recommend custom model binding as well.

Why is my View not displaying value of ViewBag?

I have a little blog application with posts and tags. This is my model for Post:
namespace HelloWorld.Models
{
public class Post
{
[Required]
[DataType(DataType.Text)]
public string Title { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime PostDate { get; set; }
public List<Tag> Tags { get; set; }
[Required]
public int PostId { get; set; }
}
public class CreatePostView
{
[Required]
[DataType(DataType.Text)]
public string Title { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Display(Name = "Tags")]
[Required(ErrorMessage = "Please select a tag")]
public string SelectedTag { get; set; }
public SelectList TagList { get; set; }
[Required]
public int PostId { get; set; }
}
}
And model of Tag consist of string TagName, int TagId, List Posts.
When I create a new Post I use CreatePostView and my view is:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="create-post-form">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<strong>Title</strong>
<div class="col-md-10">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<strong>Description</strong>
<div class="col-md-10">
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
#Html.DropDownListFor(m => m.SelectedTag, Model.TagList, "Add tag")
#Html.ValidationMessageFor(m => m.SelectedTag)
<div class="post-create-button">
<input type="submit" value="Create">
</div>
<div class="back-to-list-button">
#Html.ActionLink("Back", "Index")
</div>
</div>
}
And now I want to display my tag that I selected. I put value of selected tag in ViewBag, but it does not display. Maybe it's silly, but I do not know how to fix it. My Create action of PostsController:
// POST: Posts/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreatePostView post)
{
Post currPost = new Post {
Title = post.Title,
Description = post.Description,
PostDate = DateTime.Now,
Tags = null };
ViewBag.Tag = post.SelectedTag.ToString();
ViewBag.Trash = "texttexttexttexttext"; // It's strange, but it not displayed.
if (ModelState.IsValid)
{
//var tags = db.Tags.Where(s => s.TagName.Equals(post.SelectedTag)).ToList();
//currPost.Tags = tags;
db.Posts.Add(currPost);
db.SaveChanges();
return RedirectToAction("Index", "Posts");
}
return View(currPost);
}
My view with all Posts (use model Post)
#foreach (var item in Model)
{
<article class="post">
<h3>#Html.DisplayFor(modelItem => item.Title)</h3>
<p>#Html.DisplayFor(modelItem => item.Description)</p>
<!--None of them is not shown-->
<p><strong>Tag: #ViewBag.Tag</strong></p>
<p><strong>Trash: #ViewBag.Trash</strong></p>
</article>
}
ViewBag is used when returning a view, not when redirecting to another action. Basically it doesn't persist across separate requests. Try using TempData instead:
TempData["Tag"] = post.SelectedTag.ToString();
and in the view:
<p><strong>Tag: #TempData["Tag"]</strong></p>

Model Invalidation in Model view viewmodel controller

I am new to ASP.NET MVC 5. I am trying to make a user-management software. but in the user registration(create) controller my model is getting invalidated. Don't know why. I might have a mistake in my model Binding. Here is the attached code. Any Help is appreciated.
Model file
public class UserData
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int userid { get; set; }
[Required(ErrorMessage = "Domain ID")]
[Display(Name = "Domain ID")]
public string domainid { get; set; }
[Required(ErrorMessage = "Choose Role")]
[Display(Name = "Role")]
public string role { get; set; }
[Required(ErrorMessage = "Choose Country")]
[Display(Name = "Country")]
public string country { get; set; }
[Required(ErrorMessage = "Choose BU")]
[Display(Name = "BU")]
public string bu { get; set; }
[Required]
[RegularExpression(#"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))#"
+ #"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
[0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
+ #"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
+ #"([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$", ErrorMessage = "Please Provide Valid Email-ID")]
[Display(Name = "Email"),DataType(DataType.EmailAddress)]
public string email { get; set; }
[HiddenInput(DisplayValue=true)]
public DateTime date_from { get; set; }
[HiddenInput(DisplayValue = true)]
public DateTime date_to { get; set; }
[HiddenInput(DisplayValue=true)]
public bool active { get; set; }
}
ViewModel File
public class UserRegistrationViewModel
{
public UserData userdata { get; set; }
public string SelectedRole { get; set; }
public IEnumerable<SelectListItem> RoleList { get; set; }
public string SelectedCountry { get; set; }
public IEnumerable<SelectListItem> CountryList { get; set; }
public string SelectedBU { get; set; }
public IEnumerable<SelectListItem> BUList { get; set; }
}
Controller file
public class UserDatasController : Controller
{
private ApplicationDataContext db = new ApplicationDataContext();
// GET: UserDatas
public ActionResult Index()
{
return View(db.UsersData.ToList());
}
public ActionResult Create()
{
var model = new UserRegistrationViewModel();
model.CountryList = from p in XDocument.Load("C:/Users/inkosah/Documents/Visual Studio 2013/Projects/Policy Assessment/Policy Assessment/country_list.xml").Descendants("Name")
//var a=Path.GetFullPath("Policy Asse")
let value = (string)p.Element("Text")
select new SelectListItem
{
Selected = (value == model.SelectedCountry),
Text = (string)p.Element("Text"),
Value = value
};
model.BUList = from q in XDocument.Load("C:/Users/inkosah/Documents/Visual Studio 2013/Projects/Policy Assessment/Policy Assessment/bu_list.xml").Descendants("BU")
let value2 = (string)q.Element("BU_Name")
select new SelectListItem
{
Selected = (value2 == model.SelectedBU),
Text = (string)q.Element("BU_Name"),
Value = value2
};
model.RoleList = from n in XDocument.Load("C:/Users/inkosah/Documents/Visual Studio 2013/Projects/Policy Assessment/Policy Assessment/UserRoleList.xml").Descendants("Role")
let value1 = (string)n.Element("Role_Name")
select new SelectListItem
{
Selected = (value1 == model.SelectedRole),
Text = (string)n.Element("Role_Name"),
Value = value1
};
return View(model);
}
// POST: UserDatas/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "SelectedRole,SelectedCountry,SelectedBU")]UserRegistrationViewModel RegisterData,[Bind(Include="domainid,email")] UserData userdata)
{
userdata.date_from = DateTime.Now;
userdata.date_to = DateTime.MaxValue;
userdata.active = false;
userdata.role = RegisterData.SelectedRole;
userdata.bu = RegisterData.SelectedBU;
userdata.country = RegisterData.SelectedCountry;
if (ModelState.IsValid)
{
db.UsersData.Add(userdata);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(userdata);
}
create.cshtml
#model Policy_Assessment.ViewModels.UserRegistrationViewModel
#{
ViewBag.Title = "User Registration Page";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>User Input</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.userdata.domainid, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.userdata.domainid)
#Html.ValidationMessageFor(model => model.userdata.domainid)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.userdata.role, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#*#Html.EditorFor(model => model.role)*#
#Html.DropDownListFor(model => model.SelectedRole, Model.RoleList, "-----Role-----")
#Html.ValidationMessageFor(model=>model.SelectedRole)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.userdata.country, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#*#Html.EditorFor(model => model.country)*#
#Html.DropDownListFor(model => model.SelectedCountry,Model.CountryList,"----Country-----")
#Html.ValidationMessageFor(model => model.userdata.country)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.userdata.bu, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model=>model.SelectedBU,Model.BUList,"--Select BU----")
#Html.ValidationMessageFor(model => model.userdata.bu)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.userdata.email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.userdata.email)
#Html.ValidationMessageFor(model => model.userdata.email)
</div>
</div>
#*<div class="form-group">
#Html.HiddenFor(model => model.userdata.date_from, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.HiddenFor(model => model.userdata.date_from)
#Html.ValidationMessageFor(model => model.userdata.date_from)
</div>
</div>
<div class="form-group">
#Html.HiddenFor(model => model.userdata.date_to, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.HiddenFor(model => model.userdata.date_to)
#Html.ValidationMessageFor(model => model.userdata.date_to)
</div>
</div>
<div class="form-group">
#Html.HiddenFor(model => model.userdata.active, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.HiddenFor(model => model.userdata.active)
#Html.ValidationMessageFor(model => model.userdata.active)
</div>
</div>*#
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Register" class="btn btn-default" />
</div>
</div>
</div>
}
#*<div>
#Html.ActionLink("Back to List", "Index")
</div>*#
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
Context File
public class ApplicationDataContext : DbContext
{
public ApplicationDataContext()
: base("DefaultConnection")
{ }
public System.Data.Entity.DbSet<Policy_Assessment.ViewModels.UserRegistrationViewModel> UserRegistrationData { get; set; }
public System.Data.Entity.DbSet<Policy_Assessment.Models.UserData> UsersData { get; set; }
}
Please Note i am a beginner in MVC ASP.Net. Any Help or Explanation would be helpful.
Your posting back your data model (included as a property of your view model). The data model has a [Required] attribute for property role but you are creating a control for this property so nothing is bound, meaning its null and therefore its invalid. Two ways to solve this.
A. Remove property string SelectedRole from the view model and bind directly to the the data model that's included in the view model
#Html.DropDownListFor(m => m.userdata.role, Model.RoleList, ...)
Now, userdata.role will contain the selected option value and will be valid (note you would need to do this for the other 2 properties as well).
B. Remove property UserData userdata from the view model and include in the view model the properties from UserData that you are editing
public class UserRegistrationViewModel
{
[Required(ErrorMessage = "Domain ID")]
[Display(Name = "Domain ID")]
public string domainid { get; set; }
[Required(ErrorMessage = "Choose Role")]
[Display(Name = "Role")]
public string role { get; set; }
[Required(ErrorMessage = "Choose Country")]
[Display(Name = "Country")]
public string country { get; set; }
[Required(ErrorMessage = "Choose BU")]
[Display(Name = "BU")]
public string bu { get; set; }
[Required]
[Display(Name = "Email"),DataType(DataType.EmailAddress)]
[EmailAddress]
public string email { get; set; }
public SelectList RoleList { get; set; }
public SelectList CountryList { get; set; }
public SelectList BUList { get; set; }
}
Note I've excluded properties you don't appear to be editing, used [EmailAddress] rather than your Regex (could not see what the regex was doing that an EmailAddress attribute is not already doing) and used SelectList rather than IEnumerable<SelectListItem> which means you can simplify it to
public ActionResult Create()
{
var model = new UserRegistrationViewModel();
var roles = from n in XDocument.Load(....
model.RoleList = new SelectList(roles, "value", "value");
....
return View(model);
}
and then in the POST method, map the properties from the view model to a new instance of the data model, setting the other properties such as date_from if required (alternatively you could put these default values in a constructor) and save to the database.

Pass a model to a partial view?

this is my partial:
#model RazorSharpBlog.Models.MarkdownTextAreaModel
<div class="wmd-panel">
<div id="wmd-button-bar-#Model.Name"></div>
#Html.TextAreaFor(m => m.Name, new { #id = "wmd-input-" + #Model.Name, #class = "wmd-input" })
</div>
<div class="wmd-panel-separator"></div>
<div id="wmd-preview-#Model.Name" class="wmd-panel wmd-preview"></div>
<div class="wmd-panel-separator"></div>
I'm trying to include it like this in my View:
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.Title)
#Html.TextBoxFor(m => m.Title)
#Html.Partial("MarkdownTextArea", new { Name = "content" })
<input type="submit" value="Post" />
}
these are the model classes:
public class MarkdownTextAreaModel
{
[Required]
public string Name { get; set; }
}
public class BlogContentModel
{
[Required]
[Display(Name = "Post Title")]
public string Title { get; set; }
[Required]
[DataType(DataType.MultilineText)]
[Display(Name = "Post Content")]
public string Content { get; set; }
}
What am I doing wrong, how should I do this in order to make my partial reusable?
Your partial expects an instance of the MarkdownTextAreaModel class. So do so, instead of passing an anonymous object which would throw anyways:
#Html.Partial("MarkdownTextArea", new MarkdownTextAreaModel { Name = "content" })
Now this being said a far better solution would be to adapt your view model, so that it contains a reference to MarkdownTextAreaModel and use editor templates instead of partials in your views, just like so:
public class BlogContentModel
{
[Required]
[Display(Name = "Post Title")]
public string Title { get; set; }
[Required]
[DataType(DataType.MultilineText)]
[Display(Name = "Post Content")]
public string Content { get; set; }
public MarkdownTextAreaModel MarkDown { get; set; }
}
then of course readapt the controller serving this view so that it populates the MarkDown of your view model:
public ActionResult Foo()
{
BlogContentModel model = .... fetch this model from somewhere (a repository?)
model.MarkDown = new MarkdownTextAreaModel
{
Name = "contect"
};
return View(model);
}
and then inside your main view simply:
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.Title)
#Html.TextBoxFor(m => m.Title)
#Html.EditorFor(x => x.MarkDown)
<input type="submit" value="Post" />
}
and then in order to follow standard conventions move your partial to ~/Views/YourControllerName/EditorTemplates/MarkdownTextAreaModel.cshtml and now everything will magically come into place as it should.
#using (Html.BeginForm()) {
#Html.LabelFor(m => m.Title) #Html.TextBoxFor(m => m.Title)
#Html.Partial("MarkdownTextArea", new MarkdownTextAreaModel { Name = "content" })
<input type="submit" value="Post" />
}

Categories

Resources