I'm attempting to enable / disable an input field.
<input data-bind="disable: chatDisabled" id="send-message" type="textarea" class="input-area" value="">
And my knockoutJS
function MessagesViewModel() {
var self = this;
var socket = io.connect('http://127.0.0.1:4000');
self.messages = ko.observableArray([]);
self.chatSend = ko.observable();
self.questionChoice = ko.observable();
self.chatDisabled = ko.observable(false);
socket.on('receiveMessages', function(data) {
self.messages(data.messages);
var last = data.messages[data.messages.length-1];
self.chatDisabled = last.enforce || false;
scrollToBottom();
});
}
ko.applyBindings(new MessagesViewModel());
I've managed to get other parts working such as having a list of messages on the screen populate when the array is updated. However for the life of me I cannot get the input to toggle between disabled / enabled when it is changed within socket.on(
self.messages( updates corrected so why does self.chatDisabled not? (To be clear the variable JS side is updated however it the data-bind is not.
This should do the trick:
self.chatDisabled(last.enforce || false);
You were assigning a new value to your property instead of updating the observable value.
Related
I need a input mask that doesn't sync with knockoutJS observable variables.
Ex: if the user input is 50000000, the UI should show the masked value (500,000.00) but in the ViewModel (knockoutJS) variable it should save like 500000.00
I tried with 3 following jQuery plugins
github.com/RobinHerbots/Inputmask
github.com/igorescobar/jQuery-Mask-Plugin
digitalbush.com/projects/masked-input-plugin/
Even tried with the knockoutJS integration of RobinHerbots input mask plugin.
All those plugins were working perfectly but the problem is,
When user input the value 50000000, it shows as 500,000.00 but it has been saved to the knockoutJS observable variable the same value (500,000.00).
Do anyone facing a problem like this?
Update:
I have modified some code in RobinHerbots input mask (knockout integration) and now I'm removing all commas from the input string when the value is updating.
[JAVASCRIPT]
ko.bindingHandlers.inputmask = {
init: function (element, valueAccessor, allBindingsAccessor) {
var mask = valueAccessor();
var observable = mask.value;
if (ko.isObservable(observable)) {
$(element).on('focusout change', function () {
if ($(element).inputmask('isComplete')) {
observable($(element).val());
} else {
observable(null);
}
});
}
$(element).inputmask(mask);
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var mask = valueAccessor();
var observable = mask.value;
if (ko.isObservable(observable)) {
var valuetoWrite = observable();
$(element).val(valuetoWrite);
var value = valuetoWrite.toString().replace(/,/g ,'');
observable(value);
}
}
[HTML]
<input type="text" data-bind="inputmask: { value:ItemPrice , mask:'999,999.99'}" />
Now it works as I needed. Anyone knows how to get the currency (It doesn't work the way we used to do with jQuery) mask in the RobinHerbots input mask in knockout version?
You can create a knockout extension for masking with markup like
<input type="text" data-bind="customMasking:{}"/>
ko.bindingHandlers.customMasking={
init:function(element,valueaccessor,allbindingaccessor){
var el =$(element);
var options=allbindingaccessor();
el.inputmask({
//provide your options
})
}
}
I have also faced similar difficulties in using the masks. I prefer to keep a computed variable that cleans up the input value. See the snippet below:
var model = function() {
var self = this;
self.number = ko.observable('0');
self.floatNumber = ko.computed(function() {
return self.number().split(',').join('');
});
}
ko.applyBindings(new model());
$("#test").inputmask({ alias : "currency", prefix: '' });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.inputmask/3.2.6/jquery.inputmask.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input type="text" id="test" data-bind="textInput: number" />
<br />
Cleaned Number:
<span data-bind="text: floatNumber" ></span>
I want to trigger a function when user select other value from a combobox <select>
HTML
<div class="wrapper wrapper-content" id="appGradeHorariaCompleta">
<select class="form-control m-b" data-bind="options: Curriculos,optionsText:'Text',optionsValue:'Value',optionsCaption:'Selecione', value: CurriculoSelected, event:{ change: $parent.CurriculosChanged}"></select>
</div>
JS
function PainelViewModel() {
var self = this;
self.Curriculos = ko.observableArray([]);
self.CurriculosChanged = (function (curriculo) {
console.debug(curriculo);
});
}
function CurriculoViewModel() {
var self = this;
self.Id = ko.observable(0);
self.Value = ko.observable('');
self.Selected = ko.observable(0);
}
...GET DATA...
...
..
.
$(data.CurriculoComboBox).each(function (index, item) {
var model = new CurriculoViewModel();
model.myvalues = item.myValues;
painelVM.Curriculos().push(model);
});
ko.applyBindings(painelVM, document.getElementById("appGradeHorariaCompleta"));
What I want is when value change in the combobox I want to get this parameter to bind another function.
But in the way I've done, I got an error:
Unable to process binding "event: function (){return { change:$parent.HabilitacoesCursosChanged} }
First thing first your view model is real messed up. You may need to make changes with variable names used in data-bind to match those in viewmodel. I hope I am getting you right. What you want is to trigger a method when value of combobox changes. For that there is an easier way of using subscribe on an observable(your combobox value). So, whenever value of your combobox changes, subscribe function is triggered. The functionality that you want is passed inside the subscribe function as a function body.
HTML:
<div class="wrapper wrapper-content" id="appGradeHorariaCompleta">
<select class="form-control m-b" data-bind="options:Curriculos, optionsText:'Text',optionsValue:'Value',optionsCaption:'Selectone', value: CurriculoSelected"></select>
</div>
Javascript:
function CurriculoViewModel() {
var self = this;
self.Curriculos = ko.observableArray([]);
self.CurriculoSelected = ko.observable('');
self.CurriculoSelected.subscribe(function(value) {
// Your change functionality goes here combobox.
});
}
References check out the subscribe:
Knockout observables subscribe
Knockout options binding
Subscribe not work, so I still use event: {change: $parent.CurriculosChanged}
So, using ideia from siddhearth to get I get the value selected from my var, I can get the new value changing the $parent for $root
HTML
<select class="form-control m-b" data-bind="options: Curriculos,optionsText:'Text',optionsValue:'Value',optionsCaption:'Selecione', value: CurriculoSelected, event:{ change: $root.CurriculosChanged}"></select>
JS
function PainelViewModel() {
var self = this;
self.Curriculos = ko.observableArray([]);
self.CurriculoSelected = ko.observable(0);
self.CurriculosChanged = function (c) {
console.debug(c.CurriculoSelected);
};
}
Check binding context
This question already has an answer here:
Knockout.js bound input value not updated when I use jquery .val('xyz')
(1 answer)
Closed 6 years ago.
self.totalHours = ko.pureComputed(function() {
var start=self.num1;
var end=self.num2;
return start+end;
});
<input type="text" data-bind="textInput: start">
<input type="text" data-bind="textInput: end">
<input type="text" data-bind='text: totalHours()'>
The above first is part of my viewmodel and the second is part of my model. num1,num2 are observables. Every time I change manually the value inside the above first two inputs the third input is updated immediately; however, when the values change by code, knockout does not listen to the changes and total is not updated. How may I oblige knockout to listen to the changes provoked by code?
Quite some stuff you can fix and improve here:
A computed value will re-evaluate when an observable it uses in its method changes: self.num1 and/or self.num2 need to be observable and evaluated using ()
If you want to bind an <input>'s value, you have to use either the value or textInput data-bind; the text bind will not work.
If you want to write to a computed, you'll have to specify a write method. You'll have to tell knockout how to update the computed's dependencies to make sure all values add up. (e.g.: setting totalHours could set num1 to totalHours and num2 to 0)
You've bound to start and end, while your viewmodel properties are named num1 and num2.
When using value or textInput, user input will be returned as a string. You'll need to parse the strings to numbers if you want to use them in any math.
Now that all code should be working correctly, you can update your viewmodel's values via the inputs, or via code:
var ViewModel = function() {
var self = this;
self.num1 = ko.observable(0);
self.num2 = ko.observable(0);
self.totalHours = ko.pureComputed(function() {
var start = parseFloat(self.num1());
var end = parseFloat(self.num2());
return start + end;
});
};
var vm = new ViewModel();
ko.applyBindings(vm);
// Updating your values from code:
vm.num1(1);
vm.num2(2);
// Whenever the values need to be updated via js,
// you should change the source values, _not_ the
// <input>'s values. Worst case scenario, you'll
// have to do something like this:
var updateNum1ViaDOM = function() {
ko.dataFor(document.querySelector("input")).num1(5);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="text" data-bind="textInput: num1">
<input type="text" data-bind="textInput: num2">
<span data-bind='text: totalHours'></span>
Note: it's probably better to use an extender to force num1 and num2 to be numeric: Live Example 1: Forcing input to be numeric
Not sure if it is a copy paste problem but the the code you posted will not work as intended. I've updated the example, when changing an observable value it must be passed as parameter so as not to overwrite the knockout observable
self.start = ko.observable();
self.end = ko.observable();
self.totalHours = ko.computed(function() {
return self.start() + self.end();
});
<input type="text" data-bind="textInput: start">
<input type="text" data-bind="textInput: end">
<input type="text" data-bind='text: totalHours()'>
//Then when changing the value by code
var newValue = 42;
model.start(newValue); //assuming you are making the change outside your viewmodel
*Just noticed this code will throw an exception when you edit the input bound to totalHours as it does not have a write handler defined. This is a separate issue though.
I have model in a page that is bound to several controls. Based on some condition some of these controls will be visible or invisible. And on the final submit I should only validate those which are visible.
The following is a sample code to explain my requirement
<script src="knockout-3.4.0.js" type="text/javascript"></script>
<input type="checkbox" data-bind="checked:requireAge" >Age Required</input><br />
Name : <input data-bind="value:Name" /><br />
<div data-bind="visible:requireAge">
Age: <input data-bind="value:Age,visible:requireAge" />
</div>
<button type="button" onclick="validateModel();">Validate</button>
<script type="text/javascript">
var viewModel = { Name: ko.observable(), Age: ko.observable(),requireAge:ko.observable(false) };
ko.applyBindings(viewModel);
function validateModel() {
//validate visible properties and throw a common message that all visible fields should be filled
}
</script>
My suggestion is to use the knockout-validation library (you made no mention of it in your question so I assume you're not using it already) It ties in seamlessly with knockout and makes validation far more convenient. I've used it extensively over the past year and its make my life a whole lot easier. No need to create computeds to keep track of whether an observable contains a valid value or not. You can find the knockout-validation library on github.
In your case you can simply do the following:
var viewModel = function(){
var self = this;
self.name = ko.observable();
self.requireAge = ko.observable(false);
self.age = ko.observable().extend({
required: {
onlyIf: function() { return self.requireAge(); }
}
});
};
Validation error messages are inserted automatically below the element the observable is bound to. You can also create your own validation rules but there are many that work straight out the box including the one demonstrated above. You can even use some data attributes for some rules. This is probably the best way to go about validation in conjunction with knockout.
Based on some condition some of these controls will be visible or invisible.
It would be better if these conditions are contained in the model. And validation method too.
See snippet:
var viewModel = function() {
this.Name = ko.observable("");
this.Age = ko.observable("");
this.requireAge = ko.observable(false);
this.isValid = ko.computed(function() {
if (ko.unwrap(this.Name).length === 0) return false;
if (ko.unwrap(this.requireAge) &&
ko.unwrap(this.Age).length === 0) return false;
return true;
}, this);
};
window.onload = function() {
ko.applyBindings(new viewModel());
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="checkbox" data-bind="checked:requireAge" >Age Required</input><br />
Name : <input data-bind="value:Name" /><br />
<div data-bind="visible:requireAge">
Age: <input data-bind="value:Age,visible:requireAge" />
</div>
<div>is valid: <span data-bind="text: isValid"></span></div>
I am using Knockout.js to develop a calculator. I am facing a situation that I don't know how to handle.
In the below example, everything works fine when the user enters a product and value and the values are saved in the DB. But when the user comes to edit this page, my requirement is to show all the values the user entered along with the total. But when the user changes something in the product or quantity, the total should change as expected.
We now store the total in DB and total could be changed by some admin users.In this case,is there a way we can override the computed value when the user goes to the edit page but when the user changes product or quantity,then the compute should happen with the latest values from product and quantity.
Help is appreciated.
var TsFoundationDeviceModel = function(product,qty) {
var self = this;
self.product = ko.observable();
self.quantity= ko.observable();
self.computedExample = ko.computed(function() {
return self.product() * self.quantity() ;
});}
My HTML code looks like
<input name="product" data-bind="value:product">
<input name="value" data-bind="value:value">
<input name="total" data-bind="value:computedExample"/>
You have to bind the view to the screen. Check out this fiddle and give it
var TsFoundationDeviceModel = function(product,qty) {
var self = this;
self.product = ko.observable(product);
self.quantity= ko.observable(qty);
self.computedExample = ko.computed(function() {
return self.product() * self.quantity() ;
});}
ko.applyBindings(new TsFoundationDeviceModel(2,3));
http://jsfiddle.net/Z6VPV/5/
When you reference observables within your computed you need to treat them like functions so instead of return self.product * self.quantity ; you would use return self.product() * self.quantity();
Fiddle: http://jsfiddle.net/SAV9A/