61

How to call a function using knockout.js when enter key is pressed.. here is my code below.

ko.bindingHandlers.enterkey = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    var inputSelector = 'input,textarea,select';
    $(document).on('keypress', inputSelector, function (e) {
        var allBindings = allBindingsAccessor();
        $(element).on('keypress', 'input, textarea, select', function (e) {
            var keyCode = e.which || e.keyCode;
            if (keyCode !== 13) {
                alert('a');
                return true;
            }

            var target = e.target;
            target.blur();

            allBindings.enterkey.call(viewModel, viewModel, target, element);
            alert('b');
            return false;
        });
    });
}
};
ko.applyBindings(viewModel);

HTML

<input type="text" data-bind="value:sendMessageText, enterkey: sendMessage" /> 

ViewModel

function contactsModel(){
    var self = this;
    self.jid=ko.observable();
    self.userName=ko.observable();
    self.sendMsgText=ko.observable();
    self.sendMessage = function(){
        if(self.sendMessageText() == '' )
            alert("Enter something in input field");
        else{
            var message = {
                to : self.userName(),
                message : self.sendMsgText()
            }
            self.sentMessages.push(message);
            sendMessage(message);
        }

     }
 }

Any idea's about what is wrong here or suggestions for better approach.

Nisarg Shah
  • 14,151
  • 6
  • 34
  • 55
Dave
  • 4,376
  • 3
  • 24
  • 37
  • Can you post the code for your viewModel? Looking at the knockout binding, it is expecting to find a method called sendMessage on viewModel. Your jQuery code to bind to the keypress event may be conflicting with this. – DaveRead Apr 15 '14 at 15:19
  • This question may offer a solution to your issue: http://stackoverflow.com/questions/4386311/how-can-i-get-knockout-js-to-data-bind-on-keypress-instead-of-lost-focus – DaveRead Apr 15 '14 at 15:20
  • @DaveRead i have added viewmodel in question now... pls check.. thanks – Dave Apr 15 '14 at 15:30
  • @DaveRead yes i referred to link u provided and similar related links also.. it was of no help in my case becoz it seems there's something i am missing here.. so decided to post a new question. – Dave Apr 15 '14 at 15:31

5 Answers5

103

No need for a custom binding, just use knockout's keypress event(Knockout docs):

<input type="text"
       data-bind="textInput : keyword, 
                  event: {keypress: onEnter}" >
</input>

And your function:

that.onEnter = function(d,e){
    e.keyCode === 13 && that.search();  
    return true;
};

JSFiddle example

EDIT: New binding from knockout(3.2.0) : textInput - obviates the need to have a valueUpdate binding.

DaafVader
  • 1,735
  • 1
  • 14
  • 14
67

When you create your own knockout bindingHandler, it is used in the same way as the other bindingHanlders eg: data-bind="text: myvalue"

so your HTML will need to look something like this

<input type="text" data-bind="value:sendMessageText, valueUpdate: 'afterkeydown', enterkey: sendMessage" />

An important binding to add is the valueUpdate: 'afterkeydown' binding. Without this binding when a user types text in the input and hits enter the onblur event is not raised prior to enterkey binding. This results in the observable returning an unexpected value and not the current text if the input's value is accessed in an action invoked by enterKey.

Another Look at Custom Bindings for KnockoutJS

EDIT
This is what I have used previously on other projects. JsFiddle Demo

ko.bindingHandlers.enterkey = {
    init: function (element, valueAccessor, allBindings, viewModel) {
        var callback = valueAccessor();
        $(element).keypress(function (event) {
            var keyCode = (event.which ? event.which : event.keyCode);
            if (keyCode === 13) {
                callback.call(viewModel);
                return false;
            }
            return true;
        });
    }
};
Michael Best
  • 16,623
  • 1
  • 37
  • 70
Nathan Fisher
  • 7,961
  • 3
  • 47
  • 68
  • you are correct.. I tried this.. But didn't worked. Using jquery keypress event for now.. If any other better solution you have using knockout I .. Welcome – Dave Apr 16 '14 at 03:27
  • Updated question with respect to your answer.problem still persist – Dave Apr 16 '14 at 04:00
  • how so? did you check out the jsFiddle Demo? – Nathan Fisher Apr 16 '14 at 04:11
  • 6
    Added information for `valueUpdate: 'afterkeydown'` to ensure expected behavior – Chris Marisic Nov 12 '14 at 20:37
  • 2
    The problem is, in this answer, the binding is named `enterkey` but inside the init it's looking for `executeOnEnter`. line 7 should be `allBindings.enterkey.call()` instead of `allBindings.executeOnEnter.call()` – FirstVertex Feb 02 '15 at 17:07
  • Thanks @HDog. Code was originally executeOnEnter for the binding name. I have updated it to be consistent. – Nathan Fisher Feb 02 '15 at 21:46
  • i had to add `valueUpdate` handler as `data-bind="value: organisationName, valueUpdate: 'input', executeOnEnter:initialize" ` – Rahmathullah M Mar 23 '15 at 10:39
  • 2
    Add `element.blur();` just before `allBindings.enterkey.call(viewModel);` call and that way your not backed into the corner of having to specify a `valueUpdate`. Adding `valueUpdate` makes a lots of applications overly chatty if its talking to the back-end via ajax. – TugboatCaptain Mar 28 '15 at 16:55
12

This worked for me, thanks to @DaafVader for most of it.

in view

<input data-bind="value: searchText, valueUpdate: 'input', event: { keyup: searchKeyUp }" />

in viewmodel

var searchKeyUp = function (d, e) {
    if (e.keyCode == 13) {
        search();
    }
}
jacobsgriffith
  • 1,448
  • 13
  • 18
4

Use the submit binding (http://knockoutjs.com/documentation/submit-binding.html) on the form around your input, that's what it's made for.

Example from the Knockout docs:

<form data-bind="submit: doSomething">
    ... form contents like inputs go here ...
    <button type="submit">Submit</button>
</form>

<script type="text/javascript">
    var viewModel = {
        doSomething : function(formElement) {
            // ... now do something
        }
    };
</script>

It also automatically handles your button if there is one.

Mafii
  • 7,227
  • 1
  • 35
  • 55
3

And this worked for me, thanks to @DaafVader.

in view:

<input id="myInput" type="text" 
      data-bind="value : keyword, valueUpdate: 'afterkeydown'">
</input>

in javascript:

$("#myInput").keyup(function (event) {
        if (event.keyCode == 13) {
            search();
        }
});

To put keyup event in your jquery event instead of knockout event reduced the complexity of the knockout viewmodel.

Luo Jiong Hui
  • 5,527
  • 2
  • 23
  • 18