Code Monkey home page Code Monkey logo

autocomplete's Introduction

Thank you for the opportunity to work on this project.

Introduction

This project was written loosely based on the user experience within Personal Capital's UI for searching for a financial institution when linking a new account.

As soon as you begin typing, matching product results will begin to show on the page.

Selecting a product (either with a mouse click or pressing enter) currently sends an alert showing which product was selected. This is based on the functionality of Personal Capital's search - further details about the feature would be needed before deciding how the URLs of the products should be used (if at all).

Requirements

  • Single page app
  • Allow users to search for a financial institution using an autocomplete style search box
  • When the user enters text into the search box, the app should use the provided data feed to search product names for the term the user entered into the search box
  • Results should be returned & displayed as a "drop down" of the search box
  • UX should be a consideration
  • Follow responsive layout
  • Any libraries/tools are allowed except for libraries that implement autocomplete directly

Design Choices

  • I started with Create React App and wrote a custom component: Autocomplete.tsx.
  • Though it's not a very complex project, I decided to use TypeScript to keep the code organized and so that the project could be easily expanded upon.
  • I wanted to support searching for names of products out of order, e.g. "schwab charles" would also return "charles schwab" as an option.
  • There is no debouncing of the input since the performance seems to be able to keep up with a person typing.
  • I considered using a library such as Material-UI but decided to keep things simple and focus on functionality.
  • No additional libraries were used.

Features

The following design guidelines were taken into consideration:

  • Style Auxiliary Data Differently: Addressed in the CSS file with...

    .product-type {
      font-size: 10px;
      color: rgb(134, 126, 126);
      margin-left: 5px;
      text-align: right;
    }
  • Avoid Scrollbars & Keep the List Manageable: Results are limited to the first 10 matches. This was done by setting the limit in this for loop:

    for (let i = 0; i < products.length && newMatches.length < 10; i++) ...
  • Highlight the Differences: This is also addressed below in the Challenges section and implemented with this function:

    function boldDifference(name: string) {
      let phrase = "(" + searchText.trim().replace(/ /g, "|") + ")";
      const __html = name.replace(
        new RegExp(phrase, "ig"),
        `<span class="matchedText">\$1</span>`
      );
      return { __html };
    }
  • Support Keyboard Navigation: Implemented using the onKeyDown function and a switch case:

    function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
      let newIndex: number | undefined = selectedIndex;
      switch (event.key) {
        case "ArrowDown":
          if (newIndex === undefined) {
            newIndex = 0;
          } else if (newIndex < matches.length - 1) {
            newIndex++;
          }
          break;
        case "ArrowUp":
          if (newIndex === undefined) {
            newIndex = matches.length - 1;
          } else if (newIndex > 0) {
            newIndex--;
          }
          break;
        case "Enter":
          if (newIndex !== undefined) {
            onSelect(matches[newIndex]);
          }
          break;
        default:
          newIndex = undefined;
          break;
      }
      setSelectedIndex(newIndex);
    }
  • Match User’s Hover Expectations: Addressed using CSS with the following code:

    .content-item:hover,
    .content-item-selected {
      background-color: rgba(100, 100, 100, 0.5);
      }
  • Show Search History: Further thought would need to be put in to this guideline based on how the feature will be used by the user.

  • Reduce Visual Noise And Consider Including Labels & Instructions: The page consists only of a text area for search input and results (once the user begins typing). The search text area includes a placeholder with an example of a financial institution to search.

Challenges

The most challenging part of the project was writing the function to emphasize the differences between the search input text and the product matches. Changing the class name multiple times within one string required some thought and data manipulation. The regular expression to allow for the searching of phrases in random order (searching for Express American will return American Express) further complicated this. In the end, I decided to use dangerouslySetInnerHTML to render the manipulated string with an added html class. This is done in the following function...

function boldDifference(name: string) {
  let phrase = "(" + searchText.trim().replace(/ /g, "|") + ")";
  const __html = name.replace(
    new RegExp(phrase, "ig"),
    `<span class="matchedText">\$1</span>`
  );
  return { __html };
}
dangerouslySetInnerHTML={boldDifference(product.name)}

In production, I've read that we should consider how this feature is being used in order to mitigate cross-site scripting attacks (for example by sanitizing content). In this case, since the text that is being set as innerHTML is actually always coming from a trusted source (the list of products from the server), the risk of using dangerouslySetInnerHTML is outweighed by the simplicity of the implementation and the benefit of the feature to the end user.

Conclusion & Next Steps

I enjoyed working on this exercise. There were a variety of interesting algorithm and design challenges. Trying to predict user behavior and edge case scenarios could be done by understanding more about the actual intended usage of the component. In the same vein, discussing a variety of additional questions (e.g. what should the user expect to happen upon selecting/ clicking on a product?) would help ensure that it is intuitive and easy to use.

Beyond that, if I were to continue this project I would consider writing tests with either jest or cypress as those are both tools I'd like to gain more experience with.

Thanks for reading and checking out my code! Also thanks for giving me this opportunity. If anything is unclear or there are any questions/comment/concerns I'd love to hear them and get some feedback so I can continuing building my skills.

autocomplete's People

Contributors

lelelew avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.