Source: src/js/views/maps/viewfinder/PredictionView.js

"use strict";
define([
  "backbone",
  "text!templates/maps/viewfinder/viewfinder-prediction.html",
], (Backbone, Template) => {
  // The base classname to use for this View's template elements.
  const BASE_CLASS = "viewfinder-prediction";

  /**
   * @class PredictionView
   * @classdesc PredictionView shows an autocomplete suggestion
   * for the user when they are searching for a place on a map.
   * @classcategory Views/Maps
   * @name PredictionView
   * @extends Backbone.View
   * @screenshot views/maps/viewfinder/PredictionView.png
   * @since 2.28.0
   * @constructs PredictionView
   */
  const PredictionView = Backbone.View.extend(
    /** @lends PredictionView.prototype */ {
      /**
       * The type of View this is
       * @type {string}
       */
      type: "PredictionView",

      /**
       * The HTML class to use for this view's outermost element.
       * @type {string}
       */
      className: BASE_CLASS,

      /**
       * The HTML element to use for this view's outermost element.
       * @type {string}
       */
      tagName: "li",

      /**
       * The HTML classes to use for this view's HTML elements.
       * @type {Object<string,string>}
       */
      classNames: {
        content: `${BASE_CLASS}__content`,
      },

      /**
       * The events this view will listen to and the associated function to call.
       * @type {Object}
       */
      events: { click: "select" },

      /**
       * Values meant to be used by the rendered HTML template.
       */
      templateVars: {
        classNames: {},
        isFocused: false,
      },

      /**
       * @typedef {Object} PredictionViewOptions
       * @property {Prediction} The Prediction model associated with this
       * autocompletion prediction.
       * @property {ViewfinderModel} The model associated with the parent view.
       * @property {number} The position of this prediction within the parent's
       * full list of predictions.
       */
      initialize({ index, predictionModel, viewfinderModel }) {
        this.predictionModel = predictionModel;
        this.viewfinderModel = viewfinderModel;
        this.index = index;

        this.templateVars = {
          ...this.templateVars,
          classNames: this.classNames,
          description: this.predictionModel.get("description"),
        };

        this.setupListeners();
      },

      /**
       * Setup all event listeners on ViewfinderModel.
       */
      setupListeners() {
        this.listenTo(this.viewfinderModel, "change:focusIndex", () => {
          this.render();
        });
      },

      /**
       * Event handler function that selects this element, deselecting any other
       * sibling list elements.
       */
      select(event) {
        this.viewfinderModel.selectPrediction(this.predictionModel);
      },

      /**
       * Render the view by updating the HTML of the element.
       * The new HTML is computed from an HTML template that
       * is passed an object with relevant view state.
       * */
      render() {
        const focusIndex = this.viewfinderModel.get("focusIndex");
        this.templateVars.isFocused = focusIndex === this.index;

        this.el.innerHTML = _.template(Template)(this.templateVars);
      },
    },
  );

  return PredictionView;
});