Knockout.js - select value not set - javascript

I am using knockout.js, and it's not setting the value of an empty option (Four):
<select data-bind="value: item.widgetValue, attr: {id: item.widgetName, name: item.widgetName}, options: item.options, optionsText: ‘label’, optionsValue: ‘value’” id=”fld-“ name=”fld0”>
<option value=”one”>One</option>
<option value=”two”>Two</option>
<option value=”three”>Three</option>
<option value>Four</option>
...
</select>
This is creating a problem: when you're on any option and try to select Four, it selects One; it will only select Four the second time you try to select it.
I have tried changing the knockout data-bind to fix it:
value: $.trim(item.widgetValue)
This allows you to select Four immediately, but incorrectly shows One as being selected after you submit the form with Four selected.
Any ideas as to what could be causing this, or how to fix it?

You shouldn't be manually setting options if you are using the options binding on your select element. If those are being dynamically created by the binding (ie. you are actually using item.options for your source) then check the objects you are binding the select element to -
item.options probably looks like this (missing a value or is somehow not like the other options) -
item.options = [
{ label: 'someLabel1', value: 'someValue1' },
{ label: 'someLabel2', value: 'someValue2' },
{ label: 'someLabel3', 'someValue3' }
];
but should be a more uniform object like this (well defined model) -
function optionModel(label, value) {
var self = this;
self.label = ko.observable(label);
self.value = ko.observable(value);
}
item.options = [
new optionModel('someLabel1', 'someValue1'),
new optionModel('someLabel2', 'someValue2'),
new optionModel('someLabel3', 'someValue3')
];

Related

Framework7: Adding a hidden value to picker

In a standard select list you can pass a hidden variable back to the form handler just by using the value attribute, i.e.:
<select>
<option value="hidden-variable">Displayed Value</option>
</select>
However with Framework7's picker, it doesn't look like there's a way of achieving the same thing. It does allow you to specify 'value' and 'displayValue' for each column, but when you select a 'displayValue', it's the 'value' that gets shown in the actual field. i.e.:
var picker = myApp.picker({
input: '#picker-input',
cols: [
{
values: ['hidden-variable-1','hidden-variable-2'],
displayValues: ['Displayed Value 1','Displayed Value 2']
}
]
});
When you select 'Displayed Value 1' in the picker, it's 'hidden-variable-1' that shows in the field. Is there a way to write the hidden variable to a hidden input field and display the Display Value to the user?
Not too late ?
Try to use the formatValue property.
var picker = app.picker.create({
inputEl: '#picker-input',
formatValue: function(values, displayValues) {
return displayValues;
},
cols: [
{
values: ['hidden-variable-1','hidden-variable-2'],
displayValues: ['Displayed Value 1','Displayed Value 2']
}
]});

Angular: Get the index of the dropdown item

I have the following in my view
<div>
<select ng-model="obj.arr[otherObj.variable]" ng-change="otherObj.variable=SOMETHING">
<option ng-repeat="label in obj.arrs">{{label}}</option>
</select>
</div>
Without the ng-change attribute, this code does what I want when otherObj.variable is one of the indexes of the obj.arr - it selects the correct item in the list.
What I want in addition to this is to set otherObj.variable to the index of the array item that is picked when the dropdown variable is changed. So, if the second value in the dropdown is picked then otherObj.variable should be set to 1. I tried to do this with a
ng-change="otherObj.variable=SOMETHING"
Problem is., I don't know what that SOMETHING should be. Am I doing this right?
EDIT
My requirements are
Select the top option in the dropdown by default
select the appropriate item in the array depending on the value of otherObj.variable (this gets set by some external code so if I come to the page with this value set then I want the correct option selected)
Make sure otherObj.variable is updated if I change the value in the dropdown.
angular.module('selects.demo', [])
.controller('SelectCtrl', function($scope){
$scope.values = [{
id: 1,
label: 'aLabel',
}, {
id: 2,
label: 'bLabel',
}];
$scope.selectedval = $scope.values[0];
});
<script src="https://code.angularjs.org/1.3.15/angular.js"></script>
<div ng-app="selects.demo">
<div ng-controller="SelectCtrl">
<p>Using ngOptions without select as:</p>
<select ng-model="selectedval" ng-options="value.label for value in values"></select>
<p>{{selectedval}}</p>
<p>Using ngOptions with select as statement: (this will return just the id in the model)</p>
<select ng-model="selectedval2" ng-options="value.id as value.label for value in values"></select>
<p>{{selectedval2}}</p>
</div>
</div>
Sorry if my comment was a little cryptic. Select elements like other form elements are actually directives in AngularJS, so they do a lot of stuff for you automatically. You don't need to use an ngChange to populate the ngModel associated with your select element. AngularJS will handle that for you.
Also, you can use ngOptions instead of ngRepeat on select elements to generate the values automatically on options.
Assuming that you have an object with values:
$scope.values = [{
id: 1,
label: 'aLabel',
}, {
id: 2,
label: 'bLabel',
}];
You would write:
<select ng-model="selectedval" ng-options="value.label for value in values"></select>
Now your ngModel is going to be bound to the selected element. It will be set with the value of the object that was chosen. If you add {{selectedval.id}} to your view, it will display the id of the selected element.
If you want to set the value to the first item, in your controller, you would add:
$scope.selectedval = $scope.values[0];
If you want to update some property on $scope.values based on the selected value, you could use something like:
$scope.addActiveProp = function() {
var selected = $scope.values.filter(function(e) { return e == $scope.selectedval; });
selected.active = true;
}
And then run the addActiveProp fn in ngChange on the select.
Please give a try with below code
<select ng-model="obj.arr[otherObj.variable]" ng-change="otherObj.variable=key" ng-options="key as value for (key , value) in obj.arrs"></select>

Knockout Binding not updating with foreach select options

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
});

Knockout won't handle numeric array for multiple select list

I am trying to get a numeric array to bind to my select element. I am using a numeric array because that is what the server is returning. I have a jsFiddle setup demonstrating the problem.
HTML
<select data-bind="selectedOptions: EnvironmentIds" id="EnvironmentIds" multiple="multiple" name="EnvironmentIds">
<option selected="selected" value="1">Hosting</option>
<option value="2">Internal</option>
</select>
Script
function IncidentViewModel() {
var self = this;
//Properties
self.EnvironmentIds = ko.observableArray([1]);
}
var incidentViewModel = new IncidentViewModel();
ko.applyBindings(incidentViewModel);
If you simply switch to a string array like so:
ko.observableArray(["1"])
Then the code works as expected. However, I don't want to use a string array since that isn't the type of the data. Is there a way around this or have I overlooked something simple?
Knockout's options binding uses ko.selectExtensions to give option elements a non-string value. A simple custom binding can do this to the existing options.
ko.bindingHandlers.makeOptionsNumeric = {
init: function(element) {
ko.utils.arrayForEach(element.options, function(option) {
ko.selectExtensions.writeValue(option, +option.value);
});
}
};
Add this to the bindings for your select element.
data-bind="makeOptionsNumeric, selectedOptions: EnvironmentIds"
The order is important. makeOptionsNumeric must run before selectedOptions. If you're not yet using Knockout 3.0, you'll need to give some dummy value to the binding (for example makeOptionsNumeric: {}).
jsFiddle: http://jsfiddle.net/mbest/gUdPq/
JS:
function IncidentViewModel() {
var self = this;
//Properties
self.Environments = [{id: 1, name: 'Hosting'}, {id: 2, name: 'Internal'}]
self.EnvironmentIds = ko.observableArray([1]);
}
var incidentViewModel = new IncidentViewModel();
ko.applyBindings(incidentViewModel);
HTML:
<select data-bind="options: Environments,
optionsText: 'name',
optionsValue: 'id',
selectedOptions: EnvironmentIds" id="EnvironmentIds" multiple="multiple" name="EnvironmentIds">
</select>

Set initial dropdown value to viewmodel

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.

Categories