Drop-down list automatically becomes multiple - c#

Can anyone explain why my drop-down list automatically allows multiple selections?
I'm quite new to Net Core and this is the first time I add a drop-down and I'm obvisouly doing something wrong. Everything works technically, the drop-down list is populated and the Model gets the correct data when posting but for some reason the multiple attribute is automatically set for the drop-down list.
View
<select asp-for="#Model.fooForm.CountryRows"
asp-items="#(new SelectList(Model.fooForm.CountryRows,"CountryCode","CountryName"))"
class="form-control">
<option>Please select Country of use</option>
</select>
ViewModel
namespace foo.Models.ViewModels
{
[Bind(Prefix = nameof(fooIndexRootVM.fooForm))]
public class fooVM
{
public fooVM()
{
}
public fooVM(CountryVM[] countryRows)
{
CountryRows = countryRows;
}
[Display(Name = "Country of use")]
public virtual CountryVM[] CountryRows { get; set; }
}
}
Controller/Service
public async Task<fooIndexRootVM> GetCountries()
{
var countryRows = await fooContext.Country
.OrderBy(c => c.CountryCode)
.Select(c => new CountryVM
{
CountryCode = c.CountryCode
,CountryName = c.CountryName
,CountryBlocked = c.CountryBlocked
})
.ToArrayAsync();
return new fooIndexRootVM
{
fooForm = new fooVM(countryRows)
};
}

From MSDN: The select tag helper
The Select Tag Helper will automatically generate the multiple =
"multiple" attribute if the property specified in the asp-for
attribute is an IEnumerable.
So in your case the model it's looking at represents a list for asp-for="#Model.fooForm.CountryRows".
In order to fix this you can add new property for selected country to model
public virtual CountryVM SelectedCountry { get; set; }
Then asp-for should be like this:
<select asp-for="#Model.fooForm.SelectedCountry"
asp-items="#(new SelectList(Model.fooForm.CountryRows,"CountryCode","CountryName"))"
class="form-control">
<option>Please select Country of use</option>
</select>

Related

ASP drop down select showing up weird

I've been trying to create a drop down list with asp tag helpers and for some reason they always look strange. I'll include my code for Controller, View, and view model. Also the picture of how it looks.
Controller:
public async Task<IActionResult> Create()
{
var dalias = await _context.DeptAliases
.Select(m => new SelectListItem { Text = m.Alias, Value = m.DeptAliasPkey.ToString() }).Distinct()
.ToListAsync();
var vm = new CopyCenterCreateViewModel()
{
DAlias = dalias,
};
return View(vm);
}
View:
#model PrintShop.ViewModels.CopyCenterCreateViewModel
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="DAlias" class="control-label"></label>
<select asp-for="DAlias" asp-items="Model.DAlias" class="form-control"></select>
<span asp-validation-for="DAlias" class="text-danger"></span>
</form>
ViewModel:
public class CopyCenterCreateViewModel
{
public List<SelectListItem> DAlias { get; set; }
}
Result:
It looks like the select control is rendering in multi-selection mode. If the tag helper asp-for is binding to an IEnumerable then the select element is rendered in multiple mode.
From tag-helpers multiple select section of the docs:
The Select Tag Helper will automatically generate the multiple = "multiple" attribute if the property specified in the asp-for
attribute is an IEnumerable.
You only have a single property in the ViewModel which is a List, and you're binding the items to the same property as the selected value.
You could rename the list of items to something else and add a property to bind to the value of the selected item:
public class CopyCenterCreateViewModel
{
public string DAlias { get; set; }
public List<SelectListItem> Items { get; set; }
}
In the controller you'd populate the Items property of the CopyCenterCreateViewModel.
In the view bind asp-items to the view model Items property:
<select asp-for="DAlias" asp-items="Model.Items" class="form-control"></select>

Select List from List in ViewModel presenting options as "[object Window]"

I would like to create a select list on my view that allows the client to chose the customer from that select list.
My view model looks like this:
public int SalesOrderId { get; set; }
public int CustomerId { get; set; }
public string PONumber { get; set; }
public DateTime OrderDate { get; set; }
public List<Customer> Customers { get; set; }
public List<SalesOrderItemViewModel> SalesOrderItems { get; set; }
My Customer model looks like this:
public int CustomerId { get; set; }
public string CustomerName { get; set; }
My knockout js looks like this:
SalesOrderViewModel = function (data) {
var self = this;
// This automatically creates my view model properties for ko from my view model passed from the server
ko.mapping.fromJS(data, salesOrderItemMapping, self);
// .... Other save functions etc.
};
[Edit]
Sales Item mappings as requested
var salesOrderItemMapping = {
'SalesOrderItems': {
// key for each child
key: function (salesOrderItem) {
return ko.utils.unwrapObservable(salesOrderItem.SalesOrderItemId);
},
// Tell knockout what to fo for each sales order item it needs to create
create: function (options) {
// create a new sales order item view model using the model passed to the mapping definition
return new SalesOrderItemViewModel(options.data); // Notice data is a property of the options object
// Moreover, data is the data for this child and options is the object containing the parent
}
}
};
[Edit]
#Html.Raw(data) as requested:
{"SalesOrderId":1,"CustomerId":1,"PONumber":"123456","OrderDate":"2015-01-25T00:00:00","MessageToClient":"The original value of Customer Name is Ashfield Clutch Services.","ObjectState":0,"Customer":{"CustomerId":1,"CustomerName":"Ashfield Clutch Services"},"SalesOrderItems":[{"SalesOrderItemId":1,"ProductCode":"ABC","Quantity":10,"UnitPrice":1.23,"SalesOrderId":1,"ObjectState":0},{"SalesOrderItemId":2,"ProductCode":"XYZ","Quantity":7,"UnitPrice":14.57,"SalesOrderId":1,"ObjectState":0},{"SalesOrderItemId":3,"ProductCode":"SAMPLE","Quantity":3,"UnitPrice":15.00,"SalesOrderId":1,"ObjectState":0}],"SalesOrderItemsToDelete":[],"Customers":[{"CustomerId":1,"CustomerName":"Ashfield Clutch Services"},{"CustomerId":3,"CustomerName":"Davcom-IT Ltd"},{"CustomerId":2,"CustomerName":"Fluid Air Conditioning"}]}
And at the top of my view I have this js:
<script src="~/Scripts/salesOrderViewModel.js"></script>
<script type="text/javascript">
var salesOrderViewModel = new SalesOrderViewModel(#Html.Raw(data));
ko.applyBindings(salesOrderViewModel);
</script>
If I bind my select list to the Customers collection in my view model the select list doesn't appear to be bound correctly:
<select class="form-control" name="Customers" id="Customers" data-bind="options: Customers, optionsText: CustomerName, optionsValue: CustomerId, value: CustomerId"></select>
You can see that instead of showing the customers it shows "[object Window]" for all of the customers. I think it could be half way there as it shows the correct number of "[object Window]" vs the number of clients in the db.
I understand that the Customers must be a knockout observable array but I'm not sure how to apply this to my js view model.
Any help would be appreciated.
Arent you missing "" in options text and options value ?
<select class="form-control" name="Customers" id="Customers" data-bind="options: Customers, optionsText: "CustomerName", optionsValue: "CustomerId", value: CustomerId"></select>
You need to make one change while binding your customers to select drop down
Your Exisitng Code
<select class="form-control" name="Customers" id="Customers" data-bind="options: Customers, optionsText: CustomerName, optionsValue: CustomerId, value: CustomerId"></select>
Make following change
<select class="form-control" name="Customers" id="Customers" data-bind="options: salesOrderViewModel.Customers, optionsText: Customers.CustomerName, optionsValue: Customers.CustomerId, value: CustomerId"></select>
options: salesOrderViewModel.Customers
And it should work for you.

MVC5 Html.DropDownListFor Does not select correct value

I'm doing something horribly simple and it isn't working.
#Html.DropDownListFor(m => m.ContentDefinitionID, Model.ContentBoxesSelectList, new {#class = "form-control"})
The ContentDefinitionID is a UInt64 (although I've tried an int)
I use this same select list for 4 different controls on the page.
If my Model.ContentDefinition is set to 4, (which would be test4 in the drop down) then it SHOULD pull that selected value from the Model, NOT from the selectList right? Someone else said that it ignores the value on the SelectList when you use the m=>m.X syntax - which makes sense.
But it always selects the first one. I tried adding another parameter for what it should select, but it wants the text, not the value and I hate to have to lookup the text. (And I'm not sure this will post back correctly if I do that anyway)
I'm about to go create some JQuery code to set the default values for everything -but that is crazy. This is the obvious behavior of the DropDownListFor() method, kind of a 'duh' thing - why doesn't it work? Do I need to create a custom SelectList for every control that exists on the page?
--- Update, the model etc:
class PageModel
{
Int64 ContentDefinitionID {get;set;}
SelectList ContentBoxesSelectList {get;set;}
}
Controller init for model:
model.ContentDefinitionID = 4; // In real situation, this is an
array of N model.ContentBoxesSelectList = new SelectList( from
ContentDefinitionDocument doc in allContentBoxes
where doc.Size == size
select new {Name = doc.Name, id = doc.DefinitionID}, "Id", "Name");
Rendered Output (from it as an array):
selected value should be: 1
<select class="form-control" data-val="true" data-val-number="The field ContentDefinitionID must be a number." data-val-required="The ContentDefinitionID field is required." id="ContentBoxes_0__ContentDefinitionID" name="ContentBoxes[0].ContentDefinitionID" style="width:25%;float:left"><option value="1">Test1</option>
<option value="2">Test 2</option>
<option value="4">Test 4</option>
<option value="0">Test 0</option>
</select>
And None of them are selected.
From the html your generating (name="ContentBoxes[0].ContentDefinitionID"), you are using this in a for loop. Unfortunately DropDownListFor() does not work as expected in a for loop and you need to use a custom EditorTemplate for your model (its been reported as a bug but not yet fixed).
You have not posted your models, but assuming
public class ContentBox
{
public int ContentDefinitionID { get; set; }
....
}
public class ContentBoxesVM
{
public IEnumerable<ContentBox> ContentBoxes { get; set; }
public SelectList ContentBoxesSelectList { get; set; }
}
Side note: Its only necessary to generate one SelectList (rather that one for each object in the collection)
Controller
public ActionResult Edit()
{
ContentBoxesVM model = new ContentBoxesVM();
// populate model, for example
model.ContentBoxes = new List<ContentBox>()
{
new ContentBox { ContentDefinitionID = 4 }
};
model.ContentBoxesSelectList = new SelectList(...);
return View(model);
}
Editor Template (/Views/Shared/EditorTemplates/ContentBox.cshtml)
#model ContentBox
....
#Html.DropDownListFor(m => m.ContentDefinitionID, (SelectList)ViewData["contentBoxesList"])
...
Main view
#model ContentBoxesVM
#using(Html.BeginForm())
{
....
// pass the select list as additional view data to the editor template
#Html.EditorFor(m => m.ContentBoxes, new { contentBoxesList = Model.ContentBoxesSelectList })
....
<input type="submit" />
}
You can achieve what you want by changing your model:
class PageModel
{
Int64 ContentDefinitionID {get;set;}
List<ContentDefinitionDocument> ContentBoxesList {get;set;}
}
and in controller:
array of N model.ContentBoxesList = allContentBoxes.Where(doc => doc.Size == size).ToList();
and in View create SelectList this way:
#Html.DropDownListFor(m => m.ContentDefinitionID,
new SelectList(Model.ContentBoxesSelectList,
"DefinitionID",
"Name",
Model.ContentDefintionID),
new {#class = "form-control"})

MVC 5 select list issues

I have got a number of problems:
Why will
<select id="SetLang" data-bind="options: languageSettingEx,
optionsText: 'Settedlanguage', optionsValue: 'slid' ">
</select>
but
#Html.DropDownListFor(m => m.SelectedLanguageSettingEx,
(SelectList)Model.languageSettingItemsEx, new
{
id = "slid",
data_bind = " options: languageSettingEx, optionsText: 'Settedlanguage', optionsValue: 'slid'"
})
this model is
public class langViewModel
{
public string SelectedLanguageSettingEx { get; set; }
public SelectList languageSettingItemsEx { get; set; }
}
in then using knockout to read the values and bind to the list, which works its in the normal select, I have also got the same type of way all over my application however this on fails.
Gives me the error
There is no ViewData item of type 'IEnumerable' that has the key 'SelectedLanguageSettingEx'.
this is knoutout.js bound from a JSON object
I want to either bind this to a call back on a controller, or set a Session variable

Specific parts of model for drop down list

This is what I'm trying to accomplish.
Basically I have Currency model which contains ID,Name, BuyValue, MidValue, SellValue, and DateCreated.
Now I want to use them in converter I've come up with. It has two drop down lists, where first ddl is From which currency is converted and second To which currency it is converter. Regular stuff.
The first ddl should always contain Name as text in ddl and BuyValue as value, whereas second should always contain Name as text and SellValue as value. Something like this in simple HTML terms.
<select id="ddlFirst">
<option value="BuyValue1">Name1</option>
<option value="BuyValue2">Name2</option>
...
</select>
<select id="ddlSecond">
<option value="SellValue1">Name1</option>
<option value="SellValue2">Name2</option>
...
</select>
Of course this isn't the code for it, it's just clarifying the explanation above.
I'm quite a beginner on this matter, and literally have no clue where to start. What gets me the most is should I somehow separate those values into different models and create a view model out of them or could I just use them somehow. To be honest I'm quite confused so any help is appreciated.
UPDATE
var currencies = db.Currencies.Where(c => c.DateCreated.Equals(today));
var list = currencies.Select(s => new { s.ID, s.Name, s.BuyValue, s.SellValue }).ToList();
var model = new ConverterViewModel
{
FromValues = list.Select( x => new SelectListItem { Value = x.BuyValue.ToString(), Text = x.Name}),
ToValues = list.Select(x => new SelectListItem { Value = x.SellValue.ToString(), Text = x.Name }),
};
This comes up empty though. :( And I know it's not.
What gets me the most is should I somehow separate those values into
different models and create a view model out of them or could I just
use them somehow.
Yes, of course, you should define a view model:
public class MyViewModel
{
public string From { get; set; }
public IEnumerable<SelectListItem> FromValues { get; set; }
public string To { get; set; }
public IEnumerable<SelectListItem> ToValues { get; set; }
}
and then have a controller action populate this view model and pass it to the view:
public ActionResult SomeAction()
{
var currencies = _db.Currencies.ToList();
var model = new MyViewModel
{
FromValues = currencies.Select(x => new SelectListItem { Value = x.BuyValue.ToString(), Text = x.Name }),
ToValues = currencies.Select(x => new SelectListItem { Value = x.SellValue.ToString(), Text = x.Name })
};
return View(model);
}
and finally have a strongly typed view:
#model MyViewModel
<div>
#Html.LabelFor(x => x.From)
#Html.DropDownListFor(x => x.From, Model.FromValues)
</div>
<div>
#Html.LabelFor(x => x.To)
#Html.DropDownListFor(x => x.To, Model.ToValues)
</div>

Categories