> Faqs > Problema con this en eventos de templates Lit usando map()

Problema con this en eventos de templates Lit usando map()

Estoy iniciando en programación y estoy usando Lit-element, al consumir una api de peliculas he decidido mostrar los elementos resultantes usando map y retornando un template html, pero al intentar agregar un evento a los resultantes no reconoce la función a ejecutar.

El render se visualiza asi:

render() {

    return html`
    <div id="globalContainer">
    <button class="buttonsPage1"><</button>
    <div id="containerMovies">
      <ol id="listMovies">
        ${this.path.map(function(item){return html `<li ><p>${item[0]}</p><img
        src="https://image.tmdb.org/t/p/w500/${item[1]}"><button>mostrarResumen</button></li>`} )}
      </ol>
    </div>
    <button class="buttonsPage2">></button>
    </div>
    `;
  }

y el problema surge al intentar cambiar la función map agregando el evento al boton:

render() {

    return html`
    <div id="globalContainer">
    <button class="buttonsPage1"><</button>
    <div id="containerMovies">
      <ol id="listMovies">
        ${this.path.map(function(item){return html `<li ><p>${item[0]}</p><img src="https://image.tmdb.org/t/p/w500/${item[1]}">
        <button @click=${this.mostrarResumen}>Mostrar resumen</button></li>`} )}
      </ol>
    </div>
    <button class="buttonsPage2">></button>
    </div>
    `;
}

La consola muestra un error:

  Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'mostrarResumen')

Por supuesto la función mostrarResumen si esta definida fuera de render.

  • ¿Existe alguna alternativa para utilizar el evento?
  • ¿Se pueden usar eventos con esta lógica?

Muchas gracias :)

Respuestas

Hola,

Tu problema no son los eventos, ni siquiera Lit.

El tema que te ocurre es que this es una referencia que cambia de significado en Javascript según donde la estés usando. Deberías informarte sobre cómo funciona this en Javascript para aclararte, ya que si no, vas a sufrir muchos problemas al usar el lenguaje.

En resumen this en una función normal (declarada con function) en Javascript apunta al contexto de la función. Por favor, lee esto: La palabra this y el contexto en Javascript.

Para solucionar tu código tendrías varias alternativas, pero lo que hacemos en Lit es usar funciones flecha en lugar de funciones creadas con function. Por eso verás que todo el código del manual de Lit usa funciones flecha en los map() de los templates. No es por simple capricho.

Cómo usar una función de flecha en lugar de una función normal

Lo bueno de las funciones de flecha es no crean su propio contexto en la referencia this, sino que lo heredan del contexto en el que fueron definidas, en este caso el propio componente donde estás escribiendo el método render().

El código para que tu map use una función de flecha sería este: (pero por favor no te limites a copiar y pegar, entiende el problema y el por qué de la solución, si no, vas a frustrarte mucho cuando programes en Javascript)

render() {
  return html`
    <div id="globalContainer">
      <button class="buttonsPage1"><</button>
      <div id="containerMovies">
        <ol id="listMovies">
          ${this.path.map((item) => html`
            <li>
              <p>${item[0]}</p>
              <img src="https://image.tmdb.org/t/p/w500/${item[1]}">
              <button @click=${this.mostrarResumen}>Mostrar resumen</button>
            </li>
          `)}
        </ol>
      </div>
      <button class="buttonsPage2">></button>
    </div>
  `;
}

Esto resolverá el problema del contexto this de una manera hiper sencilla y además hace tu código más compacto y legible.

Además, si en ese ejemplo necesitases pasar item como argumento a mostrarResumen, para usar los datos relevantes del elemento en el método, podrías hacer algo como esto.

render() {
  return html`
    <div id="globalContainer">
      <button class="buttonsPage1"><</button>
      <div id="containerMovies">
        <ol id="listMovies">
          ${this.path.map((item) => html`
            <li>
              <p>${item[0]}</p>
              <img src="https://image.tmdb.org/t/p/w500/${item[1]}">
              <button @click=${() => this.mostrarResumen(item)}>Mostrar resumen</button>
            </li>
          `)}
        </ol>
      </div>
      <button class="buttonsPage2">></button>
    </div>
  `;
}

Suerte en tu aprendizaje!!

Miguel Angel
3320 147 216 17