I have implemented drop down control which bind with data object that
looks like
[{id:1,name:"ABC"},
{id:2,name:"XYZ"}]
and also implemented data-bind="value: Name" using knockout, now
problem is when i change drop down option it always give me id not its
name not sure why since i am exclusively setting text to view model
property.Can you please tell me what is the issue?
Thanks
My Code is
<%= Html.DropDownListFor(m => m.id, Model.MyObject, string.Empty, new { data_bind = "value: name", Id = "ddList", style = "width: 200px;font-size: 20px" })%>
module TestModule{
export class TestViewModel {
public name: KnockoutObservable<string>;
constructor() {
this.name = ko.observable();
}
}
export class TestClass {
name: KnockoutObservable<string>;
Constructor() {
this.name = ko.observable();
}
}
If your object looks like this:
[{id:1,name:"ABC"},
{id:2,name:"XYZ"}]
And you're using this for data binding:
data-bind="value: Name"
Then is it a case issue, the binding is case-sensitive so just change Name to lowercase name:
data-bind="value: name"
Related
I want to following html code using asp.net mvc 3 razor html helper:
<input type="text" .... . placeholder="Login" data-icon="user" />
I have try this one:
#Html.TextBoxFor(m => m.UserName, new { placeholder = "Login", data-icon = "user" })
or
#Html.TextBoxFor(m => m.UserName, new { placeholder = "Login", #data-icon = "user" })
Displayed Error:
Invalid anonymous type members declaration.
This might due to dash in data-icon not taken as attributes. How could I add data-icon attributes in text box field.
try this
#Html.TextBoxFor(m => m.UserName, new { placeholder = "Login", data_icon = "user" })
Yes, you can't write like that but you can write your own Extension to solve this problem. Here is the sample code:
public static MvcHtmlString MyInput(this HtmlHelper htmlHelper, string name, string value, string icon)
{
var attrs = new Dictionary<string,object>();
attrs.Add("data-icon", icon);
return htmlHelper.TextBox(name, name, value, attrs);
}
Or you can also use in razor like this:
#{
var attrs = new Dictionary<string, object>();
attrs.Add("placeholder","Login");
attrs.Add("data-icon","user");
}
#Html.TextBoxFor(m => m.UserName, attrs)
Plz don't forget to mark it's right answer if it helps you :-)
This is really the same as vNext's second alternative, but if you prefer to write it in-line:
#Html.TextBoxFor(m => m.UserName, new Dictionary<string, object> { { "placeholder", "Login" }, { "data-icon", "user" } })
I'm sure this is easy, but maybe I haven't searched well ...
I want to know how to get results from a partial view back to the model and/or controller.
If the user enters a FirstName, Gender (from drop down) and Grade (from drop down), I only find then FirstName and Gender in the model. I want to know how to get the Grade from the drop down in the partial view all the way back into the model, so I can see it in the controller.
Please look for this question in the controller code:
What do I need to do to get the GradeLevel from the partial class to be here: <<<<<
Note: this is not the exact code. There may be small, insignificant typo's.
EDIT: Apparently you can't add a long comment, so I will add here:
Thank you, Tom and Mystere Man. Tom got me thinking as to why it doesn't work. I didn't think through the model binding. With the design I proposed, the HTML gets rendered and the Grade drop down has this id: "Grade". The property on the model I want to bind to is: "GradeLevelID". If I change the helper in the partial view to be #Html.DropDownList("GradeLevelID" ... it works perfectly.
But that is not a good solution. My idea was to abstract the partial view from the main view. Hard coding the name blows that! I did work up a slightly improved solution. In the main view, I change the #Html.Partial statement to pass the model property name to the partial. Like such:
#Html.Partial("GradeDropDown", (SelectList)Model.GradeSelectList, new ViewDataDictionary { { "modelPropertyName", "GradeLevelID" } })
Then I could change the partial view to say
#model System.Web.Mvc.SelectList
#Html.DropDownList((string)ViewData["modelPropertyName"], Model)
But that also seems like a goofy way to approach things. Thanks for the help. I'll look at EditorTemplates.
Here is my model:
public class RegisterModel{
public MemberRegistration MemberRegistration{
get{
if (HttpContext.Current.Session["MemberRegistration"] == null){
return null;
}
return (MemberRegistration)HttpContext.Current.Session["MemberRegistration"];
}
set{
HttpContext.Current.Session["MemberRegistration"] = value;
}
}
public string FirstName{
get{
return MemberRegistration.FirstName;
}
set{
MemberRegistration.FirstName = value;
}
}
public SelectList GenderSelectList{
get{
List<object> tempList = new List<object>();
tempList.Add(new { Value = "", Text = "" });
tempList.Add(new { Value = "M", Text = "Male" });
tempList.Add(new { Value = "F", Text = "Female" });
return new SelectList(tempList, "value", "text", MemberRegistration.Gender);
}
}
[Required(ErrorMessage = "Gender is required")]
public string Gender{
get{
return MemberRegistration.MemberPerson.Gender;
}
set{
MemberRegistration.MemberPerson.Gender = value;
}
}
public SelectList GradeLevelSelectList{
get{
List<object> tempList = new List<object>();
tempList.Add(new { Value = "", Text = "" });
tempList.Add(new { Value = "1", Text = "1st" });
tempList.Add(new { Value = "2", Text = "2nd" });
tempList.Add(new { Value = "3", Text = "3rd" });
tempList.Add(new { Value = "4", Text = "4th" });
return new SelectList(tempList, "value", "text", MemberRegistration.GradeLevel);
}
}
[Required(ErrorMessage = "Grade is required")]
public Int32 GradeLevel{
get{
return MemberRegistration.GradeLevel;
}
set{
MemberRegistration.GradeLevel = value;
}
}
}
Here is my main view:
#model RegisterModel
#using (Html.BeginForm())
{
<p class="DataPrompt">
<span class="BasicLabel">First Name:</span>
<br />
#Html.EditorFor(x => x.FirstName)
</p>
<p class="DataPrompt">
<span class="BasicLabel">Gender:</span>
<br />
#Html.DropDownListFor(x => x.Gender, Model.GenderSelectList)
</p>
<p class="DataPrompt">
<span class="BasicLabel">Grade:</span><span class="Required">*</span>
<br />
#Html.Partial("GradeDropDown", (SelectList)Model.GradeLevelSelectList)
</p>
<p class="DataPrompt">
<input type="submit" name="button" value="Next" />
</p>
}
Here is my partial view (named "GradeDropDown"):
#model System.Web.Mvc.SelectList
#Html.DropDownList("Grade", Model)
Here is my controller:
[HttpPost]
public ActionResult PlayerInfo(RegisterModel model)
{
string FirstName = model.Registration.FirstName;
string Gender = model.Registration.Gender;
>>>>> What do I need to do to get the GradeLevel from the partial class to be here: <<<<<
Int32 GradeLevel = model.Registration.GradeLevel;
return RedirectToAction("Waivers");
}
I don't even know why you are using a partial view. All you're doing is using one helper method, you could replace the partial view with the helper method in the view and it would be less code.
Second, you should be using Html.DropDownListFor() instead of Html.DropDownList(), then it will correctly name the html controls for you.
Just do this:
<p class="DataPrompt">
<span class="BasicLabel">Grade:</span><span class="Required">*</span>
<br />
#Html.DropDownListFor(m => m.GradeLevel, (SelectList)Model.GradeLevelSelectList)
</p>
try this to get the correct naming for the elements when they get posted.
On your main view
#Html.Partial("GradeDropDown", Model) //Pass the Model to the partial view
Here is your partial view (named "GradeDropDown"):
#model RegisterModel
#Html.DropDownList("Grade", (SelectList)Model.GradeLevelSelectList)
Following is my model property
[Required(ErrorMessage = "Please Enter Short Desciption")]
[StringLength(200)]
public string ShortDescription { get; set; }
And following is my corresponding View code
#Html.TextAreaFor(model => model.Product.ShortDescription, new { cols = "50%", rows = "3" })
#Html.ValidationMessageFor(model => model.Product.ShortDescription)
And this is how it shows in the browser, the way i want.
Now, since there is a bug in Microsoft's MVC3 release, I am not able to validate and the form is submitted and produces the annoying error.
Please tell me the work around or any code that can be substituted in place of TextAreaFor. I can't use EditorFor, because with it, i can't use rows and cols parameter. I want to maintain my field look in the browser. Let me know what should be done in this case
In the controller action rendering this view make sure you have instantiated the dependent property (Product in your case) so that it is not null:
Non-working example:
public ActionResult Foo()
{
var model = new MyViewModel();
return View(model);
}
Working example:
public ActionResult Foo()
{
var model = new MyViewModel
{
Product = new ProductViewModel()
};
return View(model);
}
Another possibility (and the one I recommend) is to decorate your view model property with the [DataType] attribute indicating your intent to display it as a multiline text:
[Required(ErrorMessage = "Please Enter Short Desciption")]
[StringLength(200)]
[DataType(DataType.MultilineText)]
public string ShortDescription { get; set; }
and in the view use an EditorFor helper:
#Html.EditorFor(x => x.Product.ShortDescription)
As far as the rows and cols parameters that you expressed concerns in your question about, you could simply use CSS to set the width and height of the textarea. You could for example put this textarea in a div or something with a given classname:
<div class="shortdesc">
#Html.EditorFor(x => x.Product.ShortDescription)
#Html.ValidationMessageFor(x => x.Product.ShortDescription)
</div>
and in your CSS file define its dimensions:
.shortdesc textarea {
width: 150px;
height: 350px;
}
Here is my model:
public class NewsCategoriesModel {
public int NewsCategoriesID { get; set; }
public string NewsCategoriesName { get; set; }
}
My controller:
public ActionResult NewsEdit(int ID, dms_New dsn) {
dsn = (from a in dc.dms_News where a.NewsID == ID select a).FirstOrDefault();
var categories = (from b in dc.dms_NewsCategories select b).ToList();
var selectedValue = dsn.NewsCategoriesID;
SelectList ListCategories = new SelectList(categories, "NewsCategoriesID", "NewsCategoriesName",selectedValue);
// ViewBag.NewsCategoriesID = new SelectList(categories as IEnumerable<dms_NewsCategory>, "NewsCategoriesID", "NewsCategoriesName", dsn.NewsCategoriesID);
ViewBag.NewsCategoriesID = ListCategories;
return View(dsn);
}
And then my view:
#Html.DropDownList("NewsCategoriesID", (SelectList)ViewBag.NewsCategoriesID)
When i run, the DropDownList does not select the value I set.. It is always selecting the first option.
You should use view models and forget about ViewBag Think of it as if it didn't exist. You will see how easier things will become. So define a view model:
public class MyViewModel
{
public int SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
and then populate this view model from the controller:
public ActionResult NewsEdit(int ID, dms_New dsn)
{
var dsn = (from a in dc.dms_News where a.NewsID == ID select a).FirstOrDefault();
var categories = (from b in dc.dms_NewsCategories select b).ToList();
var model = new MyViewModel
{
SelectedCategoryId = dsn.NewsCategoriesID,
Categories = categories.Select(x => new SelectListItem
{
Value = x.NewsCategoriesID.ToString(),
Text = x.NewsCategoriesName
})
};
return View(model);
}
and finally in your view use the strongly typed DropDownListFor helper:
#model MyViewModel
#Html.DropDownListFor(
x => x.SelectedCategoryId,
Model.Categories
)
just in case someone comes with this question, this is how I do it, please forget about the repository object, I'm using the Repository Pattern, you can use your object context to retrieve the entities. And also don't pay attention to my entity names, my entity type Action has nothing to do with an MVC Action.
Controller:
ViewBag.ActionStatusId = new SelectList(repository.GetAll<ActionStatus>(), "ActionStatusId", "Name", myAction.ActionStatusId);
Pay attention that the last variable of the SelectList constructor is the selected value (object selectedValue)
Then this is my view to render it:
<div class="editor-label">
#Html.LabelFor(model => model.ActionStatusId, "ActionStatus")
</div>
<div class="editor-field">
#Html.DropDownList("ActionStatusId")
#Html.ValidationMessageFor(model => model.ActionStatusId)
</div>
I think it is pretty simple, I hope this helps! :)
I drilled down the formation of the drop down list instead of using #Html.DropDownList(). This is useful if you have to set the value of the dropdown list at runtime in razor instead of controller:
<select id="NewsCategoriesID" name="NewsCategoriesID">
#foreach (SelectListItem option in ViewBag.NewsCategoriesID)
{
<option value="#option.Value" #(option.Value == ViewBag.ValueToSet ? "selected='selected'" : "")>#option.Text</option>
}
</select>
Well its very simple in controller you have somthing like this:
-- Controller
ViewBag.Profile_Id = new SelectList(db.Profiles, "Id", "Name", model.Profile_Id);
--View (Option A)
#Html.DropDownList("Profile_Id")
--View (Option B) --> Send a null value to the list
#Html.DropDownList("Profile_Id", null, "-- Choose --", new { #class = "input-large" })
Replace below line with new updated working code:
#Html.DropDownList("NewsCategoriesID", (SelectList)ViewBag.NewsCategoriesID)
Now Implement new updated working code:
#Html.DropDownListFor(model => model.NewsCategoriesID, ViewBag.NewsCategoriesID as List<SelectListItem>, new {name = "NewsCategoriesID", id = "NewsCategoriesID" })
I want to put the correct answer in here, just in case others are having this problem like I was. If you hate the ViewBag, fine don't use it, but the real problem with the code in the question is that the same name is being used for both the model property and the selectlist as was pointed out by #RickAndMSFT
Simply changing the name of the DropDownList control should resolve the issue, like so:
#Html.DropDownList("NewsCategoriesSelection", (SelectList)ViewBag.NewsCategoriesID)
It doesn't really have anything to do with using the ViewBag or not using the ViewBag as you can have a name collision with the control regardless.
I prefer the lambda form of the DropDownList helper - see MVC 3 Layout Page, Razor Template, and DropdownList
If you want to use the SelectList, then I think this bug report might assist - http://aspnet.codeplex.com/workitem/4932
code bellow, get from, goes
Controller:
int DefaultId = 1;
ViewBag.Person = db.XXXX
.ToList()
.Select(x => new SelectListItem {
Value = x.Id.ToString(),
Text = x.Name,
Selected = (x.Id == DefaultId)
});
View:
#Html.DropDownList("Person")
Note:
ViewBag.Person and #Html.DropDownList("Person") name should be as in view model
To have the IT department selected, when the departments are loaded from tblDepartment table, use the following overloaded constructor of SelectList class. Notice that we are passing a value of 1 for selectedValue parameter.
ViewBag.Departments = new SelectList(db.Departments, "Id", "Name", "1");
For anyone that dont want to or dont make sense to use dropdownlistfor, here is how I did it in jQuery with .NET MVC set up.
Front end Javascript -> getting data from model:
var settings = #Html.Raw(Json.Encode(Model.GlobalSetting.NotificationFrequencySettings));
SelectNotificationSettings(settings);
function SelectNotificationSettings(settings) {
$.each(settings, function (i, value) {
$("#" + value.NotificationItemTypeId + " option[value=" + value.NotificationFrequencyTypeId + "]").prop("selected", true);
});
}
In razor html, you going to have few dropdownlist
#Html.DropDownList(NotificationItemTypeEnum.GenerateSubscriptionNotification.ToString,
notificationFrequencyOptions, optionLabel:=DbRes.T("Default", "CommonLabels"),
htmlAttributes:=New With {.class = "form-control notification-item-type", .id = Convert.ToInt32(NotificationItemTypeEnum.GenerateSubscriptionNotification)})
And when page load, you js function is going to set the selected option based on value that's stored in #model.
Cheers.
I have created a default MVC 3 project (using razor), in order to demonstrate an issue.
On the login page, there is a line:
#Html.TextBoxFor(m => m.UserName)
if I change this to:
#Html.TextBoxFor(m => m.UserName, new { title = "ABC" })
Then the it is rendered as (with a title attribute):
<input data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" title="ABC" type="text" value="" />
However, if I make it an EditorFor:
#Html.EditorFor(m => m.UserName, new { title = "ABC" })
Then it gets rendered (without a title attribute) as:
<input class="text-box single-line" data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" type="text" value="" />
So in summary, the title attribute is lost when I use EditorFor.
I know that the second parameter for TextBoxFor is called htmlAttributes, and for EditorFor it is additionalViewData, however I've seen examples where EditorFor can render attributes supplied with this parameter.
Can anyone please explain what I am doing wrong, and how I can have a title attribute when using EditorFor?
I think I found a little nicer solution to it. EditorFor takes in additionalViewData as a parameter. If you give it a parameter named "htmlAttributes" with the attributes, then we can do interesting things with it:
#Html.EditorFor(model => model.EmailAddress,
new { htmlAttributes = new { #class = "span4",
maxlength = 128,
required = true,
placeholder = "Email Address",
title = "A valid email address is required (i.e. user#domain.com)" } })
In the template (in this case, EmailAddress.cshtml) you can then provide a few default attributes:
#Html.TextBox("",
ViewData.TemplateInfo.FormattedModelValue,
Html.MergeHtmlAttributes(new { type = "email" }))
The magic comes together through this helper method:
public static IDictionary<string, object> MergeHtmlAttributes<TModel>(this HtmlHelper<TModel> htmlHelper, object htmlAttributes)
{
var attributes = htmlHelper.ViewData.ContainsKey("htmlAttributes")
? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlHelper.ViewData["htmlAttributes"])
: new RouteValueDictionary();
if (htmlAttributes != null)
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(htmlAttributes))
{
var key = property.Name.Replace('_', '-');
if (!attributes.ContainsKey(key))
{
attributes.Add(key, property.GetValue(htmlAttributes));
}
}
}
return attributes;
}
Of course you could modify it to render the attributes as well if you are doing raw HTML:
public static MvcHtmlString RenderHtmlAttributes<TModel>(this HtmlHelper<TModel> htmlHelper, object htmlAttributes)
{
var attributes = htmlHelper.ViewData.ContainsKey("htmlAttributes")
? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlHelper.ViewData["htmlAttributes"])
: new RouteValueDictionary();
if (htmlAttributes != null)
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(htmlAttributes))
{
var key = property.Name.Replace('_', '-');
if (!attributes.ContainsKey(key))
{
attributes.Add(key, property.GetValue(htmlAttributes));
}
}
}
return MvcHtmlString.Create(String.Join(" ",
attributes.Keys.Select(key =>
String.Format("{0}=\"{1}\"", key, htmlHelper.Encode(attributes[key])))));
}
In MVC3 you can add a title (and other htmlAttributes) using this kind of workaround if you create a custom EditorFor template. This case is prepared for the value to be optional, editorFor calls are not required to include the object additionalViewData
#Html.EditorFor(m => m.UserName, "CustomTemplate", new { title = "ABC" })
EditorTemplates/CustomTemplate.cshtml
#{
string s = "";
if (ViewData["title"] != null) {
// The ViewData["name"] is the name of the property in the addtionalViewData...
s = ViewData["title"].ToString();
}
}
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { title = s })
I did something very similar to include an optional class in an EditorTemplate. You can add as many items to the addtionalViewData as you like but you need to handle each on in the EditorFor template.
You may take a look at the following blog post which illustrates how to implement a custom metadata provider and use data annotations on your view model in order to define html properties such as class, maxlength, title, ... This could then be used in conjunction with the templated helpers.