I am having an issue understanding how i'm supposed to get the selectedValue of a select (drop down) list i've binded using knockout.mapping.
heres the ajax call and mapping:
var EmailCollection;
function GetAllEmailsAjax() {
$.ajax({
url: "http://localhost:54756/api/Email",
type: "GET",
dataType: "JSON",
success: function (data) {
GetAllEmails(data);
}
});
}
function GetAllEmails(data) {
// not sure if this is 100% correct but it does seem to work as expected
if (!EmailCollection) {
EmailCollection = ko.mapping.fromJS(data);
}
ko.mapping.fromJS(data, EmailCollection);
ko.applyBindings(EmailCollection);
}
<select data-bind="options: EmailCollection, optionsText: 'Name', optionsValue: 'Id', optionsCaption: 'Choose...'"></select>
as i understand it i need to specify the value in the select data-bind attribute. So it would be something like this:
however, this would mean that selectedEmail would need to be a part of my model. However as all this is being created by knockout.mapping im unsure how i do that. I am presuming some kind of Model like the following but I am unsure on how to go about it.
var EmailViewModel = {
selectedEmail : ko.Observable(),
Emails : EmailCollection // the previous model mapped bound in a scenario like this
};
// EmailViewModel.selectedEmail() would then contain my selected value..
I'm sure once i see it on paper it will all become obvious just at the moment im struggling to work it out.
If only one email will be selected (implied since you're using a dropdown), you should create a variable to hold the selected email id. If it defaults to the first email in the collection, you'd do something like this:
var selectedEmailId: ko.observable();
...
function GetAllEmails(data) {
...
ko.mapping.fromJS(data, EmailCollection);
selectedEmailId(EmailCollection.peek().Id); //Assuming EmailCollection is an array
ko.applyBindings(EmailCollection);
}
<select data-bind="options: EmailCollection, optionsText: 'Name', optionsValue: 'Id',
optionsCaption: 'Choose...', value: selectedEmailId"></select>
selectedEmailId should then be updated any time the dropdown selection is changed.
Related
I need some help with js/knockout/databindings.
In my code I am receiving an object like this:
Received object
I wish to show the value in a dropdown, and the key should be stored as the value.
I tried using some knockout data-bind like this:
<select id="routeTable" class="form-control" data-bind="
options: availableRouteTables,
optionsText: availableRouteTables.key,
optionsValue: availableRouteTables.value,
value: selectedRouteTable,
optionsCaption: '- velg rutetabell -'"></select>
I know that "availableRouteTables.key" and "availableRouteTables.value" are wrong, but it was just to explain/show what I want.
As of now the object only looks like this in JS:
this.availableRouteTables = availableRouteTables;
In the dropdown it is shown like this:
Dropdown failure
Can someone help me with identifying the issue and fix it?
thanks a lot!
When you receive the data you have to change it's structure to work with the options binding:
// Convert to array of objects with value and text properties
var availableRouteOptions = [];
for(var key in availableRouteTables) {
availableRouteOptions.push({
value: key,
text: availableRouteTables[key]
});
}
And you have to change your bindings:
options: availableRouteOptions,
optionsText: 'text',
optionsValue: 'value',
I have two selections, the seconds options options are dependent on the first selection.
Both of the selection boxes NEED to have a class attached to them, so I can not use the options attribute. The only way I have found to do this is using the foreach method.
I need to track both of the selected values at any time, but the second selection does not update its value when repopulated with new data. Please see the fiddle.
Another requirement is if the original option passed in through the viewmodel creation for the second selection is there, I would like that to be the default when populated. e.g in the fiddle when changing from WPA-PSK to none and then back I would like the default selection to be MIX(passed in) rather than AES.
Fiddle: Link to Fiddle
function ViewModel(security) {
var self = this;
self.authenticationMode = ko.observable(security.authenticationMode);
self.encryptionType = ko.observable(security.encryptionType);
self.authenticationModes = ko.observableArray([{translationText: "None", mode: "NONE", translationClass: "T_WPA-PSK"},
{translationText: "Open", mode: "OPEN", translationClass: "T_WPA-PSK"},
{translationText: "WPA-PSK", mode: "WPA-PSK", translationClass: "T_WPA-PSK"}]);
self.encryptionTypes = ko.computed(function () {
console.log(self.authenticationMode());
if (self.authenticationMode() === 'OPEN')
return [{translationText: "WEP", type: 'WEP', translationClass: "T_WEP"}];
if (self.authenticationMode() === 'WPA-PSK')
return [{translationText: "AES", type: 'AES', translationClass: "T_AES"},
{translationText: "MIX", type: 'MIX', translationClass: "T_MIX"}];
return [];
});
}
ko.applyBindings(new ViewModel({authenticationMode: 'WPA-PSK', encryptionType: 'MIX'}));
<select data-bind="value: authenticationMode, foreach: authenticationModes">
<option data-bind="text: translationText, value: mode, attr: { class: translationClass }"></option>
</select>
<select data-bind="value: encryptionType, foreach: encryptionTypes">
<option data-bind="text: translationText, value: type, attr: { class: translationClass }"></option>
</select>
<p>Selected Authentication: <b data-bind="text:authenticationMode"></b></p>
<p>Selected Encryption Type: <b data-bind="text:encryptionType"></b></p>
Fiddle Using Options - Another way I found using options to set the class with optionsAfterRender method.
Updated your fiddle:
http://jsfiddle.net/fS8qp/7/
Both requirements are met by adding the following in your viewmodel:
self.defaultEncryptionType = security.encryptionType;
self.authenticationMode.subscribe(function () {
self.encryptionType(self.defaultEncryptionType); // This will select the passed in encryptionType, if it exists in the current list of options
self.encryptionType.valueHasMutated(); // This will trigger an update of the observable
});
How do I set default value on an input box with select2? Here is my HTML:
<input type="text" id="itemId0" value="Item no. 1">
and my javascript:
$("#itemId0").select2({
placeholder: 'Select a product',
formatResult: productFormatResult,
formatSelection: productFormatSelection,
dropdownClass: 'bigdrop',
escapeMarkup: function(m) { return m; },
minimumInputLength:1,
ajax: {
url: '/api/productSearch',
dataType: 'json',
data: function(term, page) {
return {
q: term
};
},
results: function(data, page) {
return {results:data};
}
}
});
function productFormatResult(product) {
var html = "<table><tr>";
html += "<td>";
html += product.itemName ;
html += "</td></tr></table>";
return html;
}
function productFormatSelection(product) {
var selected = "<input type='hidden' name='itemId' value='"+product.id+"'/>";
return selected + product.itemName;
}
Here is the issue:
If I won't initialize my input box into a select2 box, I can display the default value of my input box which is "Item no. 1":
but when I initialize it with select2 eg. $("#itemId0").select2({code here}); I can't then display the default value of my text box:
Anyone knows how can I display the default value please?
You need to utilize the initSelection method as described in Select2's documentation.
From the documentation:
Called when Select2 is created to allow the user to initialize the selection based on the value of the element select2 is attached to.
In your case, take a look at the Loading Remote Data example as it shows how to incorporate it along with AJAX requests.
I hope this helps.
Old initial selections with initSelection
In the past, Select2 required an option called initSelection that was
defined whenever a custom data source was being used, allowing for the
initial selection for the component to be determined. This has been
replaced by the current method on the data adapter.
{
initSelection : function (element, callback) {
var data = [];
$(element.val()).each(function () {
data.push({id: this, text: this});
});
callback(data);
}
}
You can use the set value too.
You should directly call .val on the underlying element
instead. If you needed the second parameter (triggerChange), you
should also call .trigger("change") on the element.
$("select").val("1").trigger("change"); // instead of $("select").select2("val", "1");
Refs:
https://select2.github.io/announcements-4.0.html
https://github.com/select2/select2/issues/2086
http://jsfiddle.net/F46NA/7/
If you have an input element, declare it as follows. Remember to populate the value field as well.
<input type="hidden" name="player" id="player" data-init-text="bla bla" value="bla bla" >
Write an initSelection function
initSelection : function (element, callback) {
var elementText = $(element).attr('data-init-text');
callback({"text":elementText,"id":elementText});
}
make sure that this call back has same key value pair as the one return by the ajax call.
callback({"text":elementText,"id":elementText});
I have noticed that keeping the value field empty will keep the input empty by default so remember to populate it as well.
The method initSelection can not have an empty value attribute to work properly.
That was my problem.
Hopefully this will help someone.
You can easily change the value of your select input by just putting the id's of your selected option in data attribute of your select input. And then in javascript
var select = $('.select');
var data = $(select).data('val');
$(select).val(data);
And after that initialize select2 on your select input
$(select).select2();
Here is the fiddle https://jsfiddle.net/zeeshanu/ozxo0wye/
you dont need ajax or json, you just need to put SELETED tag into your OPTION and SELECT2 will display the init value.
This works for me: 'Add default value to the head of array'
data.unshift({'id':-1, 'name':'xxx'});
$('#id_xxx).select2({
placeholder: '--- SELECT ---',
data: data,
allowClear: true,
width: '100%'
});
However, official doc says:
You can set default options by calling $.fn.select2.defaults.set("key", "value").
There is no example though.
I found the extremly simple solution.
You have to pass the ID and the Name of the default option and insert it like HTML inside
var html = ' <option value="defaultID">defaultName</option>';
$(".js-example-basic-single").html(html);
How to get defaultID or defaultName depends on your code.
For instance in ASP .Net MVC you can do it like
<select id="PersonalID" class="js-example-basic-single form-control form-control-sm" name="PersonalID">
<option value="#Model.PersonalID">#ViewBag.PersonalInfo</option>
</select>
I use another approach in this specific configuration:
- multiple="multiple"
- populating from AJAX on user's search
$("#UserID").select2({
placeholder: 'Input user name',
"language": {
"noResults": function () {
return "Sorry, bro!";
}
},
dropdownParent: $("#UserID").parent(),
ajax: {
delay: 200,
url: '#Url.Action("GetUserAsJSON", "AppEmail")',
cache: true,
dataType: 'json',
data: function (params) {
var query = {
search: params.term,
page: params.page || 1
};
// Query parameters will be ?search=[term]&page=[page]
return query;
}
}
});
There are few steps to get working my solution
1) Keep each added value in a global array.
var selectedIDs = new Array();
$("#UserID").on('change', function (e) {
//this returns all the selected item
selectedIDs = $(this).val();
});
2) So when you save data you always have selectedIDs array.
3) When you refresh/load webpage just populate selectedIDs with saved data for later resaving/editing from one hand and from another hand populate select2 object
In my case of ASP MVC it looks like this but you can use JQuery to insert <option> to <select>.
<select id="UserID" class="js-example-basic-multiple form-control border" name="UserID" style="width:100%!important;" multiple="multiple">
foreach (var item in Model.ToUsers)
{
<option selected="selected" id="#item.ID" value="#item.ID">#item.Value</option>
}
</select>
I'm having some issues with a dropdown list where I need to pass the initial value to the viewmodel. Just to clarify: I'm working on an edit-form, so the dropdownlist will be populated with an already-selected value.
What I have so far is:
Razor:
<select data-bind="selectedOptions: selectedLength">
// razor code omitted
foreach(var preValue in lengthPreValues)
{
if(lengthPreValues.Contains(preValue.value))
{
<option selected="selected" value='#preValue'>#preValue</ option>
}
else
{
<option value='#preValue'>#preValue</option>
}
}
And my viewmodel looks like this:
var editOfferViewModel = {
// Properties omitted
selectedLength: ko.observable("")
};
ko.applyBindings(editOfferViewModel);
While this definately works when selecting a new value, I'm a bit stuck when it comes to setting the initial value. I was fortunate enough to get some great help from Ryan Niemeyer here on stackoverflow.com with checkboxes and creating custom bindinghandlers, but I'm still
having a hard time to figure it out to be honest.
So, any help and/or hint on this is greatly appreciated!
A common and easy way to do this is to serialize your model values to the page. This would be something like:
var viewModel = {
choices: ko.observableArray(#Html.Raw(Json.Encode(Options))),
selectedChoices: ko.observableArray(#Html.Raw(Json.Encode(SelectedOptions)))
};
Then, just use a standard data-bind on your select like:
data-bind="options: choices, selectedOptions: selectedChoices"
You then don't even need to populate the option elements in Razor.
If your viewModel is built in an external file, then you can just set the value of the observables in your view (after your external script has been loaded)
My data is something like :
dataList = [ {name:'length1',id:1},{name:'length2',id:2},{name:'length3',id:3},{name:'length4',id:4},{name:'length5',id:5} ]
And I have been using that data with dropdown like this :
<select name="xxx" id="xxxid" data-bind="options: dataList, value: selectedLength , optionsText: 'name', optionsValue: 'id', optionsCaption: 'Please Select...'"></select>
<select name="xxx2" id="xxxid2" data-bind="options: dataList, selectedOptions: multiSelectedLength , optionsText: 'name', optionsValue: 'id', optionsCaption: 'Please Select...'" size="5" multiple="true"></select>
var editOfferViewModel = {
selectedLength: ko.observable(),
multiSelectedLength: ko.observableArray()
};
ko.applyBindings(editOfferViewModel);
$(document).ready(function() {
// Set initial value
editOfferViewModel.selectedLength(2);
// Set inital multi value
editOfferViewModel.multiSelectedLength(['2','3']);
});
You can use value property to set initial value.
Here is the working example.
I'm having a small issue with setting the initial value of a dropdown. The code below is the view model definition and the initialization in $(document).ready. I have an array called sourceMaterialTypes and a selectedSourceMaterialType representing the selected value of that array. I am initializing the view model with values from the (ASP.Net MVC) Model and ViewBag.
var viewModel = {
sourceMaterialTypes :
ko.observableArray(#Html.Raw(Json.Encode(ViewBag.SourceMaterialTypes))),
selectedSourceMaterialType :
ko.observable(#Html.Raw(Json.Encode(Model.SourceMaterialType))),
ingredientTypes :
ko.observableArray(#Html.Raw(Json.Encode(ViewBag.IngredientTypes))),
selectedIngredientType : ko.observable()
};
$(document).ready(function () {
ko.applyBindings(viewModel);
viewModel.selectedSourceMaterialType.subscribe(function(newSourceMaterialType) {
$.getJSON("/IngredientType/FindByMaterialType",
{ "id": newSourceMaterialType })
.success(function (data) {
viewModel.ingredientTypes($.parseJSON(data));
})
.error(function () { alert("error"); });
});
});
The following is the definition of my dropdown (select) list with the Knockout binding definition.
<select id="SourceMaterialTypeId"
name="SourceMaterialTypeId"
data-bind="options: sourceMaterialTypes,
optionsText: 'Name',
optionsValue : 'Id',
value: selectedSourceMaterialType"></select>
This all works fine except for the initially selected value in the source materials dropdown (selectedSourceMaterialType is bound correctly so when the dropdown selection changes its value is correctly updated, it is only the initial selection I am having a problem with), which is always the first item in the sourceMaterialTypes array on my view model.
I would like the initially selected value to be that which is initialized from the (server-side) model as the value of selectedSourceMaterialType view model property.
I guess you need to pass the Id only and not the whole object in the selectedSourceMaterialType observable function ->
selectedSourceMaterialType: ko.observable(#Model.SourceMaterialType.Id)
The API has the solution for you, you'll just need to add optionsCaption to your select.
<select id="SourceMaterialTypeId"
name="SourceMaterialTypeId"
data-bind="options: sourceMaterialTypes,
optionsText: 'Name',
optionsValue : 'Id',
value: selectedSourceMaterialType,
optionsCaption: 'Please select...'"></select>
As #nEEBz suggested, selectedSourceMaterialType is initialized improperly. In the learn.knockoutjs.com "Lists and Collections" tutorial, they initialize their viewmodel's selected-item property by passing the value of a specific index of the observable array. For example, do this:
selectedSourceMaterialType: ko.observable(sourceMaterialTypes[2])
...instead of this:
selectedSourceMaterialType: ko.observable({"Id":1,"Name":"Coffee Bean" /* ... */});
That way, the value of the selected item is a reference to the item in the same observable array that the dropdownlist items come from.