Last Updated | 27 February 2017 |
In this tutorial we'll see how to
The Kotlin standard library provides a series of wrappers around the JavaScript API for interacting with documents. The main component we'd usually access is the variable document
. Given we have access to this, we can simply read and write to the corresponding properties. For instance, to set the background of the page we can do
The DOM also provides us a way to retrieve a specific element by ID, name, class name, tag name and so on. All returned elements are of type NodeList
, and to access members we need to cast them to the specific type of element. The code below shows how we could access an input element on the page:
<body> <input type="text" name="email" id="email"/> <script type="text/javascript" src="scripts/kotlin.js"></script> <script type="text/javascript" src="scripts/domInteraction.js"></script> </body>
An important note is to make sure that the scripts are located before the body
tag is closed. Placing them at the top means that the scripts would be loaded before the DOM is fully available.
Much like we reference an input element, we can access other elements on the page, casting them to the appropriate types.
The kotlinx.html library provides the ability to generate DOM using statically typed HTML builders. The library is available when targeting the JVM as well as JavaScript. To use the library we need to include the corresponding dependency. In the case of Gradle this would be
repositories { mavenCentral() maven { url "http://dl.bintray.com/kotlin/kotlinx.html/" } } dependencies { compile 'org.jetbrains.kotlinx:kotlinx-html-js:0.6.1' compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version" }
For more information about configuring Gradle to target JavaScript please see Getting Started with Gradle.
Once the dependency is included, we can access the different interfaces provided to generate DOM. The code below will add a new span
tag with the text Hello
inside a div
on the window.load
event.
import kotlin.browser.* import kotlinx.html.* import kotlinx.html.dom.* fun printHello() { window.onload = { document.body!!.append.div { span { +"Hello" } } } }
The standard library provides us with a series of wrappers around DOM as well as functions to work with JavaScript, using static typing. What happens however when we want to use a library such as jQuery? Kotlin does not have its own "header" files for all the different libraries available on the JavaScript ecosystem however, TypeScript does. The Definitely Typed repository provides us with a very large selection of header files.
Using the tool ts2kt
(TypeScript to Kotlin) we can convert any d.ts
files to Kotlin. To install the tool we can use npm
npm -g install ts2kt
To convert a file we simply provide the input file, and optionally an output directory. The command below will convert the file jquery.d.ts
in the current folder, which we've previously downloaded from the Definitely Typed repository to the output folder headers
:
ts2kt -d headers jquery.d.ts
Once we have the file generated, we can simply include it in our project and use it:
Note that jQuery
needs to be included in the corresponding HTML:
The header files merely contain function declarations for functionality that is defined at runtime. For instance, we could define a jQuery
function like so
The above code indicates that the function is defined externally. The @JsName("$")
annotation allows us to map the name at runtime to $
. For more details on external declarations, please refer to the JavaScript interop documentation.
Note that the type systems of TypeScript and Kotlin do not match exactly, so you may need to edit the generated headers in case you encounter difficulties with using the APIs from Kotlin.
While the above solution works well for situations in which we have a corresponding header file (be this something we've defined ourselves or converted from a TypeScript header), often times we need to work with some library that does not have a header. For instance, let's say we want to use a jQuery plugin, that allows us to convert an HTML table to a nice looking navigable grid.
The way in which we'd use this from JavaScript would be to call dataTable()
on the corresponding <table>
element
<table id="data" class="display" cellspacing="0" width="100%"> <thead> <tr> <th>Name</th> <th>Position</th> <th>Office</th> <th>Age</th> </tr> </thead> <tbody> <tr> <td>Tiger Nixon</td> <td>System Architect</td> <td>Edinburgh</td> <td>61</td> </tr> <tr> <td>Garrett Winters</td> <td>Accountant</td> <td>Tokyo</td> <td>63</td> </tr> <tr> <td>Ashton Cox</td> <td>Junior Technical Author</td> <td>San Francisco</td> <td>66</td> </tr> . . . </tbody> </table>
we would invoke the following in JavaScript
How would we do this from Kotlin given that the function dataTable()
does not exist, and calling it would give a compiler error?
In situations like this we can use the dynamic
type, which allows us to work with dynamic types when targeting JavaScript. The following variable is declared as dynamic
meaning that whatever we invoke on it will not result in a compile-time error:
The above code compiles. However, it will produce a runtime error if the object is not properly initialised before use or if callAnything()
is not defined at runtime.
The standard library defines a function named asDynamic()
which casts a value to the dynamic type. Given our previous example where we used jQuery to work with DOM elements, we can now combine this with asDynamic()
to then invoke dataTable()
on the result:
It is important to understand that just like in the case of callAnything()
, the dataTable()
function must exist at runtime. In our case, we need to make sure that the corresponding script file for our plugin is included:
<script type="text/javascript" src="js/jquery.js"></script> <script type="text/javascript" src="js/jquery.dataTables.js"></script> <!-- other script files .... -->
For more information about dynamic
see the reference documentation.
© 2010–2019 JetBrains s.r.o.
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/tutorials/javascript/working-with-javascript.html