仅在用户停止键入后才进行JSF 2.1 Ajax自动完成+服务器搜索 [英] JSF 2.1 Ajax autocomplete + server search only after user stops typing

查看:90
本文介绍了仅在用户停止键入后才进行JSF 2.1 Ajax自动完成+服务器搜索的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一种基于用户在<h:inputText />中输入的键入事件(onkeyup)进行数据库搜索的自动完成解决方案.

I'm developing a autocomplete solution with a database search based on typing events (onkeyup) that the user inputs in a <h:inputText />.

问题是我有两个先决条件,应用程序必须遵守这些先决条件才能进行服务器端搜索:

The problem is that i have two pre-conditions that the application must attend to do a server-side search:

  1. 通知的文本为> = 3和< = 6个字符
  2. 用户停止输入了几毫秒(以防止搜索过多导致服务器超载)

不带项目2),只需添加onkeyup="return checkInputs(this.value)之类的内容,并在每次输入的文字长度为<时返回false,就可以很简单地解决问题. 3或> 6.

Without the item 2) it's pretty simple do solve that just adding something like onkeyup="return checkInputs(this.value) and returning false every time that the text input lenght is < 3 or > 6.

但是要参加第2项,似乎我应该使用Javascript setTimeout ,在这种情况下,我使用了回调,即,我不能使用任何返回值来满足onkeyup的事件.我的输入文字.

But to attend item 2) it seems that I should use Javascript setTimeout , in which this case makes use of a callback, i.e, i can not use any return to meet the event the onkeyup of my input text .

几天来我一直在努力解决这个问题,而且我没有任何线索可以解决该问题,只是因为我的实际堆栈有限(JSF 2.1而没有任何其他库,例如PrimeFaces或OmniFaces和Jquery 1.3)

I've been struggling with this problem for a few days, and i don't have any clues how can i solve this, just because i'm limited with my actual stack (JSF 2.1 without any additional library such as PrimeFaces or OmniFaces and Jquery 1.3)

HTML代码:

<h:inputText id="text" alt="text"
                maxlength="6" size="6" title="text"
                value="#{managedBean.searchText}"
                onkeyup="return checkInputs(this.value)">
                <f:ajax listener="#{managedBean.doSearch}" execute="@this"
                    event="keyup" render="form:searchResult" />
            </h:inputText>

JavaScript:

Javascript:

function checkInputs(value) {

let cnsAnterior = sessionStorage.getItem('previousValue');
sessionStorage.setItem('previousValue', value);

if((value.length >= 3 && value.length <= 6) && (previousValue != value)){       
    return true;
}

return false;

}

我发现了一些代码段

Some snippet i've found at this website, for preventing search until user has stopped typing:

// Get the input box
var textInput = document.getElementById('test-input');

// Init a timeout variable to be used below
var timeout = null;

// Listen for keystroke events
textInput.onkeyup = function (e) {

    // Clear the timeout if it has already been set.
    // This will prevent the previous task from executing
    // if it has been less than <MILLISECONDS>
    clearTimeout(timeout);

    // Make a new timeout set to go off in 800ms
    timeout = setTimeout(function () {
        console.log('Input Value:', textInput.value);
    }, 500);
};

使用JSF,有什么办法可以参加这两个条款吗?仅当用户键入至少3个字符并且在几毫秒内停止键入时,服务器才搜索吗?

Is there any way, using JSF, that i can attend this two clauses ? Only do a server search when user typed at least 3 characters AND stopped type at few milisseconds ?

谢谢.

推荐答案

由于您尚未使用JSF 2.2或更高版本,并且无法使用PrimeFaces(仅针对其p:ajax),因此您确实需要一些解决方法"(实际上,这不是解决方法,但对于JSF 2.1是一个好的解决方案).

Since you are not on JSF 2.2 or up (yet) and using PrimeFaces (purely for its p:ajax) is not an option, you indeed need some 'workaround' (effectively it is not a workaround but for JSF 2.1 a good solution).

幸运的是,许多所谓的现代" javascript UI粉丝都忘记了这一点,JSF客户端只是html,javascript和ajax.和JSF ajax一样,就像其他任何框架中的其他ajax一样,都是使用javascript处理的,并且其基本ajax处理可以以基本的javascript方式覆盖,如

Fortunately, and many so called 'modern' javascript UI fans forget this, the JSF client side is just html, javascript and ajax. And the JSF ajax is, just like any other ajax in any other framework, handled with javascript and its basic ajax handling can be overridden in a basic javascript way as can be seen in Aborting JSF Ajax Request from jsf.ajax.addOnEvent().

我以此为基础,并将其与一些创造性的基本javascript超时处理结合在一起,因为您已经怀疑需要这样做.

I took this as a basis and combined this with some creative basic javascript timeout handling as you already suspected would be needed.

它利用该选项通过超时将原始事件参数传递给非匿名javascript函数.就像在如何传递参数中一样到setTimeout()回调?.最困难的部分是找出参数"将如何传递.事实证明,您甚至可以传递多个单个参数而不是一个"arguments"参数

It makes use of the option to pass the original event arguments on to a not-anonymous javascript function via timeout. Like in How can I pass a parameter to a setTimeout() callback?. The hardest part was to find out how the 'arguments' would be passed. It turned out you can even pass multiple individual arguments to the setTimeout instead of one 'arguments' argument

看起来很多代码,但很多是注释/日志记录(可以删除),并且可以减少一些变量.

It looks like a lot of code but a lot is comment/logging (which you can remove) and some variables can be reduced.

if (jsf) { // test if the 'jsf' javascript is available

    var originalRequest = jsf.ajax.request; // 'save' the original ajax handling
    var timeouts ={}; // keep an 'hash' of timeouts so it can be used for lots of
                      // different elements independently based on element id

    jsf.ajax.request = function(source, oevent, options) {

        // check for a 'delayedEvent' class on an input and only apply delay to those that have one
        delayed = document.getElementById(oevent.target.id).classList.contains("delayedEvent");
        if(delayed) {

            // check if an existing timer for this element is already running and clear it
            // so it will never fire but will be 'superseded' by a new one
            var timeout = timeouts[oevent.target.id];
            if (timeout != undefined) {
                console.log('Delayed event cleared: ' , arguments, timeout);
                clearTimeout(timeout);
            } 

            // create a new timeout with a 350 ms delay. Making the delay 'dynamic' could 
            // be done by creating 'composite' classnames like 'delayEvent500' and delayEvent250'. 
            // Or putting both via html 5 data attributes on a container elelement... 
            // Be creative
            timeout = setTimeout(applyOriginalEvent, 350, source, oevent, options);
            console.log("Delayed event created: ", arguments, timeout);
            timeouts[oevent.target.id]=timeout;
        } else {
            console.log('Direct event fired: ' , arguments);
            originalRequest.apply(null, arguments); // apply the request direcyly
        }
    };


    function applyOriginalEvent(source, oevent, options) {
        var timeout = timeouts[oevent.target.id];
        console.log('Delayed event fired: ' , arguments, timeout);
        // fire an ajax request with the original arguments;
        originalRequest.apply(null, arguments);
        // remove the timeout from the list
        delete timeouts[oevent.target.id];
    }

};

只需确保在加载jsf.js之后就加载了该文件.我在本地和通过浏览器开发人员控制台在Omnifaces展示柜上对此进行了测试.

Just make sure this is loaded after jsf.js is loaded. I tested this locally and on the Omnifaces showcase via a browser developer console.

我没有进行测试的是您现有的长度"检查,但这些检查可能会保持不变.

What I did not test it with is your existing 'length' checks but these could be left untouched.

这篇关于仅在用户停止键入后才进行JSF 2.1 Ajax自动完成+服务器搜索的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆