I have this simple knockout.js application:
View:
<select data-bind="options: allDocumentTypes , optionsCaption: 'Choose ...', optionsValue: 'id', optionsText: 'name', selectedOptions: selectedDocument"></select>
<span data-bind="click: cl">CLEAR VALUE!</span>
and this simple ViewModel:
function documentType(id, name){
this.id = id;
this.name = name;
}
var viewModel = {
allDocumentTypes: ko.observableArray([]),
selectedDocument: ko.observable(''),
cl: function(){
viewModel.selectedDocument('');
}
};
/* load data */
viewModel.allDocumentTypes.push(new documentType(1,'Test 1'));
viewModel.allDocumentTypes.push(new documentType(2,'Test 2'));
ko.applyBindings(viewModel);
I would expect, that after i click on span "CLEAR VALUE!", in select will be selected option "choose...", but it is not happening.
The value in viewModel is set to "" (empty string), which is right, but user still see old value in select.
Is there any way to do that?
Thanks for helping:)
You must change binding type to "value" instead of "selectedOptions". Next step is to set viewModel.selectedDocument in cl function:
viewModel.selectedDocument(null);
In some cases setting the observable value to null will not work, for example :
// This is the array
self.timePeriods = ko.observableArray([
new timePeriod("weekly", 7),
new timePeriod("fortnightly", 14),
new timePeriod("monthly", 30),
new timePeriod("half yearly", 180),
new timePeriod("yearly", 365)
]);
And below is the HTML part:
<select data-bind="options: timePeriods,
optionsText: function(item) {
return item.Name;
},
value: selectedPeriod"
class="combo">
You can't reset select box by:
self.selectedPeriod(null); // but this will not work
Insetead write this:
self.selectedPeriod(self.timePeriods()[0]);
<script>
var vm ={
CountryId=ko.observable(),
QC=ko.observable(),
clearSelectedStation: function () {
this.CountryId(null); //DropDown
this.QC(''); //Textbox
}
};
</script>
here is a html
<input type="text" tabindex="10" data-bind="value:QC"/>
<select class="dropdownlist" data-bind="options:Countries, value: CountryId,
optionsCaption: '--Select--', optionsText: 'CountryName', optionsValue: 'CountryId'">
Related
I am trying to get the text of selected index in dropdown using knockout.js,
following is my HTML
<select name="" id="management" class="form-control" data-bind="value: ManagementCompanies,optionText:ManagementCompaniestxt">
<option value="0">---Select---</option>
<option value="1">abcd</option>
<option value="2">efgh</option>
</select>
following is my Model binding:
var FilterViewModel = {
ManagementCompanies: ko.observable(''),
ManagementCompaniestxt:ko.observable('')
}
FilterViewModel.ManagementCompanies.subscribe(function (newValue) {
alert(FilterViewModel.ManagementCompaniestxt());
});
ko.applyBindings(FilterViewModel, window.document.getElementById("SelectFilters"));
i have tried to bind using Text as well but didn't work.
how can i get selected text abcd in subscribe event?
thanks
It's a bit weird that you're trying to get data from your view to your viewmodel. Usually, your view is a representation of your viewmodel. It's better to have the data needed to render your <select> in your model, and use knockout's options data-bind to render it.
Here's how you can do this:
var FilterViewModel = {
ManagementCompanies: ko.observable(''),
ManagementCompaniestxt: ko.observable(''),
options: [
{ text: "---Select---", value: 0 },
{ text: "abcd", value: 1 },
{ text: "efgh", value: 2 }]
}
FilterViewModel.ManagementCompanies.subscribe(function(newValue) {
console.log(newValue.text);
});
ko.applyBindings(FilterViewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<select data-bind="value: ManagementCompanies,
options:options,
optionsText: 'text'">
</select>
[ Please see updates at the bottom ]
I'm trying to make knockout depended selects, it's intended to make a "product" selection by these attributes, for example a product can have "size" and "material", if I selected "size", a knockout script make a request to the backend and retrieves which "material" available for the selected size, in other words, if an attribute is selected, other attributes are filtered out to show only available values ("all sizes": 1,2,3,4,5; "aluminium": 1,4).
Attributes list are completely dynamic, there are about 80 attributes which can be linked to the products in arbitrary way.
Are there any "best practices" for this situation?
I am trying to solve it with code like this, without success yet:
var ViewModel = function(data) {
var self = this;
self.data = data;
self.attributes = ko.observableArray();
self.data.forEach(function(item, i, a) {
// I passed .self to catch it later
// in products as view_model.attributes().
self.attributes.push(new VariableProduct(item, self));
})
};
var VariableProduct = function(item, view_model) {
var self = this;
self.attribute_name = ko.observable(item.name);
self.attribute_value = ko.observable('--');
// list of attribute values
self.attribute_values = ko.computed(function() {
var result = {};
view_model.attributes().forEach(function(attribute, i, a) {
// here I try to filter each attributes lists by values
// it doesn't work well
if (attribute.attribute_name() != self.attribute_name() && self.attribute_value() != '--') {
result = attribute.attribute_values().filter(
function(value) {
return value.indexOf(self.attribute_value()) >= 0;
});
}
});
return result;
});
};
UPDATE 1:
With Dnyanesh's reference to ko.subscribe(), i've achived these results, isn't ok yet, but a progress:
http://jsfiddle.net/xwild/65eq14p3/
UPDATE 2:
At the end it was solved with knockout.reactor and knockout.mapping plugins.
Related stackoverflow question with details and the answer.
For dependent select I think you can use subscribe in following manner
var vm = {
sizes: ko.observableArray([
{ name: 'size 1', id: 1},
{ name: 'size 2', id: 2},
{ name: 'size 3', id: 3},
{ name: 'size 4', id: 4}
]),
selectedSize : ko.observable(0),
};
vm.selectedSize.subscribe(function(newValue){
alert('Selected Size is ---> ' + newValue )
// Here at this point call your ajax or backend method and bind the values which are coming form
});
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<select data-bind="
options: sizes,
optionsText: 'name',
optionsValue: 'id',
value: selectedSize,
optionsCaption: 'Choose Size...'"">
</select>
<select data-bind="
options: material,
optionsText: 'name',
optionsValue: 'id',
value: selectedMaterial,
optionsCaption: 'Choose Material...'"">
</select>
I know I am talking about only part of solution to your problem but, I think you need to divide your data object to bind it to various controls.
I have an issue with Knockout.js . What I try to do is filter a select field. I have the following html:
<select data-bind="options: GenreModel, optionsText: 'name', value: $root.selectedGenre"></select>
<ul data-bind="foreach: Model">
<span data-bind="text: $root.selectedGenre.id"></span>
<li data-bind="text: name, visible: genre == $root.selectedGenre.id"></li>
</ul>
And the js:
var ViewModel = function (){
self.selectedGenre = ko.observable();
self.Model = ko.observableArray([{
name: "Test",
genre: "Pop"
}
]);
self.GenreModel = ko.observableArray([
{
name: "Pop",
id: "Pop"
},
{
name: "Alle",
id: "All"
}
]);
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
JSFiddle: http://jsfiddle.net/CeJA7/1/
So my problem is now that the select list does not update the binding on the span inside the ul and I don't know why...
The value binding should update the property selectedGenre whenever the select value changes, shouldn't it?
Any ideas are welcome.
There are a lot of issues in your code:
1) self is not a magical variable like this. It's something people use to cope with variable scoping. Whenever you see self somewhere in a JavaScript function be sure there's a var self = this; somewhere before.
2) KnockoutJS observables are not plain variables. They are functions (selectedGenre = ko.observable()). ko.observable() returns a function. If you read the very first lines of documentation regarding observables you should understand that access to the actual value is encapsulated in this retured function. This is by design and due to limitations in what JavaScript can and cannot do as a language.
3) By definition, in HTML, <ul> elements can only contain <li> elements, not <span> or anything else.
Applying the above fixes leads to this working updated sample:
HTML:
<select data-bind="options: GenreModel, optionsText: 'name', value: selectedGenre"></select>
<span data-bind="text: $root.selectedGenre().id"></span>
<ul data-bind="foreach: Model">
<li data-bind="text: name, visible: genre == $root.selectedGenre().name"></li>
</ul>
JavaScript:
var ViewModel = function (){
var self = this;
self.selectedGenre = ko.observable();
self.Model = ko.observableArray([
{
name: "Test",
genre: "Pop"
}
]);
self.GenreModel = ko.observableArray([
{
name: "Pop",
id: "Pop"
},
{
name: "Alle",
id: "All"
}
]);
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
I'm trying to show or hide a div based on a selection from a list. I'm not quite sure how to handle the observable for the div being passed to a function so it can return a true or false value to show or hide the div.
If "American Express" is selected from the list, I want to display the "postalCodeDiv", otherwise hide it.
I have a fiddle for it here
<label for="Card Type">Card Type</label>
<select data-bind='value: cardType, options: $root.cardTypeList, optionsText: "type"'>
</select>
<div data-bind="visible: postalCodeDiv()">
<label for="PostalCode">Postal Code (required for AMEX)
</label>
</div>
Here's the javascript
function cardTypeSelection(cardType,postalCodeDiv){
var self = this;
self.cardType = cardType;
self.postalCodeDiv = postalCodeDiv;
if(self.cardType == "American Express"){
return self.postalCodeDiv(true);
}
else{
return self.postalCodeDiv(false);
}
}
function MakePaymentViewModel(cardType) {
var self = this;
self.postalCodeDiv = ko.observable(false);
self.cardTypeList = [
{type: '-'},
{type: 'Visa'},
{type: 'MasterCard'},
{type: 'American Express'}
];
self.cardType = ko.observableArray([
new cardTypeSelection(self.cardTypeList[0], self.postalCodeDiv)
]);
}
ko.applyBindings(new MakePaymentViewModel());
And upon selection of it, I pass it to a function to enable/disable based on the value of the selection
i think you can have it much easier than you tried. not quite sure why you try to store the selected value from the dropdown into an array, you could just store the selected value into an observable and toggle the div visibility upon this.
jsFiddle
ViewModel:
function MakePaymentViewModel(cardType) {
var self = this;
self.cardTypeList = [
{type: '-'},
{type: 'Visa'},
{type: 'MasterCard'},
{type: 'American Express'}
];
self.cardType = ko.observable(self.cardTypeList[1]);
}
ko.applyBindings(new MakePaymentViewModel());
HTML:
<label for="Card Type">Card Type</label>
<select data-bind='value: cardType, options: $root.cardTypeList, optionsText: "type"'>
</select>
<div data-bind="visible: cardType() == cardTypeList[3]">
<label for="PostalCode">Postal Code (required for AMEX)
</label>
</div>
As an alternative to the accepted answer provided by #infadelic, here is an example using a computed observable. If you need this logic in more than one place, you may want to put it in your viewModel as a computed observable instead of having the logic repeated in multiple bindings.
Fiddle: http://jsfiddle.net/6ymwN/12/
ViewModel
function MakePaymentViewModel(cardType) {
var self = this;
self.postalCodeDiv = ko.observable(false);
self.cardTypeList = [
{type: '-'},
{type: 'Visa'},
{type: 'MasterCard'},
{type: 'American Express'}
];
self.cardType = ko.observableArray([
new cardTypeSelection(self.cardTypeList[0], self.postalCodeDiv)
]);
self.selectedCardType = ko.observable();
self.isAmex = ko.computed(function(){
var card = self.selectedCardType();
return card == 'American Express';
});
}
HTML
<label for="Card Type">Card Type</label>
<select data-bind='value: cardType, options: $root.cardTypeList, optionsText: "type", optionsValue: "type", value: selectedCardType'>
</select>
<div data-bind="visible: isAmex()">
<label for="PostalCode">Postal Code (required for AMEX)
</label>
</div>
I'm having hard time getting the selected value of dropdown list using Knockout JS
jsFiddle
HTML
<select id="l" data-bind="options: locations, value=selectedLocation"></select>
<select id="j" data-bind="options: jobTypes, value=selectedJobType"></select>
<button data-bind="click: myFunction"> Display </button>
Script
var viewModel = {
locations: ko.observableArray(['All Locations', 'Sydney', 'Melbourne', 'Brisbane', 'Darwin', 'Perth', 'Adelaide']),
selectedLocation: ko.observable(),
jobTypes: ko.observableArray(['All Vacancies', 'Administration', 'Engineering', 'Legal', 'Sales', 'Accounting']),
selectedJobType: ko.observable(),
myFunction: function() {
alert(selectedJobType + ' ' +selectedLocation );
}
};
// ... then later ...
//viewModel.availableCountries.push('China');
// Adds another option
ko.applyBindings(viewModel);
That should be
value:selectedLocation
and:
value:selectedJobType
in you bindings. Bindings use the same syntax as an object literal.
Also, in your alert, you need viewModel.selectedJobType(), because (a) it's a property of viewModel not of global and (b) it's an observable so you need to call it to get the value. Same for selectedLocation.
Here's a working fiddle