6

So I have an inputText that has its value hook to myBean.text, I want that if I click enter/return key, the inputText will invoke a method inside myBean to do something. Can any one help me?

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Thang Pham
  • 38,125
  • 75
  • 201
  • 285
  • When you *click* the enter key? Don't you mean *press*? Do you want to invoke a specific method or just the default button's action method? Do you want to submit the whole form or only the current input element? – BalusC Oct 14 '10 at 22:08
  • I mean press, yes BalusC. And yes I only want to submit the current input element. I have another `form` outside, so I cant use what Damo suggest. – Thang Pham Oct 15 '10 at 04:09

6 Answers6

14

As per your question history, I know that you're using JSF 2.0, so here's a JSF 2.0 targeted answer: use <f:ajax> which listens on a change event and use keypress event to invoke it when the enter key is pressed (keycode 13).

<h:inputText value="#{bean.text1}" 
    onkeypress="if (event.keyCode == 13) { onchange(); return false; }">
    <f:ajax event="change" listener="#{bean.listener}" />
</h:inputText>

The #{bean.listener} should point to a method like

public void listener(AjaxBehaviorEvent event) {
    // ...
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • if I want to pass in a parameter to `#{bean.listener}`, usually I just do `#{bean.listener(param)}`, but since the first parameter is taken by `AjaxBehaviorEvent`, does it mean I have to use `f:param`? – Thang Pham Oct 15 '10 at 16:19
  • 1
    What would you like to pass? Isn't that parameter just already (in)directly in the bean? – BalusC Oct 15 '10 at 16:21
  • You can think of a `comment - reply` system like `facebook`. All the comments are display in a dataTable, with `var="item"`. In addition, each row has their own dataTable (`var="item2"`) representing the **replies** for that specific comment. So the inputText inject `reply` directly into the second dataTable, therefore I need to pass in the `id` of the row, **#{item.id}**, to whatever the method I execute. So that once I display, I know that this comment `X` is the reply to `Y`. – Thang Pham Oct 15 '10 at 16:32
  • BalusC, can u check the syntax. The inputText, when I press enter, nothing happen. It does not call my listener function. I update my post with some codes, will u take a look for me please? – Thang Pham Oct 15 '10 at 18:01
  • Does the generated HTML look right? I haven't tested this in combination with PrimeFaces components. – BalusC Oct 15 '10 at 18:20
  • I took out all the primefaces component. Still does not work. Here is the thing, if I put an `alert` inside the if statement of `onkeypress`, then the alert pop up when I press enter. So i try to replace your codes inside the `if` to `$('#myButton').click();`, where `myButton` is an `id` of a `h:commandButton style="display:none"` that invoke an action. Sadly, it still does not work. Any other idea? – Thang Pham Oct 15 '10 at 19:16
  • I think I just gonna do myself a big favor and adding in a button and save any more headache. Thank you guys – Thang Pham Oct 15 '10 at 19:41
  • You're using jQuery? Try `$(this).change()` instead of `onchange()`. There might be browser specific behaviours on `onchange()` I am not aware of. Which browser are you using? – BalusC Oct 15 '10 at 19:58
  • I have some times today to play with this. Firebug show me this. If I use `onchange()`, it give me error said `onchange() is not defined.` If I try `$(this).change()`, it said `$ is not a function`. Any idea why, BalusC? I used Mozilla btw. Thank you – Thang Pham Nov 02 '10 at 15:13
  • it seems to me that, this only work with `h:inputText`, but not to PF component like autoComplete. Thank you. – Thang Pham Nov 02 '10 at 16:02
  • 1
    Yes, it might have generated some JS code which is hooking on the `change` event as well. How to fix it depends on the actual generated HTML/JS. – BalusC Nov 02 '10 at 16:07
  • The JS generated by PF is enormous, do u actually eyeball those JS for debugging or is there a technique for it, BalusC? – Thang Pham Nov 02 '10 at 18:54
  • Thanks BalusC! This is the perfect answer to a problem I've been having with doing barcode scan inputs into a custom webapp! – Brian Knoblauch Apr 12 '12 at 19:17
  • @BalusC I think this is wrong and causes not expected behaviour. For example even don't hit the enter button but let's click first input text type sth. then click somewhere else fires ajax event. I think the reason is event=change which detects other changes as well. – Ömer Faruk Almalı Feb 19 '13 at 13:49
  • @Ömer: I have no idea what you're talking about. If you have a problem on your own, just press `Ask Question` button to ask a clear question about that. – BalusC Feb 19 '13 at 13:52
3

Actually you can use the following syntax:

<h:inputText value="#{bean.text1}" 
     onkeypress="return (event.keyCode == 13)">
  <f:ajax event="keypress" listener="#{bean.listener}" />
</h:inputText>

JSF creates an event chain and whatever you state under "onkeypress" will be evaluated BEFORE your f:ajax event. Thus you can return false to break the event chain. If you use the change event on f:ajax it'll of course fire on other change events which you probably don't want.

Jens B
  • 31
  • 1
  • This doesn't fire the initial change event when the user doesn't use enter key and leaves the field by tab/blur and therefore breaks the original functionality. – BalusC Sep 13 '13 at 12:10
3

The easiest way is to put the inputText in a form and hide a commandButton next to it.

For example:

<h:form>
  <h:inputText styleClass="myText" value="#{myBean.text}"/>
  <h:commandButton styleClass="myButton" action="#{myBean.myMethod}" style="display:none;" value="submit"/>
</h:form>

UPDATE:

If you are using Seam you can use the <s:defaultAction/> tag. This makes that commandButton that contains it the one that responds to the ENTER.

<h:commandButton class="myButton" action="#{myBean.myMethod}" style="display:none;" value="submit">
  <s:defaultAction/>
</h:commandButton>

If you aren't using Seam you could try one of the similar defaultAction controls

Or you could roll your own with a bit of Javascript; ideally jQuery. For example:

$('input.myText').keypress(function(e) {
    if (e.which == 13) {
        $('.myButton').click();
    }
});
Damo
  • 11,410
  • 5
  • 57
  • 74
  • On the very outside, I have a `form` already, so I cant have another `form` here. And unlucky enough, I have another commandButton as well. So when I press enter/return, is there a way to tell which commandButton to execute? – Thang Pham Oct 15 '10 at 04:07
  • I am gonna try your jQuery suggestion since I am not using Seam. So I just paste the code inside my header, inside the `` correct? Is `myText` the `id` of my `inputText`? I put an alert inside the if statement, and the alert does not get generated, any idea? – Thang Pham Oct 15 '10 at 18:33
  • Remember that JSF changes the IDs to include the form. You're better off sticking with the class. In this case "myText" is the class. – Damo Oct 16 '10 at 00:31
2

you can probably do something like this:

<h:inputText value="123" onkeyup="if(event.keyCode==13)this.blur();" onchange="document.getElementById('fakebutton').click();" valueChangeListener="#{yourbean.dosomething}"/>
<h:commandButton id="fakebutton"actionListener="#{yourbean.fakeaction}"/>

inside your bean:

public void dosomething(ValueChangeEvent event)
{
    System.out.println("I did something");
}
public void fakeaction(ActionEvent event)
{
    System.out.println("I do no nothing");
}
lkdg
  • 1,031
  • 7
  • 18
1

I decided to make this an answer so the code would be clearer than inlined as a comment, but Damo's solution is exactly what worked for me (so upvote his answer not this one ;-). I had a form with a text entry field and a search icon (a magnifying glass). I wanted the ajax query to be submitted by both a click on the magnifying class and pressing enter in the input text field. Clicking the icon in my original solution worked, but for the life of me I couldn't get pressing enter in the text field to submit the ajax call as well (it submitted the form via the normal mechanism instead). Here's the code that finally worked. Thanks again Damo.

<div class="boxWrapper searchWrapper right">
    <div class="boxHeader"><div class="tail" /></div>
    <div class="boxContent">
        <h:form prependId="false">
            <label>SEARCH:</label>
            <div class="searchBox">
                <f:ajax execute="@form" render="@none">
                    <h:inputText id="keywords" value="#{search.searchString}" onblur="inputTextBlur( this, '#{search.searchString}' );" onfocus="inputTextFocus( this, '#{search.searchString}' );" />
                    <h:commandButton action="#{search.search}" style="display:none;" value="submit" />
                    <h:commandLink id="cmdLink" action="#{search.search}">
                        <!-- the span here is to apply .searchWrapper span { } specific css to the image position -->
                        <span><h:graphicImage styleClass="iconSearch" url="images/iconMask.png" width="17" height="17" /></span>
                    </h:commandLink>
                </f:ajax>
            </div>
        </h:form>
    </div>
    <div class="boxFooter"><div class="tail" />
</div>

p.s. - @BalusC: This is the rare case where your answer wasn't a 100% fit with what I was looking for but I've lost count of how many of your others have been. So thank you to you as well, and enjoy the book I sent you from your wishlist. If you'd ever like to do some consulting please check my profile and send me an email.

Regards,

par

par
  • 17,361
  • 4
  • 65
  • 80
1

I had the same problem and since I don't have enough reputation jet, I post this as an answer.

In my case there are multiple inputs which need to be submitted with f:ajax separately. I needed to improve the solution of BalusC a bit.

You need to add this. in front of onchange().

<h:inputText value="#{bean.text1}" 
    onkeypress="if (event.keyCode == 13) { this.onchange(); return false; }">
    <f:ajax event="change" listener="#{bean.listener}" />
</h:inputText>
daff
  • 103
  • 1
  • 1
  • 8