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.
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 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>
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.
Help me please with knockout.js problem:
Why variable currentObject is undefinded ? How I can save current selected object in some variable ?
I have follow html view for down drop list:
<select data-placeholder="Select object" class="span5" id="objects" data-bind="options: objects, optionsText: 'Name', optionsValue: 'Id', value: currentObject">
<option></option>
</select>
ModelView:
function baseViewModel() {
self.objects = ko.observableArray([]);
...
self.currentObject = ko.observable();
...
self.func = function() {
//allert(self.objects()[0].Name) //return correct Name
alert(self.currentObject().Name) //returns undefinded
}
}
In your data-bind, you have value: currentObject which will indeed do a two-way bind between currentObject and the select's value.
The select's value is set to the Id field of the selected option's object (because of optionsValue: 'Id' in your data-bind).
So, currentObject will be set to the Id field of the selected object, and that's why doing .Name gets you undefined.
I suggest not using optionsValue at all, this way KO will handle the value and it will be as if the value of the selectbox is the actual selected object, and value: currentObject will correctly set currentObject to the selected object. (And if you do want to use optionsValue, then know that currentObject will be set to the object's field, not the object itself)
Fiddle: http://jsfiddle.net/antishok/KXhem/78/
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.