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.
Related
I have a problem with my js script because for both button will open te same site 1. I don't know why?
Could somebody help me to resolve this problem?
$('#trackAndTraceForm').submit(function(event) {
var val = $('input[name="numer"]', this).val();
elementClicked = $(event.target);
var typeBtn = elementClicked.attr('name');
if (typeBtn == 'spr') {
if (val.substring(0, 1) != '0') {
//console.log('nie zero');
var action = 'http://92.43.115.24:8080/ApolloWebBooking/WebBooking/StatusyPrzesylki.aspx';
$(this).attr('action', action);
} else {
var action = 'http://apollo.loxx.pl:8080/ApolloWebBooking/WebBooking/StatusyPrzesylki.aspx';
$(this).attr('action', action);
}
} else if (typeBtn == 'pod') {
var action = 'http://www.loxx.pl/loxx_it/loxxwarpod.php';
$(this).attr('action', action);
} else {
//do nothing;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="trackAndTraceForm" target="_blank" class="form-horizontal" enctype="application/x-www-form-urlencoded" method="get" action="http://apollo.loxx.pl:8080/ApolloWebBooking/WebBooking/StatusyPrzesylki.aspx">
<span>Track and Trace:</span>
<input type="text" value="" name="numer" placeholder="Numer listu przewozowego" />
<input type="submit" name="spr" class="btn btn-sm btn-primary" value="Sprawdz" />
<input type="submit" name="pod" class="btn btn-sm btn-primary" value="POD" />
</form>
If I click POD button action is the same like for Sprawdz with url
http://apollo.loxx.pl:8080/ApolloWebBooking/WebBooking/StatusyPrzesylki.aspx?numer=0317037128&pod=POD
You need to prevent the original event from triggering the default submit action. You do that by calling event.preventDefault();.
Here's what your code needs to look like:
$('#trackAndTraceForm').submit(function(event) {
event.preventDefault(); // <-- the important bit
// ...
if (typeBtn == 'spr') {
// ...
} else if (typeBtn == 'pod') {
// ...
}
});
Looks like you can't change the action attribute of the event after the submit event has been called.
What you need to do is to add event listeners to each of your buttons, change the action attribute and then submit the form:
function changeFormAction(newAction) {
$('#trackAndTraceForm').attr('action', newAction);
}
$('input[name="spr"]')
.click(function(e) {
e.preventDefault();
var value = $('input[name="numer"]').val();
var newAction = value.startsWith('0') ?
'http://apollo.loxx.pl:8080/ApolloWebBooking/WebBooking/StatusyPrzesylki.aspx' : 'http://92.43.115.24:8080/ApolloWebBooking/WebBooking/StatusyPrzesylki.aspx';
changeFormAction(newAction);
$('#trackAndTraceForm').submit();
}
$('input[name="pod"]')
.click(function(e) {
e.preventDefault();
changeFormAction('http://www.loxx.pl/loxx_it/loxxwarpod.php');
$('#trackAndTraceForm').submit();
}
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>
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>
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
}
}
I would like to show error message on user button click (in case user open page and click on directly just on button).
But Visible state workin just if user edit fields
How to fire methods to change visible state ?
<body>
<input type="text" data-bind="value: can" id="txtcan" />
<span ID="lblCANerror" data-bind="visible:(viewModel.can()=='')" class="error">Mesasage 1</span>
<input type="text" data-bind="value: login" id="txtusername" />
<span ID="lblUsernameError" data-bind="visible:(viewModel.login()=='')" class="error">Mesasage 2</span>
<input type="password" data-bind="value: password" name="txtpassword" />
<span ID="lblPasswordError" data-bind="visible:(viewModel.password()=='')" class="error">Mesasage 3</span>
<button ID="lnkLogin" data-bind="click: ClickBtn"> Click</button>
</body>
<script type='text/javascript'>
var ViewModel = function () {
this.can = ko.observable();
this.login = ko.observable();
this.password = ko.observable();
this.isValidForm = ko.computed(function () {
return ($.trim(this.can) != "") && ($.trim(this.login) != "") && ($.trim(this.password) != "");
}, this);
this.ClickBtn = function(data, e)
{
if (!this.isValidForm())
{
e.stopImmediatePropagation();
};
};
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
</script>
<style type='text/css'>
.error
{
color: #FF0000;
}
</style>
I don't want write to write code for change span visible state manually (like if () then span.show) is it possible to use just knockoutjs FW ?
I have tried subscribe to event with JQuery but result is the same.
$().ready(function () {
$("#lnkLogin").click(function (event) {
if (!viewModel.isValidForm()) {
event.preventDefault();
};
})
});
Thanks.
Remove user defined error span it is not needed.
option 1 (recommended)
1.) import ko validation js.
2.)extend validation
this.can = ko.observable().extend({required:true});
3.)set initial show validation error msg == false
4.) set value == true to show error
Check this fiddle how to show validation error msg when button click
Option2
1.)Add another observable
this.showError = ko.observable(false);
2.)modify condition
data-bind="visible:(can()=='' && showError())"
3.)Changes in click
$().ready(function () {
$("#lnkLogin").click(function (event) {
//check contions here
if(!true){
viewModel.showError(true); // to show error msg
}
if (!viewModel.isValidForm()) {
event.preventDefault();
};
})
});