code is:
#using (Html.BeginForm("Register", "User", FormMethod.Post, new { id = "RegisterForm" }))
{
#Html.DropDownList("StateId", new SelectList(Model.States, "StateId", "StateName"),
"--Select an option--", new { #tabindex = "11" })
}
i need required field validation for dropdown
Have you tried using Data Annotations in your model to mark the property as required?
[Required(ErrorMessage = "You must select a State")]
Are you exposing the StateId as a part of the Model? If so that's where you should set the Required Attribute, like so:
[Required(ErrorMessage = "You must select a State")]
public int StateId { get; set; }
Related
I am building a simple ASP.NET MVC 3 site, using Entity Framework to build the model based on some tables in an already existing Oracle database (in other words, I used the 'database first' methodology to have my model built). I now have a simple blog type site, which I am quite familiar with as I have been learning MVC in a number of languages.
I want to change some of the auto-generated views. One piece I would like to change in particular is that I have a field in one of my tables called 'Visible'. This is simply a numeric value (0 or 1) indicating whether or not a display application should use the row as display data. Currently, I have the simple text field that is auto-generated:
<div class="editor-field">
#Html.EditorFor(model => model.VISIBLE)
#Html.ValidationMessageFor(model => model.VISIBLE)
</div>
What I would like to do is replace this with a drop down box with string values like True and False. The application should display any entry with a 0 as false and vice versa. If a user wants to flip the toggle, the drop down should allow them to do that and understand to make the numeric update when clicking submit. How can this be done?
I have seen countless examples where the drop-down was going to be filled with more then just two values, and in those cases I understand that you can add logic to your controller that pulls all the distinct values, puts them in a list, then adds the list to the ViewBag. However, in my case with only two possible numeric values, it seems like there should be a simpler, more accepted way to do it.
Any help is greatly appreciated.
UPDATE
Following Quinton's answer, I am trying to place said code in my model. Here is my current model:
namespace CurrentActivityBlog
{
using System;
using System.Collections.Generic;
using System.Web.UI.WebControls;
public partial class TBLCURRENTACTIVITY
{
public string TITLE { get; set; }
public string DESCRIPTION { get; set; }
public System.DateTime DATETIME { get; set; }
public short VISIBLE { get; set; }
public decimal ID { get; set; }
public IEnumerable<SelectedListItem> PossibleValues { get; set; }
public TBLCURRENTACTIVITY() {
PossibleValues = new[] { new SelectListItem { Value = "0", Text = "Hidden" },
new SelectListItem { Value = "1", Text = "Visible" } };
}
}
}
I am unable to build this solution, but Visual Studio 2010 is telling me that
"the type or namespace name 'SelectedListItem' could not be found (are you missing a using directive or an assembly reference?)"
As you can see, I have
using System.Web.UI.controls
and have added the reference to System.Web. Is there anything I am forgetting, or anything I should know about (such as models generated using EF behaving differently then one might expect, etc.)?
Thanks again.
The one line solution to it would be:
#Html.DropDownList(Model.VISIBLE.ToString(), new [] {new SelectListItem { Value = "0", Text = "Hidden"}, new SelectListItem { Value = "1", Text = "Visible"}})
but you probably don't want domain logic in your view. So add the possible items to your Model (or from the controller):
public class MyModel {
public int VISIBLE { get; set; }
public IEnumerable<SelectListItem> PossibleValues { get; set; }
public MyModel() {
PossibleValues = new[] { new SelectListItem { Value = "0", Text = "Hidden" }, new SelectListItem { Value = "1", Text = "Visible" } };
}
}
and then your razor code:
#Html.DropDownList(Model.VISIBLE.ToString(), Model.PossibleValues)
Obviously "Hidden" and "Visible" descriptions can be replaced with "False" and "True" or whatever.
You could also create and Editor and Display Template for that specific field. Checkout ScottGu's blog post here, search for "UI Helper Templating Support" and you'll see how to create a editor template and how to render a specific template by name.
EDIT:
If your model is not part of your MVC project, then referencing any classes that are in the MVC assemblies would require a explicit add reference. You can avoid this though by initializing any MVC assembly types in your model from your controller, like such:
public class MyModel {
public int VISIBLE { get; set; }
public IEnumerable<SelectListItem> PossibleValues { get; set; }
}
controller action method:
public ActionResult Edit(int Id) {
...
myModelInstance. PossibleValues = new[] { new SelectListItem { Value = "0", Text = "Hidden" }, new SelectListItem { Value = "1", Text = "Visible" } };
...
Return View(myModel);
}
I feel like I'm taking crazy pills. I have a dropdownlist for a view that reads from our database all of the wine producers we have. I want to set the selectedValue to a particular ID driven by the referring page. I can see it picks up the selectedValue in debug, I see the selected value populated (906 for this example), but it doesn't set the dropdownlist to the correct value when the page is rendered, it always defaults to 1 for the default value. I've tried creating the selectList in razor as opposed to my controller, but nothing works. Any help on this would be appreciated, I'm guessing it is something small.
Controller:
if (User.IsInRole("admin"))
{
if (ID != 0)
{
ViewBag.ProducerSelect = new SelectList(db.Producers.OrderBy(p => p.Name), "ProducerID", "Name", ID);
}
else
{
ViewBag.ProducerSelect = new SelectList(db.Producers.OrderBy(p => p.Name), "ProducerID", "Name");
}
}
View:
if (User.IsInRole("producereditor"))
{
<h3>#ViewBag.ProducerName</h3>
}
else
{
<div class="editor-label">
#Html.LabelFor(m => m.Wine.ProducerID, "Producer")
</div>
<div class="editor-field">
#Html.DropDownListFor(m => m.Wine.ProducerID, ViewBag.ProducerSelect as SelectList)
</div>
}
Tried the below but no success:
ViewBag.ProducerSelect = new SelectList(from p in db.Producers
orderby p.Name
select new { p.ProducerID, p.Name }
, "ProducerID", "Name", ID);
If you want to preselect an item, You set that value to your ProducerId property.
var yourViewModelObj=new YourViewModel;
yourViewModelObj.Wine.ProducerId=906; //or whatever value you want
return View(yourViewModelObj);
Suggestion : For better code readablity/Maintenance, Try to avoid ViewBag / ViewData and use a ViewModel to pass the data.
I would add a Property to my ViewModel to hold the Collection of Producers
public class WineViewModel
{
//Other Existing properties also
public IEnumerable<SelectListItem> Producers{ get; set; }
public string SelectedProducer { get; set; }
}
Then in yout GetAction method, you can set the value like this, If you want to set one select option as the default selected one.
public ActionResult CreateWine()
{
var vm=new WineViewModel();
//The below code is hardcoded for demo. you mat replace with DB data.
vm.Producers= new[]
{
new SelectListItem { Value = "1", Text = "Prodcer A" },
new SelectListItem { Value = "2", Text = "Prodcer B" },
new SelectListItem { Value = "3", Text = "Prodcer C" }
};
//Now let's set the default one's value
vm.SelectedProducer = "2";
return View(vm);
}
And in your Strongly typed View,
#Html.DropDownListFor(x => x.SelectedProducer,
new SelectList(Model.Producers, "Value", "Text"), "Select Producer")
The HTML Markup generated by above code will have the HTML select with the option with value 2 as selected one.
I figured this out. I had ViewModel.wine.ProducerID elsewhere on the page in a hidden field, and that defaults to 1, so I just assigned that to passed in value, and it worked great. I knew it was something like that. Thanks!
User a ViewModel ex WineViewModel
public class WineViewModel
{
public Wine Wine { get; set; }
public SelectList PProducerList { get; set; }
public WineViewModel() { }
public WineViewModel(Wine wine)
{
this.Wine = wine;
}
}
Try the following in your controller
var model = new WineViewModel( selectwine);
model.ProjectTypeList = new SelectList( from p in db.Producers
orderby p.Name
select new { p.ID, p.Name }, "ID", "Name")
notice how I am exclusively declaring which is the ID and which is the Value in my SelectList
Then in your view do
#Html.DropDownListFor(model => model.Wine.ProducerID, Model.ProjectTypeList)
I have a table that has bit values (true/false)
Table Definition:
CharacterID int
isActive bit
UserId uniqueidentifier
I have 2 problems:
How to display the existing selected option in the edit view in a Dropdown
I need to save the value (yes/No) as true and false in the database.
Here is what I have attempted so far:
<div class="editor-label">
#Html.LabelFor(model => model.IsActive)
</div>
<div class="editor-field">
#Html.DropDownList("", new SelectListItem[] { new SelectListItem() { Text = "Yes", Value = "true", Selected = Model.IsActive }, new SelectListItem() { Text = "No", Value = "false", Selected = !Model.IsActive }})
</div>
Assuming that model.IsActive is declared as bool:
Wouldn't using a CheckBox be a bit more intuitive to the user and require less clicks?
In that case you could just use:
#Html.EditorFor(model => model.IsActive)
If you really want dropdowns, then this SO might provide a working implementation: https://stackoverflow.com/a/4036922/1373170
Applied to your context, I believe it would be:
#Html.DropDownListFor(model => model.IsActive, new SelectList(new SelectListItem[] { new SelectListItem() { Text = "Yes", Value = "True" }, new SelectListItem() { Text = "No", Value = "False"}}, model.IsActive.ToString())
Now, for saving it to the database I'd have to know if you are using EF, L2S, etc.
But I imagine you already have an action in your controller set up for saving. In that case it is probably already receiving an instance of your model as parameter. Using DropDownListFor instead of DropDownList, your model should be bound automatically by MVC's default ModelBinder, and you should be able to map that to your database entity and store it.
There are couple things you need to setup for drop-down and viewmodel property to make this work.
1) Your view model:
public class MyModel
{
public MyModel()
{
BoolSelectList = new List<SelectListItem>();
}
public int CharacterID { get; set; }
public bool isActive { get; set; }
public Guid UserId { get; set; }
public IList<SelectListItem> BoolSelectList { get; set; }
}
2) In controller you need to assign value to bool Value and List
public MyModel viewmodel = new MyModel();
// Set other properties of viewmodel
// ....
// Set Drop-down List values
viewModel.BoolSelectList = new SelectList(new SelectListItem[] { new SelectListItem() { Text = "Yes", Value = "True" }, new SelectListItem() { Text = "No", Value = "False"}};
3) In your view :
#Html.LabelFor(model => model.isActive, "Is Active ")
#Html.DropDownListFor(model => model.isActive, Model.BoolSelectList, model.IsActive.ToString())
On your Post action, the value of IsActive should be True/False depending on your selection.
The DisplayAttribute in System.ComponentModel.DataAnnotations has a GroupName property, which allows you to logically group fields together in a UI control (e.g. a property grid in WPF/WinForms).
I am trying to access this metadata in an ASP.NET MVC3 application, essentially to create a property grid. If my model looks like this:
public class Customer
{
[ReadOnly]
public int Id { get;set; }
[Display(Name = "Name", Description = "Customer's name", GroupName = "Basic")]
[Required(ErrorMessage = "Please enter the customer's name")]
[StringLength(255)]
public string Name { get;set; }
[Display(Name = "Email", Description = "Customer's primary email address", GroupName = "Basic")]
[Required]
[StringLength(255)]
[DataType(DataType.Email)]
public string EmailAddress { get;set; }
[Display(Name = "Last Order", Description = "The date when the customer last placed an order", GroupName = "Status")]
public DateTime LastOrderPlaced { get;set; }
[Display(Name = "Locked", Description = "Whether the customer account is locked", GroupName = "Status")]
public bool IsLocked { get;set; }
}
and my view looks like this:
#model Customer
<div class="edit-customer">
#foreach (var property in ViewData.ModelMetadata.Properties.Where(p => !p.IsReadOnly).OrderBy(p => p.Order))
{
<div class="editor-row">
#Html.DevExpress().Label(settings =>
{
settings.AssociatedControlName = property.PropertyName;
settings.Text = property.DisplayName;
settings.ToolTip = property.Description;
}).GetHtml()
<span class="editor-field">
#Html.DevExpress().TextBox(settings =>
{
settings.Name = property.PropertyName;
settings.Properties.NullText = property.Watermark;
settings.Width = 200;
settings.Properties.ValidationSettings.RequiredField.IsRequired = property.IsRequired;
settings.ShowModelErrors = true;
}).Bind(ViewData[property.PropertyName]).GetHtml()
</span>
</div>
}
</div>
then the form is laid out very nicely based on the metadata, with labels, tooltips, watermarks etc all pulled out of the model's metadata; but, I would like to be able to group the items together, for instance in a <fieldset> per group. Does anyone know how to get the GroupName out of the metadata, short of writing an extension method for ModelMetadata?
GroupName is not parsed by the DataAnnotationsModelMetadataProvider. So there's no way to get it right off the ModelMetadata object, even with an extension method.
You could implement your own provider that extends the existing one to add support for GroupName, which Brad Wilson explains in his blog.
You could also write your own attribute instead of using Display(GroupName = ) and implement the IMetadataAware interface to add the groupname to ModelMetadata.AdditionalValues.
You can also use this Extension Method:
public static class ModelMetadataExtensions
{
public static T GetPropertyAttribute<T>(this ModelMetadata instance)
where T : Attribute
{
var result = instance.ContainerType
.GetProperty(instance.PropertyName)
.GetCustomAttributes(typeof(T), false)
.Select(a => a as T)
.FirstOrDefault(a => a != null);
return result;
}
}
Then
var display= this.ViewData.ModelMetadata
.GetPropertyAttribute<DisplayAttribute>();
var groupName = display.Groupname;
An alternative could be to use the ShortName property of the DisplayAttribute class. It is exposed by the ModelMetadata class as the ShortDisplayName property.
This isn't exactly what you're looking for, but it will allow you to avoid creating another attribute class...and on top of that, you can take advantage of the localization ability of the DisplayAttribute.
I have Results page that contains an signup form. I'm trying to use client-side validation on the email model, but I can't because the model type is different than the type I'm posting.
class Results
{
... // some results data to display
}
class EmailSignup
{
public virtual int Id { get; set; }
[Required(ErrorMessage = "Please enter your email.")]
[DataType(DataType.EmailAddress)]
[RegularExpression(#"^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+#((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$", ErrorMessage = "Please enter a valid email address.")]
public virtual string Email { get; set; }
}
Results.cshtml
#model MyApp.Results
[display results]
...
#using (Html.BeginForm("SubmitEmail", "AnalysisResults", FormMethod.Post))
{
<fieldset>
#Html.TextBoxFor( model => model.???? )
</fieldset>
}
The type I want the user to submit is EmailSignup, not Results.
Move the form to a partial view that takes an EmailSignup model.
This can be done quite easily. You just have to do it like this:
var contactModel = new ContactModel();
#Html.TextBoxFor(m => contactModel.Title)
#Html.ValidationMessageFor(m => contactModel.Title)
The validation works like a charm.
I have find out 2 more ways
Override the Name attribute for TextBoxFor and set it as the property name.
var formModel = new ForgotPasswordFormModel();
#Html.TextBoxFor(m => formModel.UsernameOrEmail, new { Name = "UsernameOrEmail" })
Specify the same exact model name as the post method parameter.
var formModel = new ForgotPasswordFormModel();
#using (Html.BeginForm("ChangePassword", "LoginSurface")
{
#Html.TextBoxFor(m => formModel.UsernameOrEmail)
}
...
public virtual ActionResult ChangePassword(ForgotPasswordFormModel formModel)
You could create another HtmlHelper like this
var emailSignupHtml = new HtmlHelper<EmailSignup>(Html.ViewContext, new ViewDataContainer<EmailSignup>(new EmailSignup()));
and use it like this
#emailSignupHtml.TextBoxFor(m => m.Email)
For the ViewDataContainer I use following helper class
public class ViewDataContainer<TModel> : ViewDataDictionary<TModel>, IViewDataContainer
{
public ViewDataContainer(TModel model) : base (model)
{
ViewData = new ViewDataDictionary(model);
}
public ViewDataDictionary ViewData { get; set; }
}
I guess you can also try #HTML.Action("EmaialSignup")
and your controller will have a Function calling the partial view
if you have to render multiple model bounded View in this view