Convert Javascript onkeypress to knockoutjs to call on enter - javascript

I am trying to do everthing I can in KnockoutJS however I am having a hard time getting this to convert to knockoutjs.
I have an input box that upon enter press I need to call addInputName(). This is kind of the old school way I think to do it. Is there a way to do this all in knockout?
<input id="inputName" onkeypress="addInputName(this, event);" />
<input id="addInputName" type="button" data-bind="event: { click: addInputName }" value="Add" />
self.addInputName = function (inputElement, event) {
if (event.keyCode == 13) {
$('#addInputName').click();
}
};

// View
<input id="inputName" data-bind="value: name, enterKey: addInputName" />
<input id="addInputName" type="button" data-bind="click: addInputName" value="Add" />
// ViewModel
function ViewModel() {
var self = this;
self.name = ko.observable();
self.names = ko.observableArray();
self.addInputName = function () {
self.names.push(self.name());
self.name("");
};
}
// Custom Binding
ko.bindingHandlers.enterKey = {
init: function (element, valueAccessor, allBindings, data, context) {
var wrapper = function (data, event) {
if (event.keyCode === 13) {
valueAccessor().call(this, data, event);
}
};
ko.applyBindingsToNode(element, { event: { keyup: wrapper } }, context);
}
};
Custom Bindings #20:05
Look into Custom Bindings. It's an invaluable tool to help get UI logic out of your ViewModel's business logic.

Why not just wrap the inputs inside a form? Then you can change your HTML to
<form data-bind="submit: addInputName">
<input id="inputName" type="text" data-bind="value: name" />
<input id="addInputName" type="submit" value="Submit" />
</form>
Then your KO viewmodel looks something like
var ViewModel = function()
{
var self = this;
self.name = ko.observable();
self.addInputName = function() {
// do stuff
}
}

Related

Mapping not working in knockout with the button click

Mapping not working in knockout with the button click,
I have used mapping in knockout, while changing input text value when clicking button not changed properly.
Need to change value for name input text after click load user data button
Here my code,
<div class='sample'>
<p>Load: <input type="button" value="Load User Data" data-bind="click: loadUserData" /></p>
<p>Name: <input data-bind='value: firstName' /></p>
<p>Save: <input type="button" value="Save User Data" data-bind="click: saveUserData" /></p>
</div>
<script>
$(document).ready(function () {
var viewModel = {};
viewModel.firstName = 'Knockout JS';
viewModel.loadUserData = function () {
$.getJSON("/data.json", function (data) {
// update the data in existing ViewModel.
viewModel.firstName = data.name;
ko.mapping.fromJS(data, viewModel);
});
};
viewModel.saveUserData = function () {
// Convert the viewModel into JSON.
var data_to_send = { userData: ko.toJSON(viewModel) };
// Send that JOSN data to server.
$.post("WebService.asmx/updateData", data_to_send, function (data) {
alert("Your data has been posted to the server!");
});
};
ko.applyBindings(viewModel);
});
</script>
Did i anything wrong?
In order to make it update the UI, you need to make the firstName observable.
Then when you want to modify an observable value, you need to treat that as a function and pass the new value as an argument like this firstName('newValue')
See the link here to get more information and a sample below:
var masterVM = (function () {
var self = this;
self.firstName = ko.observable("Knockout JS");
self.loadUserData = function() {
var currentName = self.firstName();
self.firstName(currentName + "Updated");
}
})();
ko.applyBindings(masterVM);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<p>Load: <input type="button" value="Load User Data" data-bind="click: loadUserData" /></p>
<p>Name: <input data-bind='value: firstName' /></p>

How to applyBindings and keep input values with Knockout JS?

I'm building a HTML/KnockoutJS application. My webserver returns a form with input fields with information. When I new up my model and do an ko.applyBindings, naturally the input values are overwritten by the model.
Is there a way to do an ko.applyBindings in which the model is automatically loaded with the data of the input fields?
Example: https://jsfiddle.net/KeesCBakker/p7ygq5y2/1/
HTML:
Title: <input data-bind="textInput: title" value="MyTitle" placeholder="Nothing here!" /><br/>
Text: <input data-bind="textInput: text" value="MyText" placeholder="Nothing here!" /><br/>
<button id="bind">Bind!</button>
JS:
ko.bindingHandlers.initFromInput = {
init: function(element, valueAccessor) {
valueAccessor()(element.value);
}
};
function Model() {
this.title = ko.observable();
this.text = ko.observable();
}
document.getElementById('bind').onclick = function() {
var model = new Model();
ko.applyBindings(model);
};
You could use a custom binding, that tells Knockout to use the input values as default, like this:
ko.bindingHandlers.initFromInput = {
init: function(element, valueAccessor) {
valueAccessor()(element.value);
}
};
Here's a jsfiddle: http://jsfiddle.net/kv3zras3/3/
EDIT:
With the new binding, your data-binds should look something like this:
<input data-bind="initFromInput: title, value: title" value="MyTitle" placeholder="Nothing here!" />
<input data-bind="initFromInput: text, value:text" value="MyText" placeholder="Nothing here!" />
EDIT:
There's an abit nicer way of achieving this, if you make like binding look like this:
var origValueInput = ko.bindingHandlers.value.init;
ko.bindingHandlers.value.init = function(element, valueAccessor, allBindings) {
if (allBindings.has('initValueFromInput')) {
valueAccessor()(element.value);
}
origValueInput.apply(this, arguments);
};
You can write your data-binds like this:
<input value="MyTitle" data-bind="initValueFromInput, value: title"/>
<input value="MyText" data-bind="initValueFromInput, value: text"/>
Here's a fiddle: https://jsfiddle.net/yy51kok5/
I've ended up improving the answer from clean_coding. Add the following anonymous method to a script after loading KnockoutJS. It will reroute both textInput and value handlers.
(function () {
var z = ko.bindingHandlers.textInput.init;
ko.bindingHandlers.textInput.init = function (element, valueAccessor, allBindings) {
if (allBindings.has('initWithElementValue')) {
valueAccessor()(element.value);
}
z.apply(this, arguments);
};
var y = ko.bindingHandlers.value.init;
ko.bindingHandlers.value.init = function (element, valueAccessor, allBindings) {
if (allBindings.has('initWithElementValue')) {
valueAccessor()(element.value);
}
y.apply(this, arguments);
};
}())
It can be used, by specifying it after the textInput or value declaration:
<input type="text" data-bind="textInput: title, initWithElementValue" />
Ended up creating a plugin for Knockout. Added it to GitHub as well.
<script type="text/javascript" src="https://cdn.rawgit.com/KeesCBakker/KnockoutAutomaticFormValueBinding/master/knockout-automatic-form-value-binding-1.0.min.js"></script>
Include the plugin
Set ko.automaticFormValueBinding = true;
Bind ko.applyBindings({yourmodel});
More info at Git: https://github.com/KeesCBakker/KnockoutAutomaticFormValueBinding

knockoutjs remove click binding

I use knockoutjs and have a button (id='enter') with a click binding:
<input id="enter" type="button" value="Enter" data-bind="click: function(data,event) { console.log('do something'); console.log('do something more');}"/>
If I click the button "do something" and "do something more" is logged on the console.
How can I update the click binding, e.g. set a now binding? So that the click
of the button invokes another actions?
This doesnt work:
var enterButton = document.getElementById('enter');
var newClickBind = "click: function(data,event) { console.log('muh'); }";
enterButton.setAttribute('data-bind',newClickBind);
Thanks and regards
One thing you can do is make an observable that holds a function, which you can change based on the state of things in your form. The click would get bound to an invocation of that observable.
function thing1() {
vm.output('thing 1');
}
function thing2() {
vm.output('thing 2');
}
function thing3() {
vm.output('thing 3');
}
var vm = {
dynamicFunction: ko.observable(thing1),
changeIt: function() {
console.debug("Whatever");
if (vm.dynamicFunction() == thing3) {
vm.dynamicFunction(thing2);
} else {
vm.dynamicFunction(thing3);
}
},
output: ko.observable('')
};
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="button" value="Run" data-bind="click: dynamicFunction()" />
<input type="button" value="Switch" data-bind="click: changeIt" />
<div data-bind="text:output"></div>
you should put all the logic of the click binding inside the viewModel. below is the VM function equivalent of your inline click binding
// Here's my data model
var ViewModel = function() {
this.clickFunction = function(data, event) {
console.log('do something');
console.log('do something else');
console.log(data, event);
};
};
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input id="enter" type="button" value="Enter" data-bind="click: function() { clickFunction($data, event); }"/>
EDIT: changing the click event based on other events
// Here's my data model
var ViewModel = function() {
this.action = ko.observable('doNothing');
this.setDoSomething = function() {
this.action('doSomething');
};
this.setDoSomethingElse = function() {
this.action('doSomethingElse');
};
this.clickFunction = function() {
if (this.action() == 'doSomething') {
doSomething();
}
else if (this.action() == 'doSomethingElse') {
doSomethingElse();
}
else {
this.action('doNothing');
}
};
function doSomething() {
console.log('do something');
}
function doSomethingElse() {
console.log('do something else');
}
};
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<button data-bind="click: setDoSomething">Make it Do something</button><br/>
<button data-bind="click: setDoSomethingElse">Make it Do something else</button><br/>
<br/><br/>
<input id="enter" type="button" value="Enter" data-bind="click: clickFunction"/><br/>
clicking enter will <div data-bind="text: action"></div>
You can use a ko.computed that returns to the click bind the function that needs to be executed, see the example:
function AppViewModel() {
this.choosenAction = ko.observable("1");
var action1 = function(){
console.log("Action 1 Done!!!")
};
var action2 = function(){
console.log("Action 2 Done!!!")
};
this.onClickTest = ko.computed(function(){
if(+this.choosenAction()===1)
return action1;
else
return action2;
},this);
}
// Activates knockout.js
ko.applyBindings(new AppViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<label for="act1"> Action 1 </label>
<input type="radio" id="act1" name="action" value="1" data-bind="checked: choosenAction"/>
<label for="act2"> Action 2 </label>
<input type="radio" id="act2" name="action" value="2" data-bind="checked: choosenAction"/>
</br>
</br>
<button data-bind="click: onClickTest()">Teste</button>
look that the function to be executed depends on the action choosed.

Updating value when overriding enter press

I have page when I have input and a button.
<div>
<div class="input-group">
<span class="input-group-addon">Enter test</span>
<input type="Text" class="form-control" data-bind="value:Test, event: { keypress: searchKeyboardCmd}" required />
</div>
</div>
<button data-bind=' event:{click:foo}' class="btn btn-default">Submit</button>
and my code:
var ViewModel = function () {
var self = this;
self.Test = ko.observable();
self.data = ko.observableArray([]);
self.DeviceId = ko.observable();
self.number = ko.observable(1);
self.MeUser = ko.observable(true);
self.searchKeyboardCmd = function (data, event) {
if (event.keyCode == 13)
alert("Znalazlem enter " + ko.toJSON(self));
return true;
};
self.foo = function () {
alert("foo");
}
};
ko.applyBindings(new ViewModel());
});
And I have problems with my code. I catch enter with this code:
self.searchKeyboardCmd = function (data, event) {
if (event.keyCode == 13)
alert("Znalazlem enter " + ko.toJSON(self));
return true;
};
It's catches perfectly but binded object is updated after calling alert. So in the first enter I null in value Test. After second enter I have first value and so on. Can anyone suggest me how to modify this code?
The problem is that the event is executed before the blur event (which is when the value is updated. You can make sure the update gets updated after every keystroke by adding valueupdate: 'afterkeydown' to the input:
<div>
<div class="input-group">
<span class="input-group-addon">Enter test</span>
<input type="Text" class="form-control"
data-bind="valueUpdate: 'afterkeydown', value:Test, event: { keypress: searchKeyboardCmd}" required />
</div>
</div>
<button data-bind=' event:{click:foo}' class="btn btn-default">Submit</button>

KnockoutJS setting focus after adding to array/collection

I have viewmodel with an array of diagnosis codes. In my html I have a button data-bound to a click that adds a blank diagnosis code to the array. This all works.
What I cant figure out, is how to set focus to the dynamically added textbox when a code is added. What can I add :
<h3>Diagnosis Codes<input type="button" value="Add" data-bind="click:AddDiagnosisCode"/></h3>
<div data-bind="foreach:DiagnosisCodes">
<div><input type="text" data-bind="value:$data"/>
</div>
</div>
<script type="text/javascript">
function AddDiagnosisCode(item)
{
item.DiagnosisCodes.push("");
}
var vm = {
"DiagnosisCodes": ["2345","6789"]
};
var viewModel = ko.mapping.fromJS(vm);
ko.applyBindings(viewModel);
</script>
Use the built-in binding hasFocus and set it to true
<input type="text" data-bind="value:$data, hasFocus: true">
See http://jsfiddle.net/eT3Y8/
It can be done with a custom binding. The harder part in this approach is to not focus on the boxes of the elements that are initially in the list. That's why I needed an extra isNew property, which is false for the already existing elements. I also used jquery to focus :) Fiddle: http://jsfiddle.net/hv9Dx/1/
html:
<h3>Diagnosis Codes<input type="button" value="Add" data-bind="click:AddDiagnosisCode"/></h3>
<div data-bind="foreach:DiagnosisCodes">
<div><input type="text" data-bind="value:value, focusOnCreate:isNew()"/>
</div>
</div>
js:
var Record = function(value, isNew){
var self = this;
self.value = ko.observable(value);
self.isNew = ko.observable(isNew || false);
}
var VM = function() {
var self = this;
self.DiagnosisCodes = ko.observableArray([
new Record("2345"),
new Record("6789")]);
self.enableFocus = ko.observable(true);
self.AddDiagnosisCode = function(){
self.DiagnosisCodes.push(new Record("", true));
}
}
ko.bindingHandlers.focusOnCreate = {
init:function(element, valueAccessor, allBindings, viewModel, bindingContext) {
if(valueAccessor()){
$(element).focus();
}
}
}
ko.applyBindings(new VM());

Categories

Resources