JSF自定义组件在Ajax更新时失去输入焦点

6

我正在编写一个自定义的自动完成组件,作为JSF 2.1.3的学习练习。这个想法(可能相当熟悉)是输入一些文本到输入组件中,并呈现一个匹配值的列表框。想法是在输入上有一个keyup JavaScript事件来调用jsf.ajax.request()来更新组件。到目前为止,我已经得到了一个可以像这样包含的组件:

<mycc:autocomplete id="myauto" searchMethod="#{bean.doSearch}"/>

这会将HTML渲染成这样:
<span id="myauto">
  <input type="text" id="myauto_input" name="myauto_input"
    onkeyup="com.myco.ajaxRequest(this, event)"/>
  <select id="myauto_listbox" name="myauto_listbox">
    <option value="1st">First</option>
    <option value="2nd">Second</option>
  </select>
</span>

com.myco.ajaxRequest() JavaScript函数(keyup)的作用如下:

jsf.ajax.request(comp, null, {
                 execute: 'myauto',
                 render: 'myauto'
                 });

所以,因为我想要使用建议列表重新构建和重新渲染listbox,所以我正在重新渲染自定义组件'myauto'。通过指定execute: 'myauto',decode()方法执行并且我可以获取输入值。通过指定render: 'myauto',encode...()方法执行以重新生成html。
这一切都很好,但是因为我正在渲染myauto_input组件的父级,每次keyup事件触发时都会失去输入焦点。
如果我指定类似于render: 'myauto_listbox'的内容(毕竟我只想重新渲染列表框),问题在于encode...()方法不执行,因为它们是针对整个自定义组件而不仅仅是列表框。而我重建包含建议的列表框就在其中一个encode...()方法中。
该组件扩展了UIInput并在encodeEnd()方法中生成标记(componentFamily = "javax.faces.Input")。我假设从JavaScript强制聚焦是可怕的hack,应该避免使用。
我有点不确定该怎么做,但我认为我看到的情况表明我在某种程度上错误地处理了这个问题。如果有人能够指引我正确的方向,我将非常感激。
1个回答

1

我花了一些时间研究这个问题,失去焦点的普遍问题在ajax更新后是相当常见的,在Jim Driscoll的博客中有描述(请参阅“保持焦点”)。

就我的自定义组件而言,我认为我必须更新自定义组件本身,它是输入框的父组件,因此我会因为ajax更新而失去焦点,这就是事实。因此,我已经看了看需要做什么来恢复焦点,似乎在我的renderer encode中,我只需要在响应jsf.ajax.request发送的POST时强制将焦点恢复到输入框即可。我使用jQuery,只调用.focus()是不够的,因为您还必须将光标位置移到任何现有输入的末尾。下面的代码似乎可以正常工作:

<script>
  jQuery(function($){var cid='#myauto_input';$(cid).focus().focus().click();$(cid).val($(cid).val());});
</script>

注意:在IE8中需要使用.focus().focus().click(),而在Chrome中只需要使用.focus()。

看起来这个可怕的hack方法挽救了这一天。我曾经想过如果我使用jQuery ajax例程而不是jsf ajax库是否会有任何区别,但我想这不会有任何影响。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接