2

Get an UndefinedBehaviorError when using a parameter of type case class in an scalajs method which I handover from a play framework Scala/Twirl template view/notify.scala.html:

@(note: Notification, ...)(implicit ...)
<!DOCTYPE html>
<html>
  <body>
    ...
    <script type="text/javascript" charset="utf-8">
      CommandsJS.notify('@note');
    </script>
  </body>
</html>

Here the case classes:

abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification

and the method defined in ScalaJs:

@JSExport
def notify(notification: Notification): Unit = {    
...
  notification match {
    case Email(email, title, _ )    => log.info(s"Email: $email")
    case SMS(number, message)       => log.info(s"SMS: $number")
  }
}

The case class gets instantiated in the controller:

class AppCtrl ... {

  def sendNote = silhouette.UserAwareAction { implicit request =>
    Ok(views.html.notify(SMS("John","hi John"), ...))
  }
}

Get runtime error within javascript console: An undefined behavior was detected: SMS(John,hi John) is not an instance of Notification. Any help/workaround appreciated - thanks

RobertJo
  • 121
  • 1
  • 10

1 Answers1

2

The short answer is: you can't do that.

You're rendering this Play template on the server, passing in the Notification. You can't just embed the Notification in the JavaScript code, which is what you're doing here:

  CommandsJS.notify('@note');

and expect it to work. That isn't a Notification -- it's a JavaScript String (containing the value of note.toString, which is getting automatically called by the way you're using it in the template), which is why you're getting the error that you are seeing.

To make this work, you'd have to serialize the Notification (as JSON or something) before you pass it into the template, embed that as the String value, and then deserialize it inside notify() on the client side. I do that occasionally, and it's a bit of a hassle, but there's nothing for it -- you can't just pass strongly-typed Scala objects from the server to the client through the template like this...

Justin du Coeur
  • 2,699
  • 1
  • 14
  • 19
  • Thanks for the feedback, serialisation as JSON works. Nevertheless I think it would be a good idea if the twirl template engine and/or Scalajs compiler could generate code making parameter passing possible and typesafe. – RobertJo Jul 18 '18 at 19:21
  • In an ideal world, I agree. In practice, though, Twirl and Scala.js are pretty completely decoupled from each other; there isn't even any overlap in the people working on them, AFAIK. I think this is one of those projects that is only going to happen if somebody decides to take the bull by the horns and make those enhancements... – Justin du Coeur Jul 19 '18 at 23:32