Need Validation on html dropdownlist with data from Viewbag - html

I know I'm not supposed to use the Viewbag and that I should build a menu using Html.DropDowlListFor() so that i can add attribute bound to the members of the model, BUT, that would involve a pretty extensive code rewrite....
I have a custom controller with a menu:
*.ASCX
<%: Html.DropDownList("CityIDs", new SelectList(ViewBag.cities, "Id", "Name"), "--Select--", new { style = "width:200px" })%>
<%= Html.ValidationMessage("CityIDs") %>
The List populates just fine and I can default to the top item to "--Select--"
The prbolem is that I want the validation error to occur on anything that is not from the viewbag.... how can I achieve this?

Validation for dropdown lists only ensures that something was posted. If you want to ensure that the value that was posted is actually one of a set of "allowed" values, then you'll have to manually do that in your post action:
var cityIds = db.Cities.Select(m => m.Id);
if (!cityIds.Contains(model.CityIDs))
{
ModelState.AddModelError("CityIDs", "You must select one of the available choices.");
}
if (ModelState.IsValid)
{
...
Two things:
Notice that I'm pulling the city ids straight from the database (the actual code you'd need here, of course, depends on your specific implementation). The important thing, though, is that ViewBag only survives a single request, so you can't look for them in ViewBag after posting.
Despite the pluralized name of CityIDs, using the DropDownList helper ensures that only a single selected value will exist. If this is actually supposed to be a multiselect, then you need to use ListBox instead, and update this conditional here to account for check for multiple values.

Populates the top item with Text = "--Select--" and Value = ""
which will post a blank value for CityIDs and cause an error in ModelState.

Related

Need to get the 2sxc Field Type from an Entity

After getting everything working on this previous question Is there a way to Clone one or many Entities (records) in Code, I wanted to clean it up and make it more useful/reusable. So far, I am deciding how to copy/add the field using the content-type field names, so attribute.Key inside the foreach on Attributes. What I need instead is to know the Entity field's Type; meaning String, Number, Hyperlink, Entity, etc.
So I want something like if(AsEntity(original).FieldType == "HyperLink") { do this stuff }. I have explored the API docs but have not spotted how to get to the info. Is it possible?
I did figure out that the attribute.Value has a Type that I could use to answer most of them, but Hyperlink and String are both showing, System.String.
Here are, in order, String, Hyperlink, Entity, and Number:
atts: ToSic.Eav.Data.Attribute`1[System.String]
atts: ToSic.Eav.Data.Attribute`1[System.String]
atts: ToSic.Eav.Data.Attribute`1[ToSic.Eav.Data.EntityRelationship]
atts: ToSic.Eav.Data.Attribute`1[System.Nullable`1[System.Decimal]]
So is there a way from the Entity or its Attributes or some other pathway of object/methods/properties to just get the answer as the field Type name? Or is there a wrapper of some kind I can get to that will let me handle (convert to/from) Hyperlinks? I am open to other ideas. Since the fields.Add() is different by "FieldType" this would be really helpful.
It's kind of simple, but needs a bit more code because of the dynamic nature of Razor. Here's a sample code that should get you want you need:
#using System.Collections.Generic;
#using System.Linq;
#using ToSic.Eav.Data;
var type = AsEntity(Content).Type;
var attributes = type.Attributes as IEnumerable<IContentTypeAttribute>;
var typeOfAwards attributes.First(t => t.Name == "Awards").Type; // this will return "Entity"
I created a quick sample for you here: https://2sxc.org/dnn-tutorials/en/razor/data910/page

How does MVC decide which value to bind when there are multiple inputs with the same name?

I have an edit page where several fields are conditionally disabled, based on the user's role. When the fields are disabled, their values are not posted to the server (as expected), which causes the ModelState to be invalid, as the values are required.
To get around this, I want to add Html.HiddenFor() for the fields; so that a value will still get posted (and so that it will retain those values if the View is returned). However, in the case that those fields are not disabled, I will then have both a TextBoxFor and a HiddenFor going to the same model property.
I have run a couple tests, and it appears that when this happens, the value of the first element on the form will be binded to the model, while the next one just gets ignored. If this is the case, then I should be able to just put the HiddenFor after the TextBoxFor, in which case the value of the hidden input will only be posted when the regular input is disabled.
#Html.TextBoxFor(m => m.FirstName)
#Html.HiddenFor(m => m.FirstName) #*Only gets binded to the model if the above text box is disabled*#
(There is some JavaScript that conditionally disabled the visible TextBox).
So two questions: 1) Is it documented that MVC binding will always work this way; can I safely have both of these fields?
And, 2) Is there a better approach to accomplishing this? I know that I can but the HiddenFor inside an #If statement so that it will only get created if the TextBox is disabled; but that is a lot of extra logic in the View that I'd like to avoid.
The DefaultModelBinder reads the values from the request in order and binds the first matching name/value pair and ignores subsequent matches (unless the property is IEnumerable). This is how the CheckBoxFor() method ensures a true or false value is always submitted to the controller (the method generates a checkbox with value="True" and a hidden input with value="False"), so you can safely add the hidden input after the textbox.
One option you might consider rather than a disabled textbox, is to make it readonly, which means it will always submit a value, therefore you only need one input (and you can always style it to look disabled if that is what you want).

Accessing ListBox selected item via UiApp.getActiveApplication().getElementByID()

Currently I am using UiService to create a form and I uses ListBox, from what I understand to pass a value via handler will be something like e.parameter.[Name of ListBox] to access the selected item.
Does anyone know is it possible to use like app.getElementById([Name of ListBox]) to access the selected item. The reason I am using this method is because my list of ListBox-es are dynamic.
I spent some time looking for this answer as well, but finally I tried one idea and it worked.
You can use e.parameter as an array so you can these two will give the same:
e.parameter.LIST_BOX_NAME
and
e.parameter['LIST_BOX_NAME']
So in the second sample any dynamic list box ID can be used. I use same handler for all added dropdown list and have this code to check what dropdown was changed and what value it has now:
if (e.parameter[e.parameter.source] == 'a'){
To change the content of the listBox you can use app.getElementById('ID of the listBox'), from there you can clear() and addItems again but you cannot read the listItems.
When I need to do this I usually store the list of items somewhere else, in a place that I can read anytime, for example the list of items can be stored as a string in the listBox tag itself so I have all items at hand to repopulate the listBox after I have clear it.

Html.TextBoxFor ID in two places on the same form

Friends,
I'm working on changes to an existing code base someone else created. They used Razor Html.TextBoxFor in many places. I need to add another textbox using the same model property in a second place on the same form:
#Html.TextBoxFor(model => model.EnrollmentToBatchDataContract.NameKey)
The problem I have is that Razor is rendering the same ID for both instances of this textbox. I need to enable and disable the textbox's independent of each other.
Any insight would be greatly appreciated.
#Html.TextBoxFor(model => model.EnrollmentToBatchDataContract.NameKey, new { #id = "new id" })
The second parameter changes the Html object values. Any property from the Html tag could be put between the braces and changed.
This does not work on EditorForModel if you need to do that aswell, last time I tried.

Html.DropDownList select value not being set by Model

I have a drop down list like so:
<%= Html.DropDownList("SoldTo", Model.SellDealerList, "Select a Dealer")%>
I'm populating the list in my Controller with the following code:
SellDealerList = new SelectList(repository.GetDealerList(), "id", "name", vehicle.SoldTo);
When I debug through the code the selected value on the SellDealerList has a value that is being set but the HTML source shows no selected value in the list.
I'm baffled as to what I'm doing wrong, but being new to MVC I'm sure it is probably something very simple. The biggest difference from all the other questions and answers I've seen is that I'm not using the ViewData.
Thanks!
Check my answer to this question, maybe it helps.
Perhaps you have a property "SoldTo" in your model, ViewData or ModelState. The DropDown tries to override the selected value if some of these objects has a property or key with the same name as your field. Is kind of crazy if you don't know how it works internally because you see the selected property set to true on the right item of the SelectList and yet no option of the select is selected.