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
Related
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>
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>
When creating Employee entity you are supposed to select MeetingCenterfrom DropDownList. All MeetingCenters show just fine in DropDownList with their Names, but when some of them is selected and Employee is created Meeting Center is null. Im using NoSQL DocumentDB database.
Controller:
[ActionName("Create")]
public async Task<IActionResult> CreateAsync()
{
ViewBag.MeetingCentersList = await _meetingCenterReposiotry.GetItemsAsync();
return View();
}
Create View:
#model Employee
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { #class = "form-horizontal" }))
{
...
<div class="form-group">
#Html.LabelFor(MeetingCenter => Model.MeetingCenter, new { #class = "control-label" })
#Html.DropDownListFor(MeetingCenter => Model.MeetingCenter, new SelectList(ViewBag.MeetingCentersList, "MeetingCenterId", "Name"), new { #class = "form-control" })
</div>
...
}
Piece of Employee Model
public class Employee
{
...
[JsonProperty(PropertyName = "id")]
public string EmployeeId { get; set; }
[JsonProperty(PropertyName = "meetingCenter")]
public MeetingCenter MeetingCenter { get; set; }
...
}
Piece of MeetingCenter Model
public class MeetingCenter
{
...
[JsonProperty(PropertyName = "id")]
public string MeetingCenterId { get; set; }
...
}
With your current code, the DropDownListFor helper will render a SELECT element with options, which has the MeetingCenterId as the value attribute and the Name as the Text. The SELECT element's name attribute value will be MeetingCenter. So when the form is submitted the form data will look like this
MeetingCenter: 2
Assuming user selected the option with value "2".
But the MeetingCenter property of your view model(Employee) is not a numeric type, it is a complex type(MeetingCenter). So model binder cannot map this value to MeetingCenter property of your view model.
You can render the SELECT element with the name MeetingCenter.MeetingCenterId and then model binder will be able to map the posted form data as the input element name matches with the naming-structure of your view model.
So you should render something like this inside your form.
<select name="MeetingCenter.MeetingCenterId">
</select>
You can generate the above markup by using the SELECT tag helper and specifying MeetingCenter.MeetingCenterId as the asp-for property.
<select asp-for="MeetingCenter.MeetingCenterId"
asp-items="#(new SelectList(ViewBag.MeetingCentersList,
"MeetingCenterId", "Title"))">
</select>
Now when the form is submitted, it will populate the MeetingCenter property of your view model and it's MeetingCenterId property.
If you want the full MeetingCenter property to be populated (properties other than MeetingCenterId, get the full object by querying the data provided by _meetingCenterReposiotry.GetItemsAsync() using the MeetingCenterId available to you in the HttpPost action. Something like this
var id = viewModel.MeetingCenter.MeetingCenterId;
var items = await _meetingCenterReposiotry.GetItemsAsync();
var item = items.FirstOrDefault(a=>a.MeetingCenterId==id);
// User item now
// May be do somethig like : viewModel.MeetingCenter = item;
I also suggest you to use the correct types. If MeetingCenterId is numeric value, use int as type instead of string
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.
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"})