Activar JavaScript al hacer clic en cualquier enlace de la página, pero antes de que cargue el contenido de la página

Hola.
Cuando cambiamos de página en Discourse, estos son los pasos aparentes:

  1. Hacemos clic en el enlace
  2. El contenido actual desaparece y aparece el indicador de carga
  3. Se actualiza la URL y aparece el nuevo contenido

Esto es ligeramente diferente cuando vamos de una página a la página de inicio, ya que la URL cambia a la URL de inicio cuando el contenido actual desaparece, y no cuando aparece el nuevo contenido.

Mi objetivo es tener un script que se ejecute tan pronto como hacemos clic en cualquier enlace de página en Discourse.
api.onPageChange no sirve en este caso, ya que el código se ejecuta casi al mismo tiempo que se carga el contenido de la nueva página.

¿Existe algún método en Discourse para esto? He revisado los desencadenadores de eventos, pero no he encontrado ninguno que se ajuste a lo que necesito.

1 me gusta

Hola :wave:

Actualmente no hay ningún método en la Plugin-API que permita ejecutar un script antes de una transición de página, ya que, hasta donde recuerdo, esto no se había planteado antes.

Dicho esto, puedes aprovechar la acción willTransition() en la ruta de la aplicación:

En tu tema o componente, podrías usar algo así:

// esto se ejecuta después de la transición
api.onPageChange((url, title) => {
  console.log("después de la transición");
});

// esto se ejecuta justo antes de la transición
api.modifyClass("route:application", {
  pluginId: "some-name",
  actions: {
    willTransition() {
      // ejecutar primero el código principal
      this._super(...arguments);
      // luego realizar algunas tareas
      console.log("antes de la transición");
      // también puedes hacer algo como esto para ver qué datos tienes disponibles
      // para trabajar, como _router
      console.log(this)
    }
  }
});
6 Me gusta

Exactamente lo que necesitaba. ¡Gracias!

2 Me gusta

Esto no parece activarse al entrar en un Tema desde una Lista de Temas.

También he intentado añadir uno:

      api.modifyClass("route:topic", {
        pluginId: PLUGIN_ID,
        actions: {
          willTransition() {

pero tampoco se activa.

Un par de razones por las que podría no estar funcionando:

  1. Poner acciones en un hash es una sintaxis antigua que ya no usamos en Discourse. Teóricamente debería funcionar, pero la interoperabilidad con la nueva sintaxis podría no ser perfecta. La forma moderna sería

    api.modifyClass("route:application", (Superclass) => class extends Superclass {
      @action
      willTransition() {
        console.log("hacer algo");
        super.willTransition(...arguments);
      }
    });
    

    se aplica el descargo de responsabilidad estándar de modifyClass: esto es arriesgado y podría romperse en cualquier momento

  2. No creo que willTransition esté garantizado que se active en la ruta de la aplicación en todas las situaciones. (por ejemplo, si una ruta hija tiene una acción willTransition, no necesariamente se propagará)

    Recomendaría usar los eventos en el servicio del enrutador de Ember en su lugar: RouterService | 5.12.0 | Ember API Documentation
    por ejemplo, algo como

    const router = api.container.lookup("service:router");
    router.on("routeWillChange", () => {
      console.log("route will change se activó");
    });
    
2 Me gusta

¡Genial, gracias David, lo intentaré la próxima vez!

Esta investigación se activó (ejem) porque necesitaba una forma de disparar algo en cada cambio de página, y antes de Render.

Al parecer, el evento de la API de cambio de página no garantiza que se active antes de que se rendericen los elementos de la página.

1 me gusta

Creo que te costará hacerlo perfectamente. Ember espera tener el control total de la renderización, por lo que intentar engancharse en puntos arbitrarios será difícil y puede causar problemas (dependiendo de lo que estés intentando hacer).

Obviamente, no sé cuál es tu objetivo final… así que tal vez el dolor esté justificado. En ese caso: siéntete libre de ignorarme :wink:

(por supuesto, si te gustaría abrir un tema de Dev sobre el problema que estás intentando resolver, con gusto le echaré un vistazo)

Encantado de ser explícito ya que el código es de código abierto:

Estoy trabajando con un proveedor de anuncios externo y tienen una función de reinicio de página de anuncios en javascript que necesita ejecutarse antes de que se activen los anuncios de la nueva página.

Cualquier mejora es bienvenida y ya me he dado cuenta de esto en la Lista de Temas con el código de Johani. (en un PR abierto).

Pero esto dejó el Tema… Intentaré tu sugerencia a continuación y la adoptaré en ambos casos si eso mejora aún más las cosas.

Ya veo, así que no estás modificando el DOM directamente :ok_hand:

En ese caso, espero que routeWillChange funcione; ciertamente debería activarse antes de que se renderice la siguiente ruta.

La advertencia es que… en el caso de cosas como redirecciones, puede activarse dos veces. O puede activarse y luego la transición termina siendo abortada. Pero tal vez eso esté bien en este caso.

2 Me gusta

Sí, nada de esa perversa modificación directa del DOM por aquí en Merefield Technology Towers. :sweat_smile:

Sí, usaré el servicio, ¡para eso está! Te informaré de mi experiencia, ya que estoy seguro de que los resultados podrían interesar a otros.

3 Me gusta

Así que sí, eso se limpia y las cosas ahora ocurren en el orden correcto en ambas rutas.

:rocket:

¡Gracias por tu ayuda!

2 Me gusta