Search code examples
javascripthtmljquerytagsposition

How to create a tag list that could show up inside input after keyUp


I am making a web application that some tags as input and replace those tags with some appropriate values

For example : the text in the input is : Hello mr [NAME] : so the result is Hello mr Robert

I did that this is easy

But I wanted to add a user experience feature which is when the user type the first bracket "[" a list containing the tags with the wrriten characters show up and he could select from it as shown in the image bellow

enter image description here

I had made 80% of the work and I know what to do else but I am blocked right now on how to get the position of the last typed character inside the input on the page or how to make that list inside the input any ideas please ?

var template = document.createElement("ul");
template =`<ul></ul>`;
var tagsArr = [];
var alltags ;

//fetching the tags from the database and making them in a set

$.ajax({
    url: "/getTags",
    type: "GET",
    dataType: "json",
    success: function (data) {
       console.log(data.tags)
        data.tags.forEach((element) => {
            tagsArr.push(element.name);
        });

         alltags = new Set(tagsArr);

   //----------------------------------------

    },
});

search in the set for the tags that contains letters as the typed ones
function search(e) {
    let X = e.target.selectionStart
    console.log(e.keyCode);
    let result = document.getElementById("result");
    result.innerHTML = "<b>X-coordinate: </b>" + X;
    var taglist = document.getElementById("taglist");
    if (taglist != null) {
       taglist.remove();
    }
    var filtredTags = [];
    alltags.forEach(function (value) {
      
        if (value.includes(String.fromCharCode(e.keyCode).toUpperCase())) {
            //recheck ythis one
            filtredTags.push(value);
         
        }
    });

    return build(new Set(filtredTags));
}


build list element with list items that have the values retrieved from search method
function build(Mcontent) {
    var str = ""
    var list  = document.createElement("ul");
    list.style.fontSize= "8pt";
    list.style.listStyle = "none";
    list.setAttribute("id","taglist");
    Mcontent.forEach(function (value) {
    var listeitem = document.createElement("li")
    listeitem.append(value)
    list.append(listeitem) 
    });

    var body = document.getElementsByTagName("body")[0];
   // str = "<ul id='taglist'  >"+str+"</ul>";
    body.append(list) ;
}

Solution

  • Well in case any one needed It I resolve it the problem was to find the position(x,y) of the last typed char on the page

    First I needed to get the position(x,y) of the input it self and it size(w,h)

    I did that using :

    • The getBoundingClientRect() method , typically this method draw a rectangle around the input and return the (top,left,bottom,right,hight , width) of any element for my case I did : const rect = input.parentElement.getBoundingClientRect(); because my input was in a div element

    • Then I used the selectionEnd property wich return the index of the caret within the value inside the input

    if the value of the input is : "abcefg" : and the cursor is after "c" the selectionEnd will return 2

    • After that you gonna need the window.scrollX , window.scrollY properties to get how much the user has scrolled either horizontally or vertically the page

    by mdn web docs : The read-only scrollX property of the Window interface returns the number of pixels that the document is currently scrolled horizontally

    • And finally you gonna need the font size of your input value

    When all of this and after creating your list in the style part you need to identify the position , top , and left props like this

     const top = rect.top +rect.height+ window.scrollY  ;
     const left = rect.left + window.scrollX + (input.selectionEnd * fs) ; // 
     considering fs is your font size 
    
     const element= document.createElement("div");
     element.style.width ="100px";
     element.style.height="100px";
     element.position ="absolute"
     element.top= top  + "px"
     element.left =left + "px"
    

    you add that previous code into keyup event listener to update the selection end . you might face a problem after reaching the end of the input , like the list will show up long far in X axis because the value length change but the input width doesn't . To work around this issue you only need to add some conditions like

     if (rect.left + window.scrollX + (input.selectionEnd * fs) > rect.width )
       left = rect.width 
     else 
        left = rect.left + window.scrollX + (input.selectionEnd * fs) 
    

    that's it the result for me was

    Result

    I hope this will help some one