Scala.js TypeError: $g.DOMParser is not a constructor - scala.js

I'm new to Scala.js and I'm just trying to write a test that will parse some html files. I'm trying to create a DOMParser:
val parser = new DOMParser
But I get the following error
scala.scalajs.js.JavaScriptException: TypeError: $g.DOMParser is not a constructor
DOMParser is defined as
#js.native
class DOMParser extends js.Object {
def parseFromString(source: String, mimeType: String): Document = js.native
}
Thank

After reading around, it looks like I needed to do this
val parser = js.Dynamic.global.DOMParser
If anyone can explain why, that would be appreciated :)

Try using val parser = new DOMParser(), the () is required for constructor to work properly. There is no need to use js.Dynamic in this case

Related

Setting parameters in scala classes

I am trying to get familiar with classes in Scala(spark) and I wrote a simple wrapper class over XGBoostClassifier to experiment with. Once that wrapper class was ready, I tried setting some parameters but I am getting errors and can't find much help online
This is the class I am using
class trialXGBClassifier{
var xgb_cls_object: XGBoostClassifier = _
}
I also wrote a small utility function to convert JSON to a Map (string, string)
def jsonToMap(jsonString: String): Map[String, String] = {
val jsonMap = JSON.parseFull(jsonString).get.asInstanceOf[Map[String, String]]
return jsonMap
}
And this is the code that's giving me the error
var params = """{"numRound": "10"}"""
var trial_xgb = new trialXGBClassifier
trial_xgb.xgb_cls_object.setSeed(jsonToMap(params)("numRound").toLong)
This is the error message I get
java.lang.NullPointerException
... 61 elided
I tried doing the following using the actual ml.dmlc class and it works
var xgb_orig = new XGBoostClassifier
xgb_orig.setSeed(jsonToMap(params)("numRound").toLong)
xgb_orig.getSeed #10
Whats the reason behind this error and how do I fix this?
In Scala, people try to use val instead of var in all places where such usage possible. Also, they try to use case class or sealed trait instead of just class.
So, there's a very nice way to avoid such kind of issues using case class:
case class TrialXGBClassifier(xgb_cls_object: XGBoostClassifier)
And then the best option to use your wrapper only when you have something to wrap:
val xgb_orig = new XGBoostClassifier
xgb_orig.setSeed(jsonToMap(params)("numRound").toLong)
val v = TrialXGBClassifier(xgb_orig)
And you even can omit xgb_orig declaration:
val v = TrialXGBClassifier(new XGBoostClassifier)
v.xgb_cls_object.setSeed(jsonToMap(params)("numRound").toLong)

How do I use Scala-Meta Parse an object?

I am trying to use Scala Meta to write an annotation so I can generate another case class from an existing object.
But when I try to do this:
MyObject.parse[Source].show[Structure]
I got this error:
Error:(5, 20) not enough arguments for method parse: (implicit convert: scala.meta.common.Convert[domain.MyObject.type,scala.meta.inputs.Input], implicit parse: scala.meta.parsers.Parse[scala.meta.Source], implicit dialect: scala.meta.Dialect)scala.meta.parsers.Parsed[scala.meta.Source].
Unspecified value parameters convert, parse, dialect.
MyObject.parse[Source].show[Structure];}
^
I am very confused because based on their tutorial, that's what I need to start with
http://scalameta.org/tutorial/#.parse[T]
How can I reflect this object to loop through all properties?
Thanks
parse[Source] parses text. You may try the following
import scala.meta._
"object MyObject".parse[Source].get.show[Syntax]
If you are creating annotation then it might look like:
#MyAnnotation
object MyObject
And in another module:
import scala.meta._
class MyAnnotation extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn.show[Syntax]
defn
}
}

JavaScript object as function parameter

I'm writting a function transpiled with Scala.js that should accept any random JavaScript object.
Ex:
// This has been transpiled using Scala.js
var my_service = new com.myself.Service();
// This is plain JavaScript
var result1 = service({ hello: "yolo" });
var result2 = service({ whatever: "ok", really: { yes: "right", no: "don't" } });
However, I can't find the input type that matches it.
What would be the Scala-function signature to get such a thing?
Could it be used then as a "Scala/JS case class" easily?
Note (if it helps giving a direction for the answers): these objects have, in the real life, an expected schema but it cannot be created as JS object generated from Scala.js since it comes from another consumed service.
Since the objects have an expected schema, its probably easiest to define a facade type:
#js.native
trait Args extends js.Object {
val hello: js.UndefOr[String]
val whatever: js.UndefOr[String]
val really: js.UndefOr[ReallyArgs]
}
#js.native
trait Really extends js.Object {
val yes: String
val no: String
}
def myMethod(args: Args): Unit = {
println(args.hello)
println(args.really.map(_.yes))
}

Scala implicit conversion not recognised

I have the following object for making a conversion of an object ParsedItemDocument to a json String. I should note that ParsedItemDocument is a trait. My problem is that the implicit conversion that is called on the second snippet is not recognized by the compiler. Is there anything more that needs to be done for the implicit conversion to work?
import scala.language.implicitConversions
import wikidataParser.ParsedItemDocument
object Converters {
def toJson(obj: Any): String = {
val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
val out = new StringWriter
mapper.writeValue(out, obj)
return out.toString()
}
implicit def parsedItemDocumentToJsonString
(item: ParsedItemDocument): String = {
Converters.toJson(item)
}
}
Now, I use the following code-snippet in my code
import tools.Converters._
import wikidataParser.ParsedItemDocument
class WikipediaRankingTester2 extends FlatSpec {
"It" should "do something" in {
val jsonrdd:RDD[String]=rankedItems.map(t:Long,ParsedItemDocument)=>
t._2.parsedItemDocumentToJsonString)//compilation error here
}
}
You are mixing up implicit conversions and implicit classes.
If you want to use parsedItemDocumentToJsonString as a "method" of an object of type ParsedItemDocument, then you would need to define your implicit as
implicit class JSONParsing(item: ParsedItemDocument): String {
def parsedItemDocumentToJsonString = Converters.toJson(item)
}
If you declare it as an implicit conversion, as you did, then it means that you can call any methods of String on an object of type ParsedItemDocument, as the object will be implicitly converted to a String through the implicit method.
Also, it is not great practice to declare an entire implicit class / conversion, unless you 1) cannot add it to the original class, or 2) will be reusing the conversion very often, and it would save great amounts of code/readability. This does not seem to be the case here, as you are only wrapping in Converters.toJSON, which is not very verbose, and jsut as readable.
PS: your syntax in your "map" is wrong, the right syntax would be
val jsonrdd = rankedItems.map(t => t._2.parsedItemDocumentToJsonString)
If your implicit is working this should do it:
rankedItems.map(t => t._2)
You can test this by making the call explicit
rankedItems.map(t => parsedItemDocumentToJsonString(t._2))
If you want to add an extra method to a ParsedItemDocument you could use an implicit class, I don't think you need it but your code looks a bit that way.

Dynamic calls to JavaScript in Scala.js

I am wondering how to do dynamic operations in Scala.js. For example, looking at the jQuery example in the tutorial, my understanding is you define the following in scala:
object TutorialApp extends JSApp {
def appendPar(msg: String) = {
jQuery("body").append("<p>" + msg + "</p>")
}
def main(): Unit = {
appendPar("Hello World")
}
}
This is all stuff that is generated statically at compile time. But I didn't see any way I could set the message parameter dynamically (eg read it from a DB).
I don't know about reading it from the DB. That is beyond the scope of this question (or you need to rephrase the question). Maybe an AJAX call or something?
But to read it from, for example, an <input> tag, you'd do something like that:
def main(): Unit = {
val msg = jQuery("#myinput").value()
appendPar(msg)
}
(Although in this case it probably doesn't make any sense in a main method, but that's not the point.)
I mean, msg is just a val (so like a var in JS but immutable). You can fetch it from any dynamic source of information as you like.
Edit:
If you want to access some data generated dynamically by the server when rendering the page, you can do so like this:
First, have your server generate the data as a global var in a <script> tag in the generated HTML. Something like:
<script type="text/javascript">
var mydata = {
msg: "Some text generated dynamically by the server"
}
</script>
Make sure to emit this script tag before the call to the main() function of Scala.js!
Then, from Scala.js, you can access these data with the js.Dynamic interface:
import scala.scalajs.js
val mydata = js.Dynamic.global.mydata
val msg = mydata.msg.asInstanceOf[String]
If your data have always a relatively static structure, it may be useful to declare yourself a facade type for them:
#JSName("mydata")
object MyData extends js.Object {
val msg: String = ???
}
Then you can access it without resorting to the Dynamic API:
val msg = MyData.msg
Adding to (and attempting to generalize) sjrd's answer: To call a javaScriptMethod on an object of a JavaScriptType you first write a type facade for it:
import scala.scalajs.js
import scala.scalajs.js.annotation.JSName
#js.native
#JSName("JavaScriptType")
class MyType() extends js.Object {
def javaScriptMethod(someParam: String) = js.native
}
After that, it's a piece of cake to use the JavaScript code using Scala on the client side:
val myObject = new MyType()
myObject.javaScriptMethod("Yippie")
As a concrete example, to use Stack Overflow's Markdown converter Pagedown in your Scala.js application you'd first create the type facade for it:
#js.native
#JSName("Markdown.Converter")
class MarkdownConverter() extends js.Object {
def makeHtml(txtUsingMarkdown: String): String = js.native
}
If you are learning Scala.js using this great tutorial project, you can declare the dependency on Pagedown in Settings.scala like this:
val jsDependencies = Def.setting(Seq(
"org.webjars.bower" % "pagedown" % "1.1.0" / "Markdown.Converter.js",
//...
Then you can simply do
val html = new MarkdownConverter().makeHtml("this is *nice*")
Here's another example where we call a static method of SparkMD5.
We define an object as opposed to the class of the previous example. Also, we can omit the #JSName annotation since our Scala type is eponymous with the JavaScript type:
#js.native
object SparkMD5 extends js.Object {
def hash(str: String, raw: Boolean = false): String = js.native
}