27

Here is an example from the Hands-on Scala.js ebook:

package webpage

import org.scalajs.dom.ext.Ajax

import scala.scalajs.js
import scala.scalajs.js.annotation.JSExport
import scalatags.JsDom.all._
import org.scalajs.dom
import dom.html

@JSExport
object HelloWorld1 extends {
  @JSExport
  def main(target: html.Div) = {

    lazy val box = input(
      `type`:="text",
      placeholder:="Type here!"
    ).render

    lazy val output = div(
      height:="400px",
      overflowY:="scroll"
    ).render

    box.onkeyup = (e: dom.Event) => {
      output.innerHTML = "Loading..."
      fetchWeather(box.value)
    }

    target.appendChild(
      div(
        h1("Weather Search"),
        p(
          "Enter the name of a city to pull the ",
          "latest weather data from api.openweathermap.com!"
        ),
        p(box),
        hr, output, hr
      ).render
    )

    def fetchWeather(query: String) = {
      val searchUrl =
        "http://api.openweathermap.org/data/" +
          "2.5/find?type=like&mode=json&q=" +
          query

      for{
        xhr <- Ajax.get(searchUrl)
        if query == box.value
      } js.JSON.parse(xhr.responseText).list match{
        case jsonlist: js.Array[js.Dynamic] =>
          output.innerHTML = ""
          showResults(jsonlist, query)
        case _ =>
          output.innerHTML = "No Results"
      }
    }
    def showResults(jsonlist: js.Array[js.Dynamic], query: String) = {
      for (json <- jsonlist) {
        val name = json.name.toString
        val country = json.sys.country.toString
        val weather = json.weather.pop().main.toString

        def celsius(kelvins: js.Dynamic) = {
          kelvins.asInstanceOf[Double] - 273.15
        }.toInt

        val min = celsius(json.main.temp_min)
        val max = celsius(json.main.temp_max)
        val humid = json.main.humidity.toString
        val (first, last) = name.splitAt(query.length)
        output.appendChild(
          div(
            b(span(first, backgroundColor:="yellow"), last, ", ", country),
            ul(
              li(b("Weather "), weather),
              li(b("Temp "), min, " - ", max),
              li(b("Humidity "), humid, "%")
            )
          ).render
        )
      }
    }
  }
}

Got an error when compiling:

[info] Compiling 1 Scala source to /Users/kaiyin/personal_config_bin_files/workspace/workbench-example-app/target/scala-2.11/classes...
[error] /Users/kaiyin/personal_config_bin_files/workspace/workbench-example-app/src/main/scala/HelloWorld1.scala:51: Cannot find an implicit ExecutionContext. You might pass
[error] an (implicit ec: ExecutionContext) parameter to your method
[error] or import scala.concurrent.ExecutionContext.Implicits.global.
[error]         if query == box.value
[error]                  ^
[warn] /Users/kaiyin/personal_config_bin_files/workspace/workbench-example-app/src/main/scala/HelloWorld1.scala:53: non-variable type argument scala.scalajs.js.Dynamic in type pattern scala.scalajs.js.Array[scala.scalajs.js.Dynamic] is unchecked since it is eliminated by erasure
[warn]         case jsonlist: js.Array[js.Dynamic] =>
[warn]                           ^
[warn] one warning found
[error] one error found
[info] workbench: Checking example-fastopt.js
[info] workbench: Checking webpage-fastopt.js
[error] (compile:compile) Compilation failed
[error] Total time: 0 s, completed 7 sept. 2015 12:51:38
78. Waiting for source changes... (press enter to interrupt)

What went wrong here?

qed
  • 22,298
  • 21
  • 125
  • 196

2 Answers2

73

As the error suggests, add the following imports:

import scala.concurrent._
import ExecutionContext.Implicits.global
  • 2
    I believe the first half of the answer is correct (IIRC, `scala.concurrent.ExecutionContext.Implicits.global` is aliased to `scala.scalajs.concurrent.JSExecutionContext.queue`, which is what you want), but the second half isn't. Remember, this is a Scala.js question -- no such thing as thread pools, or threads for that matter. It's a single-threaded execution engine, so it's a much simpler environment... – Justin du Coeur Sep 15 '15 at 16:20
  • @JustinduCoeur, I am not familiar with Scala.js. In any case, it doesn't make sense. The default thread execution environment provided by importing the implicit is that of a forkjoinpool with the number of threads primed equal to the number of processors on the machine. So if that is not the semantics required then the first part is wrong as well. Feel free to edit the answer completely to what you think should be right answer. –  Sep 15 '15 at 18:04
  • 1
    Scala.js is a reimplementation of the Scala runtime, to run on JavaScript instead of on the JVM. The only thread execution environment available is a special single-threaded one, since JavaScript is fundamentally single-threaded -- things like fork/join pools are non-sequiteurs, because they're peculiar to the JVM. *Syntactically*, you still need to add the import of an ExecutionContext, to keep the Scala compiler happy, but there is only one legitimate definition of it... – Justin du Coeur Sep 16 '15 at 15:57
  • @JustinDuCoeur That last bit is actually not 100% correct. In newer JS environments that provide JavaScript promises, an execution context has a choice between using the promise event loop (tight loop) or the setTimeout event loop (UI event loop). – gzm0 Aug 08 '16 at 16:27
  • Downvoting until the second part of the question is fixed. – gzm0 Aug 08 '16 at 16:27
  • Thanks for the fix. – gzm0 Aug 08 '16 at 16:31
0

I was using "import net.kaliber.mailer._" for sending email using Scala. And getting "no implicits found for parameter ec:" error. After importing below 2 libraries, that issue is resolved.

import scala.concurrent._

import ExecutionContext.Implicits.global
Martyns
  • 3,605
  • 22
  • 33
  • 1
    You are not importing two libraries, just one object. Your two lines are equivalent to `import scala.concurrent.ExecutionContext.Implicits.global` – smac89 Sep 11 '19 at 02:00