Вызов Scala. js кода из собственного обработчика Javascript - PullRequest
3 голосов
/ 28 февраля 2020

У меня есть приложение Scala. js, использующее Уда sh. Приложение использует некоторые Bootstrap расширения, которые напрямую манипулируют HTML DOM. Я хотел бы пройтись по этому DOM и добавить к нему еще несколько обработчиков (в конце концов я бы хотел, чтобы обработчики реализовали Uda sh binding ). Моя проблема в том, что я могу это сделать только путем вставки тега script, который ожидает от меня предоставления простого кода Javascript.

Есть ли способ, которым я мог бы позвонить по Scala. js код из этого Javascript? Обычно я экспортирую глобальную функцию и передаю ей все необходимые параметры, однако я не вижу четкого способа передачи this, единственный способ, которым я могу придумать, - это использовать глобальную переменную, которая выглядит мне безобразно. Есть ли что-то вроде локального экспорта или каким-либо другим способом, как создать код JavaScript, который я мог бы передать в script, который мог бы получить доступ к конструкциям Scala. js?

Мой текущий код выглядит так:

// somewhere in class ExtTable .. in the `render` method
    div(
      p(id := componentId, "Html constructed here"),
      script {
        ExtTable.callback = { e =>
          println(s"JS Callback for $e on $this")
        }
        //language=JavaScript
        s"""
        // I would like to implement this in Scala.js instead
        var t = $$('#${componentId.toString}');
        t.bootstrapTable();
        t.find("tr td:first-of-type").each(function(i,e){
          ExtTable.callback(e);
        })
        """
      }
    ).render
@js.annotation.JSExportTopLevel("ExtTable")
object ExtTable {
  @js.annotation.JSExport
  var callback: js.Function1[Element, Unit] = _
}

1 Ответ

1 голос
/ 28 февраля 2020

ПЕРЕВОДИТЕ СВОЙ НАКЛОНЕНОК SCALAJS

Вам необходимо использовать библиотеку jquery. Уда sh имеет свою собственную ... Я использую самую старую ( здесь ) (пример ниже).

import org.scalajs.jquery.jQuery
import org.scalajs.dom.Element
import scala.scalajs.js

@js.annotation.JSExportTopLevel("ExtTable")
object ExtTable {
  @js.annotation.JSExport
  var callback: js.ThisFunction0[Element, Unit] = _ //look first argument is what `this` in js means
}

var t = jQuery("#"+componentId.toString);
t.asInstanceOf[js.Dynamic].bootstrapTable(); //to call function that is not known statically!
t.find("tr td:first-of-type").each( { (e: Element) =>
  ExtTable.callback(e)
})
  • Чтобы покрыть функцию с this в теле, вам нужно использовать js.ThisFunction (подробнее здесь ). В приведенном выше примере .each(...) принимает ThisFunction1[Element,_], и это означает, что this из javascript будет нашим первым аргументом (e:Element в приведенном выше коде). Как вы можете видеть, он выводится из обычной scala закрывающей нотации ({(e: Element) => ...}).
  • странная .asInstanceOf[js.Dynamic] часть необходима здесь для вызова функции на jquery объекте, который происходит из jquery addon. js.Dynamic - это специальный тип, который можно вызывать любым методом, и компилятор просто переведет его на тот же вызов на js сайте ( do c). Вы можете понимать это как "Поверь мне ... будет такой метод во время выполнения". Создатель jquery фасадов не может предположить, какие надстройки вы бы использовали, и вам нужно создать свои собственные фасады или использовать его динамически, как показано выше.

ФУНКЦИЯ ВЫЗОВА НА ЭЛЕМЕНТЕ, СОЗДАННОМ СКАЛАТАГАМИ

Вы также можете создать Модификатор, который будет вызывать ваш код при создании объекта. Имейте в виду, что он будет вызван до того, как элемент будет введен в dom :

import scalatags.JsDom.all._
import org.scalajs.jquery.jQuery
import org.scalajs.dom.Element
import scala.scalajs.js
import scalatags.JsDom.Modifier

val bootstrapTable:Modifier = new Modifier {
    override def applyTo(t0: Element): Unit = {
      val t = jQuery(t0)
      t.asInstanceOf[js.Dynamic].bootstrapTable()
      t.find("tr td:first-of-type").each(i => {
        ExtTable.callback(e)
      })
  }
//in scala 2.12 you can write it simpler
val bootstrapTable2:Modifier = (t0: Element) => {
      val t = jQuery(t0)
      ...
  }

div(p(
  id := "componentId", 
  "Html constructed here",
  //use modifier here,
  bootstrapTable,
  //you can create new anonymous modifier here: 
  new scalatags.JsDom.Modifier {
    override def applyTo(t: Element): Unit = println("ex1:" + t.outerHTML)
  }
  //in scala 2.12+ you can do it like that (same semantic as above example)
  (e:Element) => println("ex2:" +e.outerHTML)
)).render
  • Здесь вам не нужно использовать jQuery("#" + componentId), потому что у вас есть доступ к Element ( jQuery(t0)).
  • scala SAM 2.12 делает это еще проще, как вы можете видеть. Вы можете создать экземпляр Модификатора, используя обозначение замыкания.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...