5

I'd like to make an autocomplete where if one types an "@" they are offered an autocomplete list of names.

I'm using jQueryUI autocomplete and the only problem with my solution ( http://jsfiddle.net/aUfrz/22/ ) is that the autocomplete-able text input needs to be placed on top of the textarea cursor position and not to the right as it currently stands.

Here's my JS that's in the JSFiddle:

$(document.body).on('keypress', 'textarea', function(e) {
   var names = [
        "johnny",
        "susie",
        "bobby",
        "seth"
    ],
    $this=$(this),
    char = String.fromCharCode(e.which);

    if(char == '@') {
       console.log('@ sign pressed');
       var input=$('<input style="position:relative; top:0px; left:0px;background:none;border:1px solid red" id="atSign" >');
       $this.parent().append(input);
       input.focus();
       input.autocomplete({
        source: names,
        select: function (event, ui) {
            console.log('value selected'+ui.item.value);
            //$this.val('@'+ui.item.value);
            $this.insertAtCaret(ui.item.value);
            $this.focus();
            input.remove();
        } //select
    });  //autocomplete
  } //if 
}); // keypress

HTML:

<textarea></textarea>​

Please note that I have NOT shown here a jQuery plugin I used to insert the selected autocomplete suggestion at the caret position: insertAtCaret() which I found at this other SO question.

Community
  • 1
  • 1
tim peterson
  • 23,653
  • 59
  • 177
  • 299
  • You mean you want to get the caret's pixel coordinates, then position the input there? I'm not sure it is possible to get the pixel coordinates of the caret. – Asad Saeeduddin Oct 19 '12 at 16:51
  • that seems like one solution, why can't we get those coordinates? – tim peterson Oct 19 '12 at 16:53
  • Because this information is generally not needed and as such has not been made accessible through the DOM. You could try multiplying the pixel width of each character by the character offset of the caret to get the pixel offset of the caret within the textarea. – Asad Saeeduddin Oct 19 '12 at 17:02
  • @Asad thank you, can you provide this suggestion in an answer? – tim peterson Oct 19 '12 at 17:02
  • 1
    I am working on implementing this in the fiddle and will post an answer shortly. If anyone beats me to it, they are welcome to post it. – Asad Saeeduddin Oct 19 '12 at 17:04

2 Answers2

2

One way to get the caret position is to multiply the pixel width of each character by the character offset of the caret. Here is a somewhat crude example that demonstrates. The x offset from the textarea is calculated like this:

e.target.value.length*13

EDIT: Here is a greatly improved version. An important discovery was that in monotype font faces the ratio between the width and height is 8/13.

In the screenshot below, you can see that the input appears at the caret position when I press @.

A screenshot showing how it looks in my browser.

And here is a screenshot in Chrome, showing the same behavior

enter image description here

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
  • the text input is still moving relative to the cursor each time a name is added, to simply things it might be easiest just append the autocomplete suggestions to the bottom left of the textarea. that wouldn't be too terrible. Also, do you know how to hide the text input such that it doesn't have a border? – tim peterson Oct 19 '12 at 17:20
  • As far as the text input moving is concerned, I have fixed that in the second fiddle. Try [this](http://jsfiddle.net/K8jGh/1/). The input appears for the autocomplete, then disappears once you have selected a value. – Asad Saeeduddin Oct 19 '12 at 17:23
  • It moves to the caret position, if that is what you mean. Was that not your requirement? – Asad Saeeduddin Oct 19 '12 at 17:33
  • It looks like it behaves different on [Chrome](http://imgur.com/jRO3q) vs. IE . Can you try also try to get rid of the text input border CSS on focus? I'd like to make the input transparent so the user doesn't realize they are actually typing in a different box. I'd appreciate your help and would like to accept your answer, its just still a little off... – tim peterson Oct 19 '12 at 18:03
  • This is outside the original scope of the question, but [here](http://jsfiddle.net/Z59Kp/) you go. There is still a lot of work to be done here (positioning and styling the autocomplete messages etc). – Asad Saeeduddin Oct 19 '12 at 18:12
  • 2
    I don't think the positioning part is of high enough quality to accept. I think I will just append the input and suggestions to the bottom of the textarea. It is a fair point that the styling was not originally asked. – tim peterson Oct 19 '12 at 18:25
  • @timpeterson I just downloaded Chrome and tested it and it works fine! Are you sure you were using the latest version of my fiddle? – Asad Saeeduddin Oct 19 '12 at 18:42
  • I'm pretty sure I was, but can you tell me what version of the fiddle you want me to look at? Regardless, having a visible text input within the textarea is ugly and confusing for the user so until I could figure out the CSS to make it "invisible" I'm not sure I want to pursue this any further. – tim peterson Oct 19 '12 at 18:47
0

This other SO answer which mentions this pretty slick jQuery plugin asuggest is what i'm going to go with. Thanks @asad for your help.

Here's the JSFiddle of the final product using asuggest(): http://jsfiddle.net/trpeters1/xjyTW/2/

here's the JS from this JSFiddle:

$.fn.asuggest.defaults.delimiters = "@";
$.fn.asuggest.defaults.minChunkSize = "0";  

$(document.body).on('keypress', 'textarea', function(e) {
  var names = [
    "johnny",
    "susie",
    "bobby",
    "seth"
  ],
  $this=$(this),
  char = String.fromCharCode(e.which);

   if(char == '@') {
     $this.asuggest(names);
     var v='';
     if($this.click()) { console.log('clicked textarea');           
       v=$this.val(); console.log('texarea value'+v);           
       for(var i=0; i<names.length;i++ ){ 
         if(v.indexOf('@'+names[i]) != -1){
           names.splice(i,1);  console.log('names spliced away: @'+names[i]);              
         } // if indexOf
       } //for
     } //if click
   } //if @
}); //keypress​

HTML:

<textarea></textarea>​
Community
  • 1
  • 1
tim peterson
  • 23,653
  • 59
  • 177
  • 299