I've three elements: selectbox, checkbox, input.
viewModel.listTest= [{ value: '1', name: '10' }, { value: '2', name: '20' }];
<select class="form-control" data-bind="options: listTest, value: TestSelectBox, optionsText: 'name', optionsValue: 'value', disable: TestTrigger()"></select>
viewModel.TestTrigger= ko.observable(false);
<input id="TestTrigger" type="checkbox" name="TestTrigger" data-bind="checked: TestTrigger" />
viewModel.inputTest = ko.observable('1');
<input name="inputTest " data-bind="value: inputTest , enable: TestTrigger(), valueUpdate: 'afterkeydown'" />
and I want to make: if checkbox is checked the value from input should pass to
viewModel.testValue
otherwise the value from select box should be pass to
viewModel.testValue
How can I do this ? I think I can use knockout method subscribe on checkbox
Use a computed observable for testValue:
HTML:
<select class="form-control" data-bind="options: listItems, value: selectValue, optionsText: 'name', optionsValue: 'name', disable: trigger()"></select>
<input id="TestTrigger" type="checkbox" data-bind="checked: trigger" />
<input type="text" data-bind="textInput: input , enable: trigger()" />
<div>
Your test value is: <span data-bind="text: testValue">
</div>
JS:
var viewModel = function() {
var self = this;
var _selectValue = "";
self.listItems = [{ value: '1', name: '10' }, { value: '2', name: '20' }];
self.trigger= ko.observable(false);
self.selectValue = ko.observable();
self.input = ko.observable('1');
self.testValue = ko.computed(function() {
if (self.trigger())
return self.input();
else
return self.selectValue();
});
};
ko.applyBindings(new viewModel());
Working JSFiddle
Each time that you update the select box, the checkbox, or the input, Knockout will call the function that you pass into ko.computed() and update whatever control is bound to it.
Under the hood, the act of evaluating the observables (trigger(), selectValue(), and input()) inside of a computed observable sets up the subscriptions to these three observables for you. There is no need to manually subscribe to updates, which is a big part of the labor-saving magic of Knockout.
give your select box an id like this:
<select class="form-control" id = "selectInput"..>
Then try this:
viewModel.testValue = initialValue
$("#TestTrigger").on("change", function(){
if(this.checked)
viewModel.testValue = $("input[name='inputTest']").val()
else
viewModel.testValue = $("#selectInput").val()
});
On a click event, call a function to update the value of the observable 'testValue'.
<input id="TestTrigger" type="checkbox" name="TestTrigger" data-bind="checked: TestTrigger, click: setTestValue()" />
In your viewmodel,
viewModel.testValue = ko.observable();
viewModel.setTestValue = function() {
viewModel.testValue((viewModel.TestTrigger()) ? viewModel.inputTest() : viewModel.TestSelectBox());
console.log(viewModel.testValue());
}
Related
I know that knockout expects us to return true in the function bound to click event in order to check/uncheck a checkbox.
I tried the following code but it is not checking the check boxes. I can display the value using an anonymous computed function but my array can be huge and I don't want to keep performance overhead.
Is there any other way of doing it? or Am I doing it wrong?
Edit: Adding the code
HTML
<div data-bind="foreach: array">
<div data-bind="foreach: $data.child">
<input type="checkbox" data-bind="checked: isChecked, click: function(data, event){$parentContext.$parent.clickBox(data, event, $parent)}">
<span data-bind="text: $data.value"></span>
</div>
<p data-bind="text: label"></p>
</div>
JS
var mainModel = function(){
var self = this;
self.isChecked = ko.observable(true);
self.clickBox = function(data, event, $parent){
var j=0;
for(var i=0; i<$parent.length; i++){
if($parent[i].isChecked()){
j++;
}
}
$parent.label(j);
return true;
}
self.array = ko.observable(
[
{child: [
{value: 'a', isChecked: ko.observable(false)},
{value: 'b', isChecked: ko.observable(false)}],
label: ko.observable(0)
},
{child: [
{value: 'c', isChecked: ko.observable(false)},
{value: 'd', isChecked: ko.observable(false)}],
label: ko.observable(0)
}
]);
}
ko.applyBindings(new mainModel());
You are missing return, change following code
<input type="checkbox" data-bind="checked: isChecked,
click: function(data, event){
$parentContext.$parent.clickBox(data, event, $parent)}">
To
<input type="checkbox" data-bind="checked: isChecked,
click: function(data, event){
return $parentContext.$parent.clickBox(data, event, $parent)}">
if you don't pass return handler, by default knockout will prevent the action by calling
if (handlerReturnValue !== true) {
if (event.preventDefault)
event.preventDefault();
else
event.returnValue = false;
}
Well, I have two problems that worry me a lot ... First, I don't know how to give a default value to the select box.
And I I'm not able to change the value of the select box via an event click ... I've created a fiddle example if someone could give me a hand it would be very appreciated!
HTML
<select id="FilterBox" data-bind="value: siteGetOne">
<option value="-2">City Wide</option>
<!-- ko foreach: sites -->
<option data-bind="text: name, value: $data"></option>
<!-- /ko -->
</select>
Selection Option Object : <span data-bind="text: siteGetOne"></span><br/>
Selection Option name : <span data-bind="text: siteGetOne().name"></span><br/>
Selection Option id : <span data-bind="text: siteGetOne().id"></span><br/>
Set Value to 1
Set Value to 2
Set Value to 3
JS
var viewModel = function() {
var self = this;
setValue = ko.observable();
self.sites = [
{ name: 'Site 1', id: 1},
{ name: 'Site 2', id: 2},
{ name: 'Site 3', id: 3}
];
self.siteGetOne = ko.observable(self.sites[2].id);
self.siteGetOne.subscribe(function (newValue) {
console.log(newValue);
}, self);
}
ko.applyBindings(new viewModel());
http://jsfiddle.net/xjYcu/276/
Edited Final version : http://jsfiddle.net/xjYcu/286/
couple things you may want to change.
here is the entire fiddle. http://jsfiddle.net/xjYcu/283/
the first one is you should use the options binding for your select.
<select id="FilterBox" data-bind=" options: sites,
optionsText: 'name',
value: siteGetOne,
optionsCaption: 'Choose...'">
</select>
also try changing your click bindings to something like this so you can pass in your parameter.
Set Value to 1
Set Value to 2
Set Value to 3
So i am using knockout and trying to get the selected item's id in my javascript on the change event. Here is my html
<div id="platforms" data-bind="with: platformsViewModel">
<p>
Selected Platform:
<select data-bind="options: platforms, optionsText: 'displayName', value: 'id', optionsCaption: 'Choose...', event: { change: loadMedias }" ></select>
</p>
</div>
my view model is as follows
my.viewModels.PlatformsViewModel = function () {
var self = this;
self.platforms = ko.observableArray();
self.message = ko.observable();
self.loadMedias = function (data, event) {
my.loadMedias(data.id);
}
}
What am i missing here?
It looks like this may be a simple fix, where you're possibly using the value binding where you should be using the optionsValue binding:
<select data-bind="options: platforms, optionsText: 'displayName', optionsValue: 'id', optionsCaption: 'Choose...', event: { change: loadMedias }" ></select>
<!-- ^ here -->
However, why not put the logic in the view model, rather than in your view:
my.viewModels.PlatformsViewModel = function () {
var self = this;
self.platforms = ko.observableArray();
self.message = ko.observable();
//new observable to hold selected platform
self.selectedPlatform = ko.observable();
//subscribe to changes in the observable value to trigger the loading
self.selectedPlatform.subscribe(function(newValue) {
my.loadMedias(newValue.id);
});
}
And an updated <select> that will bind the actual platform object selected, rather than just its ID:
<select data-bind="options: platforms, optionsText: 'displayName', value: selectedPlatform, optionsCaption: 'Choose...'" ></select>
Html:
<select name="ddlUsers" id="ddlUsers" class="form-control"
data-bind="options: ViewModel.CashierPage.AvailableCash, optionsText: 'OptionTextInfo', value: ViewModel.CashierPage.CashSelected, optionsCaption: 'Cassa...'"></select>
in js:
public CashSelected: KnockoutObservable();
...
self.CashSelected = ko.observable(null);
self.CashSelected.subscribe(function(valueNewValue){/*your code*/});
I am having a problem not being able to bind my data and then display it using cshtml. I have tried different methods of making observable arrays and I am thinking, my main problem comes from trying to utilize my supposedly "bounded-data"...The following is my cshtml(c#-html) code, and then my js code.
<!--*****Unfinished*****-->
<td>
<label class="element-label">Continuous (Vibratory) Acceleration</label>
<select class="form-control device-family-selector" , data-bind="options: changeAuxFlange.availableVForces, optionsText: 'forceName', value: changeAuxFlange.selectedForces, optionCaption: 'Choose a force...'"></select>
</td>
<td>
<input style="width:50px; text-align:right;" , data-bind="text: changeAuxFlange.selectedForces" />
</td>
</tr>
<tr>
<td>
<label class="element-label">Maximum (Shock) Acceleration</label>
<select class="form-control device-family-selector" , data-bind="options: changeAuxFlange.availableSForces, optionsText: 'forceName', value: changeAuxFlange.selectedForces, optionCaption: 'Choose a force...'"></select>
</td>
<td>
<input style="width:50px; text-align:right;" , data-bind="value: changeAuxFlange.selectedForces" />
</td>
<!--**********-->
view model:
"use strict";
function ViewModel()
{
// it would make more sense with the current setup to make the ViewModel be the Application, but I have set it up like this in case some day it is desired that this tool creates multiple applications in one session
this.application = ko.observable(new Application('New Application', this));
this.requestSearchMode = ko.observable(false);
}
function Application(name, parentViewModel)
{....
this.sections =
{
gForceSection: initGforceSection(this),
pumpSection: initPumpSection(this),
calcLoadsSection: initCalcLoadsSection(this)
}....
}
function initGforceSection(application)
{
var data = ko.observableArray();
var gForceSection = new Section('G-Forces', data, application);
var self = this;
var Force = function (name, value) {
this.forceName = name;
this.forceValue = value;
};
var vibForce = {
availableVForces: ko.observableArray([
{ vForce: "Skid steer loader", value: 4 },
{ vForce: "Trencher (rubber tires)", value: 3 },
{ vForce: "Asphalt paver", value: 2 },
{ vForce: "Windrower", value: 2 },
{ vForce: "Aerial lift", value: 1.5 },
{ vForce: "Turf care vehicle", value: 1.5 },
{ vForce: "Vibratory roller", value: 6 }
]),
selectedForces: ko.observable()
};
var shockForce = {
availableSForces: ko.observableArray([
{ sForce: "Skid steer loader", value: 10 },
{ sForce: "Trencher (rubber tires)", value: 8 },
{ sForce: "Asphalt paver", value: 6 },
{ sForce: "Windrower", value: 5 },
{ sForce: "Aerial lift", value: 4 },
{ sForce: "Turf care vehicle", value: 4 },
{ sForce: "Vibratory roller", value: 10 }
]),
selectedForces: ko.observable()
};
gForceSection.families = ko.observableArray();
productData.getPumpFamilies(function (data) {
gForceSection.families(data);
addPump(application);
});
gForceSection.tbxNumberofPumps = ko.computed(function () { return gForceSection.data().length });
return gForceSection;
}
//CREATE VIEWMODEL
var viewModel = new ViewModel;
ko.applyBindings(viewModel);
/******/
The viewModels is a series of nested objects which makes references quite complicated. I can see you're trying to logically structure the data but it makes it difficult to help. Knockout has a context for binding which starts with the bound viewmodel. You can change the context for an element/section using the with binding.
Otherwise you have to give Knockout a full path, e.g. data-bind="value: app.gforcesection.someitem.someProperty - this can be cause errors if an item in the path is undefined.
I've removed a lot of the structure to make it a working sample to try to help:
http://jsfiddle.net/Quango/3y9qhnv9/
The new viewModel is now a 'flat' object with all the properties on it directly. I wasn't sure why you bound the input boxes to the force so I amended those to bind to the value property of each one. Hope this helps you in the right direction.
I have a form which generates a list options for the user, each option has a check-box, a label and an input field. The input field should only be shown whilst the check-box is ticked. The options are generated through a JSON call.
However, knockout doesn't seem to be doing what I would have expected when using the visible binding. When I check a row, the text box is correctly shown but when I uncheck it, the text box stays shown.
I suspect this is something to-do with the observable "selected" being overridden or something like that but I am stuck for ideas.
Here is a fiddle showing the issue: http://jsfiddle.net/qccQs/2/
Here is the HTML I am using in the fiddle:
<div data-bind="template: { name: 'reason-template', foreach: reasonList }"></div>
<script type="text/html" id="reason-template">
<div>
<input type="checkbox" data-bind="value: selected" />
<span data-bind="text: name"></span>
<input type="text" class="datepicker" data-bind="value: date, visible: selected" />
</div>
</script>
Here is the javascript that I am using in the fiddle:
function ReasonItem(name) {
this.name = ko.observable(name);
this.date = ko.observable(null);
this.selected = ko.observable(false);
};
function MyViewModel() {
var self = this;
self.reasonList = ko.observableArray([ ])
};
var vm = new MyViewModel();
new Request.JSON({
url: '/echo/json/',
data: {
json: JSON.encode({
data: [
{ name: "Reason 1", selected: false, date: null },
{ name: "Reason 2", selected: false, date: null },
{ name: "Reason 3", selected: false, date: null }
]
}),
delay: 0
},
onSuccess: function(response) {
$.each(response.data, function(index, reason) {
vm.reasonList.push(new ReasonItem(reason.name));
});
}
}).send();
ko.applyBindings(vm);
Any ideas on how I can get this to behave like I expected it to?
For inputs of checkbox type you need to use checked instead of value:
<input type="checkbox" data-bind="checked: selected" />
See Knockout Documentation.