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
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) ;
}
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
window.scrollX
, window.scrollY
properties to get how much the user has scrolled either horizontally or vertically the pageby mdn web docs : The read-only scrollX property of the Window interface returns the number of pixels that the document is currently scrolled horizontally
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
I hope this will help some one