Should be using `target` rather than `srcElement` in Scala.js

358 Views Asked by At

I have some Scala.js code which works fine when the target-browser is Chrome but not when it is Firefox. I have been told that I should not use srcElement but instead target. However I can't work out how to access target.

private def TD(locId: Location, personId: Person): HTMLTableCellElement = {
  val res = td(style := myPeopleTable_td).render
  res.onclick = { (e: dom.Event) => c.clickTD(e.srcElement)}
  res.id = Id(locId, personId).toString
  cells += (Id(locId, personId) -> res)
  res
}
def clickTD(element: Element): Unit = {
  val idOption = Id.parse(element.id)
  idOption.foreach(id => {
    locIdx = Location.indexOf(id.locId)
    personIdx = Person.indexOf(id.personId)
    localSync()
    v.personValueBox.focus()
  })
}

By way of explanation c is the Controller and v is the View. The first method is in the View and and second is in the Controller. The first method is setting up a cell in an HTML table, including what happens when the user clicks on the cell. In clickTD() the code needs to know what has been clicked - it needs to somehow get at the HTML element's 'id' which has been pre-set so that model objects can be looked up.

If I try to replace e.srcElement with e.target this is the result:

[info] Compiling 1 Scala source to C:\dev\v2\atmosphere\js\target\scala2.11\classes...
[error] C:\dev\v2\atmosphere\js\src\main\scala\simple\View.scala:145: type mismatch;
[error]  found   : org.scalajs.dom.raw.EventTarget
[error]  required: org.scalajs.dom.Element
[error]     (which expands to)  org.scalajs.dom.raw.Element
[error]     res.onclick = { (e: dom.Event) => c.clickTD(e.target)}
[error]                                                   ^
[error] one error found
[error] (atmosphereJS/compile:compile) Compilation failed
[error] Total time: 1 s, completed 15-Jun-2015 02:14:41

Thanks @ochrons, your suggestion of putting res instead of e.target works. Unfortunately with the other controls I'm having an 'order of instantiation' problem. In the following I am trying to move the commented-out line to where it can see res:

private def button_TD_Tog(idT: Row): HTMLTableCellElement = {
  val idsStr: String = idT.toString
  val buttonWidget = button(
    style := myToggleButton, 
    name := "button", 
    id := idsStr
    //onclick := { (e: dom.Event) => c.clickToggleButton(e.srcElement)}
  )
  val res = td(style := myToggleButtonCol, buttonWidget).render
  buttonWidget.onclick = { (e: dom.Event) => c.clickToggleButton(res)}
  res.id = idsStr
  buttonTDs += (idT -> res)
  res
}

I (think I) need both res and buttonWidget to exist before assigning to onclick, but the compiler does not recognize onclick. I found myself searching for some API documentation to help me out here. I doubt that it exists (I've found Scala.js documentation to be excellent, but not comprehensive). Perhaps I should be looking to the DOM itself...

And so now to an example of a simple general solution that seems to work for all cases, as per your advice to force types:

c.clickPushButton(e.target.asInstanceOf[dom.Element])}
1

There are 1 best solutions below

0
On BEST ANSWER

If you only need to know that your td element has been clicked, then you can directly use c.clickTD(res) in the closure. But if there are elements within the td that can be clicked, then you can use the event's target by just casting it as an Element. In such case your inner elements must bubble the click event up to the td element.

The DOM is not entirely type-safe, so sometimes you just need to "know" what you are dealing with. The documentation typically assumes JavaScript, so they don't really care about things like type-safety.