How to invoke 3rd party javascript from scala-js? - scala.js

I need help initializing a native JS var from within a scalajs app (specifically a scalajs-react app). Fundamentally, I'm trying to use Bootstrap Responsive data-tables and I need to initialize a data table by getting the element of the data table in my HTML via a call to dom.getElementById which will be of type DataTable and then I need to initialize like this:
$(document).ready(function() {
$('#example').DataTable();
} );
I've been staring at the #js.native stuff and can't quite figure out how to make the connection to that native JS. Any help would be greatly appreciated. For reference, the link to the native javascript of the responsive data-table is here. An additional question for those with a scalajs-react background (are you there #japgolly?) is whether or not the best place to make this data-table initialization invocation should be in the ReactComponentB.componentDidMount() method?

The simplest way to set up the data table is by doing so using the dynamic API:
dom.document.getElementById("example").asInstanceOf[js.Dynamic].DataTable()
Of course you need to do so only once the document is loaded. You can use scala-js-jquery to do so:
jQuery(dom.document).ready(() =>
dom.document.getElementById("example").asInstanceOf[js.Dynamic].DataTable()
)
If you would like to have a nicer (and typesafe) invocation of DataTable, you can follow the Monkey Patching Guide (sorry no anchor, search for the term):
#js.native
trait DataTableElement extends dom.Element {
def DataTable(): Unit = js.native
}
object DataTableElement {
implicit def element2dataTableElement(e: dom.Element): DataTableElement =
{
e.asInstanceOf[DataTableElement]
}
}
You now won't need the cast anymore:
dom.document.getElementById("example").DataTable()
And:
jQuery(dom.document).ready(() =>
dom.document.getElementById("example").DataTable()
)

Related

binding.scala component to string conversion

I have a binding.scala component and a third party scalajs library that takes html string as input. How can the b.s component can be passed to the library method as an argument?
Specifics:
import com.thoughtworks.binding.Binding._
import com.thoughtworks.binding.{Binding, dom}
#dom def renderComponent: Binding[Element] = <h1> I am a component </h1>
def thirdPartyFunction(str: String) = {
...
}
I would like to call the function like thirdPartyFunction(renderComponent.bind.outerHtml.toString).
However that call never gets executed.
I think this is related to some basic understanding with B.S up until now I have not faced with. Any suggestions?
The answer is to wrap the .bind call with watch. For instance, in the window.onload function, something similar to the following:
window.onload = _ => Binding{
thirdPartyFunction(renderComponent.bind.outerHtml.toString)
}.watch()
Note that it is possible to initialize components without functions like window.onload. See this question How to execute some init after element loaded to dom with Binding.scala

How to properly pass many dependencies (external APIs) to a class in Scala?

How to properly pass many dependencies (external APIs) to a class in Scala?
I'm working on the application that uses many APIs to collect data. For API's I have trait like below.
trait api {
def url: Foo
def parse: Bar
}
Also, there are about 10 implementations of the api trait (one for each API). Inside a parent actor, I want to create a child actor for every external API. I created new trait and implementation,
trait ExternalApis {
val apiList: List[api]
}
object MyApis extends ExternalApis {
val apiList = List(new ApiImpl1, ..., new ApiImpl10)
}
so now I can pass MyApis object (or any other implementation of ExternalApis) to parent actor and map over apiList for creating such child actors.
It seems to me I'm missing something. Are there more proper ways to do it?
The implementation that you have made looks nearly ready. Just something I would like to add are:
Passing an API List may not be the most ideal way to do such a thing. Anytime you would like to add/remove something to the API list, you would have to change different areas of the code. A suggestion would be to read this from a config folder, where the config folders would contain things such as url, username, password etc.
If you could provide more insight on the usage of these API's, it would help my answer a lot.
Hope this helped!

Scala-js - Navigator.oscpu

Can you advice me how to get Navigator.oscpu using Scala-js? Mapping to native Navigator does not seems to have the oscpu.
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/oscpu
This appears to be a Firefox-only feature (based on a quick look around), so it's not supported by Scala.js out of the box. You'll need to add it yourself, by adding a side-facade to Navigator. This isn't terribly hard -- see the definition of BeaconNavigator for an example of how to do this.
So you would need something like (untested):
#js.native
trait OSCPUNavigator extends js.Object {
def oscpu: String = js.native
}
implicit def toOSCPUNavigator(n: Navigator): OSCPUNavigator =
n.asInstanceOf[OSCPUNavigator]
Basically, you define a trait with oscpu on it, and you tell Scala.js how to see a Navigator as that trait.
Mind, though, it'll still only work on Firefox. I suspect it'll throw errors on other browsers...

Scala/Play: access current url in a model

I have a simple Play application in which I need to check url being called and use different database accordingly. I know that it's easy to access current url in the controller, but for this to work I need to access it in the model.
Passing the url from controller to each call of a model method would be too big of an inconvenience. Is there any other way to solve this problem?
Play Framework 2.2.1 / Scala 2.10.3
UPDATE: This is my basic example
Controller (Application.scala):
package controllers
import play.api._
import play.api.mvc._
import models.Data
object Application extends Controller {
def index = Action {
//Call to model method - model should somehow get the URL without it being passed as a param
val smth: String = Data.getSmth()
Ok(smth);
}
}
Model (Data.scala):
package models
object Data {
def getSmth: Option[String] = DB.withSession {
val db = //this is where I need the url to decide which database to use
sql"""SELECT #$db.smth FROM smthTable""".as[String].firstOption
}
}
So, this is by design in the Play Scala API - there is no magic context, if you want data you will have to pass it along to whatever piece of your code that needs it.
You will have to take the url as a parameter of some kind, you could do it like this:
case class MyModel(someData: String, requestUrl: String)
object MyModel {
def apply(someData: String, request: Request) =
new MyModel(someData, request.url)
}
This would clearly express the dependency, but in your particular app you might call this from every request and want to avoid having to repeat providing that parameter, in that case you can use Scala implicits which makes the compiler look for a matching implicit instance that is of the same type in the current scope (you can read more about this here: http://www.scala-lang.org/old/node/114).
object MyModel {
def apply(someData: String)(implicit request: Request) =
new MyModel(someData, request.url)
}
which could then be called from a controller action like this
def myAction = Action { implicit request =>
val model = MyModel("blablabla")
...
}
Of course it may be a bad idea to tightly couple your model to the play Request API and you should probably introduce your own class to represent this 'context', you could then implicitly convert from Request to YourContext in you controllers and have the model implicitly use YourContext instead.
If all this sounds like gibberish to you, you should probably start with actually learning Scala before trying to build a web app in Scala. There are lots of good books nowadays ('Scala for the impatient' for example) as well as a multitude of good online resources (the neophytes guide to scala is a good one).
Good luck!

PlayFramework instantiate object in current request scope?

I am currently active PlayFramework learner who came from world of PHP.
For example I have a Head block object in my app, which should hold title, charset encoding, meta information, etc. Something similar to Magento blocks, but without XML declaration
package blocks.Page
object Head {
var title: String = "";
}
In Application.index() method I have
blocks.Page.Head.title
Ok(views.html.application.index());
And finally in html template
#import blocks.Page.Head
<title>#Head.title</title>
However, blocks.Page.Head object is defined for entire application scope, not for single request. This object is the same for each request.
What is the right way to do, what I am trying to do? I can create container with all blocks and instantiate it with each request, then just pass to all templates. But I have a feeling that this is wrong way.
Just use usual class instead of object and pass instance to template as parameter.
Like this:
package blocks.Page
case class Head(title: String = "")
Controller:
val head = Head("Blah")
Ok(views.html.application.index(head))
And template will looks like:
#(head: blocks.Page.Head)
...
<title>#head.title</title>
I know the feeling when coming from a request-oriented language like PHP :). However, consider application-wide access as a gift of a VM (in PHP we need to go the extra mile of using some bytecode and data caching tool like APC or eAccellerator).
I would probably create a blockManager class which gives you static access to blocks by name/tag/id from the template: Block.get("MyBlock"). Then you can define and later modify your caching / storing strategy (holding in memory vs. loading from storage) without affecting your templates.