Bind default value to TextBoxFor in MVC not working - asp.net-mvc

When I bind default value to textboxfor but it's not working as expected
#Html.TextBoxFor(model => model.LinkAddress, htmlAttributes: new { #Value = ViewBag.link })
ViewBag.link is value that pass from controller
I wanna set ViewBag.link value as default value of textboxfor but it's not working as expected

If you use Model you don't need a ViewBag because the value from Model property will bind to the TextBoxFor.
But if you use just TextBox you must do it in 2 ways
First:
#Html.TextBox("LinkAddress", (String)ViewBag.link)
Second:
<input type="text" value="#ViewBag.link" />

You can do:
#Html.TextBoxFor(model => model.LinkAddress, new { #Value = #ViewBag.link })
Or
#Html.TextBox("LinkAddress", null, new { #Value = #ViewBag.link })

Your value attribute assignment with ViewBag is pointless, because TextBoxFor is already bound to your viewmodel and you can simply assign it from a controller action which returns view using GET method ([HttpGet]) with corresponding viewmodel:
[HttpGet]
public ActionResult ActionName()
{
var model = new ViewModel();
model.LinkAddress = "linkaddresshere";
return View(model);
}
And leave TextBoxFor as-is:
#Html.TextBoxFor(model => model.LinkAddress)
If you want to assign textbox helper's value from client-side, use jQuery.val() or value property from vanilla JS after the DOM objects are fully loaded:
// jQuery
$('#LinkAddress').val("linkaddresshere");
// vanilla JS
document.getElementById('LinkAddress').value = "linkaddresshere";

Related

If I have a static value in an input field how can i pass it to the controller?

I want to pass this static value to my controller using Request.Form method using name attribute
<input type="text" value="Sunday" disabled name="Day"/>
Use this code line:
#Html.HiddenFor(model => model.Day, new { #Value = "Sunday"})

Razor EditorFor with Onclick Event

I have nullable Boolean value that is being presented as a checkbox using the following code:
#Html.EditorFor(m => m.IsInitialStatus, new { htmlAttributes = new { #onclick = "InitialOrStarting()" } })
however the #onclick attribute is not being added to the HTML when the page is loaded. Am I missing something here? I had taken the example from an answer on this page.
I have also looked at changing this to a CheckBoxFor but keep getting an issue with the nullable Bool datatypes.
Any help on this would be appreciated! I just want a nullable bool checkbox with an onClick event firing to a Javascript function... I am not the most advanced user but this seems to be more difficult for me to do than maybe it should!?
EDIT
There appears to be an EditorTemplate for Boolean which contains:
#model bool?
#Html.CheckBox("", Model.GetValueOrDefault())
You are using the overload of EditorFor() where the 2nd parameter is additionalViewData. If you did not have a specific EditorTemplate for bool?, the method would generate the default template, which is a <select> with 3 values for null, true and false, and include the attributes.
But because you have an EditorTemplate, you need to add the attributes yourself by reading the value from the ViewDataDictionary (typically, an EditorTemplate includes multiple html elements, so the method cannot know which element you want to apply the attributes to).
Your template would need to be
#model bool?
#{ var attributes = ViewData["htmlAttributes"]; }
#Html.CheckBox("", Model.GetValueOrDefault(), attributes)
Having said that, your should not be doing this. A bool? has 3 states (null, true or false) but a checkbox has only 2 states - on or off (translates to true or false) so your EditorTemplate does not represent the possible values of your property.
If you only want to allow true or false, then your property should not be nullable. Alternatively, use the default template that does allow a null selection (or if you want an alternative UI, create a template that renders 3 radio buttons for example)
In addition, I recommend you stop polluting you markup with behavior and use Unobtrusive JavaScript - i.e. your script will be
$(yourCheckBox).click(function() {
... // do something
});
Onclick Event does not working for #HtmlEditorFor. But you can use class attribute.
<script>
$(".single-checkbox").on("change", function () {
if ($(".single-checkbox:checked").length > 2) {
this.checked = false;
alert ("Only 2 choice")
}
});
</script>
#Html.EditorFor(model => model.YourProperty, new { htmlAttributes = new { #class = "single-checkbox" } })
#Html.EditorFor(model => model.YourProperty, new { htmlAttributes = new { #class = "single-checkbox" } })
#Html.EditorFor(model => model.YourProperty, new { htmlAttributes = new { #class = "single-checkbox" } })
#Html.EditorFor(model => model.YourProperty, new { htmlAttributes = new { #class = "single-checkbox" } })

Custom EditorFor Template and htmlAttributes

I'm trying to use EditorFor custom templates.
I want to create a Int32 and decimal templates to render the inputs with some validations.
This is what I'm trying
#model int?
#Html.TextBoxFor(model => model, null, new { #type="text", #oninput = "this.value=this.value.replace(/[^0-9]/g,'')" } )
And I call it like
#Html.EditorFor(x => x.ExampleIntField)
It renders an <input type="text", oninput="this.value=this.value.replace(/[^0-9]/g,'')"
To here everything works, but when I try to pass extra htmlAttributes like readonly I don't understand how I must receive it in EditorFor template.
Example
#Html.EditorFor(x => x.ExampleIntField, new { htmlAttributes = new { #readonly = "readonly" } } )
I tried this I got the exact same <input type="text", oninput="this.value=this.value.replace(/[^0-9]/g,'')" rendered without readonly attribute
You are using the overload of EditorFor() that passes the object as additionalViewData. You can read that within the template from the ViewDataDictionary
#model int?
#{ var attributes = ViewData["htmlAttributes"]; } // returns { #readonly = "readonly" }
which you could then merge with your existing attributes and use in the TextBoxFor() method.
#{
var htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(attributes);
htmlAttributes.Add("oninput", "this.value=this.value.replace(/[^0-9]/g,'')";
}
#Html.TextBoxFor(model => model, htmlAttributes)
Note that TextBoxFor() generates type="text" so there is no need to add it again. In addition, you do not need the leading # unless its a reserved keyword (for example #class = "...")

MVC3 Razor SelectedValue in DropdownListFor

I've the following code for a DropDownListFor and is working ok
#Html.DropDownListFor(Function(model) model.Habilitacoes, New SelectList(ViewBag.Habilitacoes, "KeyHL", "DescricaoHL"), New With {.class = "FillHSpace"})
The ViewBag.Habilitacoes is a List(Of T)
But know I want to add the SelectedValue to the DropDownListFor, so I've used the following code but doesn't work.
#Html.DropDownListFor(Function(model) model.Habilitacoes, New SelectList(ViewBag.Habilitacoes, "KeyHL", "DescricaoHL", model.Habilitacoes), New With {.class = "FillHSpace"})
How can I declare the SelectedValue?
You should not use the same property as first and second argument of the DropDownListFor helper. The first argument is a scalar property and the second a collection:
#Html.DropDownListFor(Function(model) model.SelectedHabilitacoes, New SelectList(ViewBag.Habilitacoes, "KeyHL", "DescricaoHL"), New With {.class = "FillHSpace"})
and then in your controller:
model.SelectedHabilitacoes = "123"
DropdownListFor has overloads to accomplish this
DropDownListFor([SelectedValue], [SelectList], optional HTML Attributes)
Normally you would go
DropDownListFor(model => model.ID, (SelectList)ViewsBag.MySelectList, optional HTML Attributes)
The selected value will be automatically bound to the dropdown list, and will automatically be posted the the model.ID value
if this doesn't help id ask you to post your model.

DropDownListFor in EditorTemplate not selecting value

I have an editor template for a custom object. Inside that editor template I use a couple of DropDownListFor helpers. In each of them I specify a unique model property (with the pre-selected value) and the select list containing all the select options.
Example:
<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>
I know that the option values are being populated (from viewing source) and that my Model is passed in with the correct ID value (DocumentCategoryType).
When the view is rendered, there is no selected item in my dropdown and therefore it defaults to the first (non-selected) value.
Does anyone have any ideas?
Thanks.
We also solved the solution by populating a new SelectList that has the appropriate SelectListItem selected, but created this extension method to keep the call to DropDownListFor a little cleaner:
public static SelectList MakeSelection(this SelectList list, object selection)
{
return new SelectList(list.Items, list.DataValueField, list.DataTextField, selection);
}
Then your DropDownListFor call becomes:
<%= Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList.MakeSelection(Model.DocumentCategoryType)) %>
Looking through the ASP.NET MVC 2 source code reveals some solutions to this problem. Essentially, any SelectListItem in the SelectList passed in the helper extension method that has the Selected property set to true does not have any bearing over the <option> element rendered with the selected attribute applied for the item.
The selected attribute on <option> elements is determined by
1) checking that the helper extension method was passed a SelectList. If this is null, the framework will look in the ViewData for a value corresponding to the key that is the view model property for which you wish to render the drop down list for. If the value is a SelectList, this will be used to render the <select> including taking any selected values, so long as the model state for the model property is null.
2) If a SelectList has been passed in the helper extension method and the model state for the model property is null, the framework will look in the ViewData for a default value, using the model property name as the key. The value in view data is converted to a string and any items in the SelectList passed to the helper extension method that have a value (if no value is set, then the Text will be checked) that matches the default value will have the Selected property set to true which in turn will render an <option> with the attribute selected="selected".
Putting this together, there are two plausible options that I can see to have an option selected and use the strongly typed DropDownListFor:
Using the following view model
public class CategoriesViewModel
{
public string SelectedCategory { get; private set ; }
public ICollection<string> Categories { get; private set; }
public CategoriesViewModel(string selectedCategory, ICollection<string> categories)
{
SelectedCategory = selectedCategory;
Categories = categories;
}
}
Option 1
Set a value in the ViewData in the controller rendering your view keyed against the property name of the collection used to render the dropdown
the controller action
public class CategoriesController
{
[HttpGet]
public ViewResult Select()
{
/* some code that gets data from a datasource to populate the view model */
ICollection<string> categories = repository.getCategoriesForUser();
string selectedCategory = repository.getUsersSelectedCategory();
CategoriesViewModel model = new CategoriesViewModel(selectedCategory, categories);
this.ViewData["Categories"] = selectedCategory;
return View(model);
}
[HttpPost]
public ActionResult Select(CategoriesViewModel model)
{
/* some code that does something */
}
}
and in the strongly typed view
<%: Html.DropDownListFor(m => m.Categories, Model.Categories.Select(c => new SelectListItem { Text = c, Value = c }), new { #class = "my-css-class" }) %>
Option 2
Render the dropdown using the name of the property of the selected item(s)
the controller action
public class CategoriesController
{
[HttpGet]
public ViewResult Select()
{
/* some code that gets data from a datasource to populate the view model */
ICollection<string> categories = repository.getCategoriesForUser();
string selectedCategory = repository.getUsersSelectedCategory();
CategoriesViewModel model = new CategoriesViewModel(selectedCategory, categories);
return View(model);
}
[HttpPost]
public ActionResult Select(CategoriesViewModel model)
{
/* some code that does something */
}
}
and in the strongly typed view
<%: Html.DropDownListFor(m => m.SelectedCategory, Model.Categories.Select(c => new SelectListItem { Text = c, Value = c }), new { #class = "my-css-class" }) %>
It is confirmed as a bug # aspnet.codeplex.com
and only behaves like this for strongly typed views.
Workaround: populate your SelectList in the view code
like
<%= Html.DropDown("DocumentCategoryType", new SelectList(Model.Categories,"id","Name",Model.SelectedCategory")) =>
Yuck. I ended up solving it like this. I hope this gets fixed for RTM.
<%if(Model!=null){ %>
<%= Html.DropDownListFor(m => m.DocumentCategoryType, new SelectList(Model.DocumentCategoryTypeList,"Value","Text", Model.DocumentCategoryType))%>
<%}else{%>
<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>
<%}%>
Make sure you have a value assigned to m.DocumentCategoryType when you send it to the view.
Generally this value will get reset when you do a post back so you just need to specify the value
when returning to your view.
When creating a drop down list you need to pass it two values. 1. This is where you will store the selected value 2. Is the actual List
Example
<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>
I made the mistake of setting the select list item Selected value to True. This won't do anything. Instead just assign a value to m.DocumentCategoryType in your controller and this will actually do the selection for you.
Here's another good solution if the source for your drop down list is an IEnumerable instead of a SelectList:
public static SelectList MakeSelection(this IEnumerable<SelectListItem> list, object selection, string dataValueField = "Value", string dataTextField = "Text")
{
return new SelectList(list, dataValueField, dataTextField, selection);
}
Model.DocumentCategoryTypeList
This is probably your problem. On the SelectListItems, do you set the value to the .ToString() output?
var list = new List<SelectListItem>()
{
new SelectListItem()
{
Value = Category.Book.ToString(),
Text = "Book"
},
new SelectListItem()
{
Value = Category.BitsAndPieces.ToString(),
Text = "Bits And Pieces" },
new SelectListItem()
{
Value = Category.Envelope.ToString(),
Text = "Envelopes" }
};
Works for me after doing that. It just needs to be able to match the value from the object
I managed to solve the same problem by saying the folling:
new SelectList(sections.Select(s => new { Text = s.SectionName, Value = s.SectionID.ToString() }), "Value", "Text")
This trick is converting to the value to a string. I know this has been mentioned in previous answers but i find my solution a little cleaner :). Hope this helps.
Copied na pasted from my project:
<%= Html.DropDownListFor(m => m.Profession.Profession_id, new SelectList(Model.Professions, "Profession_id", "Profession_title"),"-- Profession --")%>
Model that is passed:
...
public Profession Profession { get; set; }
public IList<Profession> Professions { get; set; }
...
Html generated:
<select id="Profession_Profession_id" name="Profession.Profession_id">
<option value="">-- Profesion --</option>
<option value="4">Informatico</option>
<option selected="selected" value="5">Administracion</option>
</select>
Works for me. I have this on the form and the only disadvantage is that if model is not valid and I return the model back to the view I have to reload the list of Professions.
obj.Professions = ProfileService.GetProfessions();
return View(obj);
I also had this problem with a field ProgramName. Turns out we used ViewBag.ProgramName in the BaseController and Layout.cshtml, and this was for a different purpose. Since the value in ViewBag.ProgramName was not found in the dropdownlist, no value was selected even though the SelectListItem.Selected was true for one item in the list. We just changed the ViewBag to use a different key and the problem was resolved.
Here is a drop-in DropDownListFor replacement that varies only slightly from the original MVC source.
Example:
<%=Html.FixedDropDownListFor(m => m.DocumentCategoryType,
Model.DocumentCategoryTypeList) %>
I was worried about the performance of making so many copies of my selectList, so instead, I added the selectedvalue as a custom attribute, then used jquery to actually perform the item select:
#Html.DropDownListFor(item => item.AttendeeID, attendeeChoices, String.Empty, new { setselectedvalue = Model.AttendeeID })
........
jQuery("select[setselectedvalue]").each(function () { e = jQuery(this); e.val(e.attr("setselectedvalue")); });

Resources