0

I tried searching, but am not finding a solution.

I am currently using Jquery autocomplete, along with an external service that stores the lists of possible returned results. The autocomplete is being done on a textarea, and I need to try to autocomplete for each line of text. So the user types one line, gets auto complete. Goes to a new line, starts typing, autocomplete appears only for what's on that line.

The set up is pretty standard to what JQuery shows off. I.E.:

<textarea id="entities"></textarea>

JS:

$("#entities").autocomplete({
        serviceUrl: [the service url],
        paramName: 'prefix'
});

I know there are ways to determine line number and get the value of a specific line such as:

$("#entities").on('keyup', function() {
    var textLines = $("#entities").val().substr(0, $("#entities").selectionStart).split("\n");
    var currentLineNumber = textLines.length - 1;
    console.log(lines[currentLineNumber]);
});

But I'm not sure how I could call the autocomplete function upon typing a new line.

Edit: Someone suggested using contentEditable, but this results in different wrappers for each line depending on the browser.

<div id="entities" class="entities-text" contenteditable="true"></div>

IE converts each line to:

<p>Line 1</p>
<p>Line 2</p>

FF shows:

Line 1<br>
Line 2<br>

Chrome gives:

<div>Line 1</div>
<div>Line 2</div>
yondaimehokage
  • 243
  • 2
  • 15
  • What do you mean with: "autocomplete for each line of text" ?. Could you describe better what you need ? – xsami May 23 '17 at 20:11
  • 1
    So for example, lets say they type in the textarea. When they first start typing, the autocomplete appears. They select the term. Now the user presses enter and starts typing on the second line in the textarea. The autocomplete should appear again, but only to suggest values for whatever they are typing on the second line in the textarea. In short, the textarea is part of a form that searches for values per line in the textarea. – yondaimehokage May 23 '17 at 20:15

2 Answers2

0

I am not so sure that you can achieve that so easily using a textarea and for each row of the textarea.

My suggestion is to switch to a contenteditable div, maybe formatted through CSS like a textarea if you want that style, then every time that you detect a new line, wrap the new line with an HTML element (for example a p). Then just set the autocomplete to work with all the p elements inside that div.

Here you have a really good example on how to do that in case that you type a @ (it's an autocomplete for email addresses). Changing a bit the code, you will have your job pretty done.

autocomplete with contenteditable div instead of textarea doesn't seem to work

There is also a link to the jsfiddle example inside the post.

quirimmo
  • 9,800
  • 3
  • 30
  • 45
  • Ok, I'll look into this tomorrow. Thanks for the suggestion. – yondaimehokage May 23 '17 at 20:17
  • Unfortunately, this adds another issue to fix - IE automatically wraps each in

    but FF uses
    and Chrome wraps in

    .
    – yondaimehokage May 24 '17 at 14:27
  • yes but if you use your own wrapper , then you just need to trigger the autocomplete on your own, and you won't care of the other elements that have being wrapped. You got what I mean? – quirimmo May 24 '17 at 14:28
  • No I am not understanding. What do you mean by "your own wrapper"? Can you provide an example? – yondaimehokage May 24 '17 at 14:56
  • I mean that when you detect a new line, you wrap the content of the line with an HTML element, let's say a `
    `. So your content is inside this div. Then if the browser will wrap your element with another one, it doesn't matter because you can trigger the autocomplete just in all the elements with class "row-in-the-editor" inside your contenteditable. Does it make sense?
    – quirimmo May 24 '17 at 15:08
  • But presumably, the user is typing - so how do we account for putting the changing value ans rewrapping all of it inside the "row in the editor"? Really, an example would be helpful, not just an explanation. Plus detection of a new line will still vary per browser. – yondaimehokage May 24 '17 at 15:12
  • Here an example. I did it just for one single div considering just one single line, so typing enter you will be on the same line and everything will be wrapped with one line. I left also something commented and some functions already there, that they will be pretty useful for you. If you spy in the HTML source, whatever you type is inside a div with the above class https://jsfiddle.net/4dgpLo1e/ – quirimmo May 24 '17 at 15:53
0

I think this Function help full to you ... complete your requirement.

 function CreateTextAreaAutoFill(idstr, AutoFillAry) {
    $("#" + idstr)
        // don't navigate away from the field on tab when selecting an item
        .on("keydown", function (event) {
            if (event.keyCode === $.ui.keyCode.TAB &&
                $(this).autocomplete("instance").menu.active) {
                event.preventDefault();
            }
        })
        .autocomplete({
            minLength: 0,
            source: function (request, response) {
                // delegate back to autocomplete, but extract the last term
                response($.ui.autocomplete.filter(
                    AutoFillAry, extractLast(request.term, idstr)));
            },
            focus: function () {
                // prevent value inserted on focus
                return false;
            },
            open: function (event, ui) {
               // $(this).autocomplete('widget').find('li').css('font-size', '10px');
               // $(this).autocomplete('widget').css('height', 100);
            },
            select: function (event, ui) {
                //var terms = split(this.value);
                //// remove the current input
                //terms.pop();
                //// add the selected item
                //terms.push(ui.item.value);
                //// add placeholder to get the comma-and-space at the end
                //terms.push("");
                //this.value = terms.join(" ");//terms.join(", ");
                debugger;
                var term = this.value;
                var cursorPosition = $('#' + idstr).prop("selectionStart");
                var SpaceInd = term.lastIndexOf(" ", (cursorPosition - 1));
               // var SubStr = term.substring((SpaceInd + 1), cursorPosition);
                var NewLineInd = term.lastIndexOf("\n", (cursorPosition - 1));
                var SubStrInd = SpaceInd < NewLineInd ? NewLineInd : SpaceInd;
                var FirstStr = this.value.substring(0, (SubStrInd + 1)) + ui.item.value;
                this.value = FirstStr + this.value.substring(cursorPosition, this.value.length);

                $('#' + idstr).prop('selectionEnd', FirstStr.length);

                return false;
            }
        });

    //function split(val) {
    //   // return val.split(/;\s*/);
    //   // return val.split(' ');
    //    var LineAry = val.split("\n");
    //    var FinalResult = [];
    //    $.each(LineAry, function (ind, Aval) {
    //        FinalResult = FinalResult.concat(Aval.split(' '));
    //    })
    //    return FinalResult;
    //}
    function extractLast(term, idstr) {
        debugger;
        var cursorPosition = $('#' + idstr).prop("selectionStart");
        var SpaceInd = term.lastIndexOf(" ", (cursorPosition - 1));
        var NewLineInd = term.lastIndexOf("\n", (cursorPosition - 1));
        var SubStrInd = SpaceInd < NewLineInd ? NewLineInd : SpaceInd;
        var SubStr = term.substring((SubStrInd + 1), cursorPosition);

        return SubStr;//split(term).pop();
    }
}
Gupta
  • 314
  • 2
  • 8