0

So I've been trying to build an auto suggestion feature that will display multiple suggestions that have partial match or value within the inputbox. It should also only start providing suggestions that starts with a specific character which is an @ Symbol

Example: Task 1 @james @john

Much like how facebook starts making suggestions when you provide the text with an @ Symbol

The code below listens to the values inserted in the inputbox during a keypress. Then it stores those values in array where it will filter values that only contains an @ in the beginning. Then it makes a comparison with another array that has those values. Once a match is indicated it will then loop through the names-list element for a match then adds a class called display

The code below is still a work in progress and that I'm still trying to figure it how to finish it with the proper syntax.

let listenOnInput = () => {
  let handles = [];
  let names = ['@john', '@jake'];

  $(".task-label input").on("change keyup paste", function() {
    let names = ($(this).val());
    let splitHandles = names.split(' ');

    $.each(splitHandles, function(i, value) {
      if (splitHandles[i].indexOf('@') == 0) {
         handles.push(splitHandles[i]);
       }
      for (let elements of handles) {}
    })
  });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="task-label">
  <input type="text">
</div>
<ul class="name-list">
  <li class="name name-john">@John</li>
  <li class="name name-jake">@John</li>
</ul>
clestcruz
  • 1,081
  • 3
  • 31
  • 75

1 Answers1

1

You are on the right track! And almost there.

After splitting all of the names you'll need to compare if one of the names given corresponds somehow with the right element in your HTML. You could do this multiple ways, like checking for the innerText, or the className or an id of one of the <li class="name name-x"> elements.

I've modified your HTML so that every one of your <li> elements has an id. This makes them unique and easy to select. I've also have given the <input> element an id for the same reason.

For the event listener listen to either change or input. Either of them triggers on whenever the value has been changed, so that means also when a user types, or pastes a string into it. For the example I've chosen input as you'll only want anything to happen whenever the text of the <input> is changed. Read this other SO post to learn what the difference between change and input entails.

Because I couldn't find the jQuery function necessary to build on your example I've chosen to do it with ES6. In you example I see you using a for... of loop and an arrow function, so I assumed that using modern JS is allowed.

I've tried to add as much hinting as possible in the example below explaining what every piece of code does. If you have any questions regarding the code below, feel free to ask.

I hope it helps you out.

// Select the input.
const input = document.getElementById('name');

// Select the <li class="name"> elements.
const names = document.querySelectorAll('.name');

// Listen to the 'input' event. This will be triggered whenever the value
// of the input has been changed.
input.addEventListener('input', event => {

  // Get the value of the input and split it.
  const value = event.target.value;
  const splitValues = value.split(' ');

  // Get only the values that start with '@' and return the remaining values 
  // in lowercase, without the '@' symbol, to match with the id attribute later on.
  const targetValues = splitValues
    .filter(value => value.indexOf('@') === 0) // Only values starting with '@'
    .map(value => value.substring(1).toLowerCase()); // '@Name' => 'name'

  // Loop over each name element. If one of the values corresponds, 
  // partially or fully, with the id of the a <li class="name"> element
  // add the display class, if not remove the display class.
  names.forEach(name => {
    if (targetValues.some(value => name.id.includes(value))) { // id === 'name' ?
      name.classList.add('display');
    } else {
      name.classList.remove('display');
    }
  });

});
.name {
  display: none;
}

.name.display {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="task-label">
  <input id="name" type="text" name="name">
</div>
<ul class="name-list">
  <li id="john" class="name name-john">@John</li>
  <li id="jake" class="name name-jake">@Jake</li>
  <li id="alex" class="name name-alex">@Alex</li>
  <li id="allison" class="name name-allison">@Allison</li>
</ul>
Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32