You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -566,7 +662,7 @@ It takes data model values as arguments, and returns a Laminar element manipulat
566
662
This is what many UI frameworks call a *component*.
567
663
In Laminar, components are nothing but methods manipulating time-varying data and returning Laminar elements.
568
664
569
-
## Editing prices and counts
665
+
## Editing prices
570
666
571
667
To finish our application, we should also be able to edit *prices* and *counts*.
572
668
@@ -594,10 +690,21 @@ For the prices, we start with a "component" method building an `Input` that mani
594
690
It is more complicated than the one for `String`s because of the need for parsing and formatting.
595
691
This complexity perhaps better highlights the benefit of encapsulating it in a dedicated method (or component).
596
692
597
-
We leave it to the reader to understand the details of this method.
693
+
We leave it to the reader to understand the details of the transformations.
598
694
We point out that we use an intermediate, local `Var[String]` to hold the actual text of the `input` element.
599
695
We then write separate transformations to link that `Var[String]` to the string representation of the `Double` signal and updater.
600
696
697
+
Note that we put the `<--` and `-->` binders connecting `strValue` with `valueSignal` and `valueUpdater` as arguments to the Laminar `input` element.
698
+
This may seem suspicious, as none of them nor their callbacks have any direct relationship to the DOM `input` element.
699
+
We do this to tie the lifetime of the binders to the lifetime of the `input` element.
700
+
When the latter gets unmounted, we release the binder connections, possibly allowing resources to be reclaimed.
701
+
702
+
In general, every binder must be *owned* by a Laminar element.
703
+
It only gets *activated* when that element is mounted.
704
+
This prevents memory leaks.
705
+
706
+
## Editing counts
707
+
601
708
For the counts, we want a component that manipulates `Int` values.
602
709
For those, we would like a more *controlled* input.
603
710
Instead of letting the user enter any string in the input, and only remember the last valid `Double` value, we now want to only allow valid `Int` values in the first place.
Copy file name to clipboardExpand all lines: doc/tutorial/scalablytyped.md
+14-30Lines changed: 14 additions & 30 deletions
Original file line number
Diff line number
Diff line change
@@ -25,25 +25,19 @@ ScalablyTyped can read TypeScript type definition files and produce correspondin
25
25
26
26
We set up our new dependencies as follows.
27
27
28
-
In `project/plugins.sbt`, we add a dependency on ScalablyTyped:
28
+
First, we install some npm packages: Chart.js as a regular dependency (with `-S`), and its TypeScript type definitions along with the TypeScript compiler---required by ScalablyTyped---as development dependencies (with `-D`):
In `package.json`, we add dependencies on Chart.js, its TypeScript type definitions, and on the TypeScript compiler, which is required by ScalablyTyped:
37
+
In `project/plugins.sbt`, we add a dependency on ScalablyTyped:
+ // Tell ScalablyTyped that we manage `npm install` ourselves
62
56
+ externalNpm := baseDirectory.value,
@@ -65,10 +59,8 @@ Finally, in `build.sbt`, we configure ScalablyTyped on our project:
65
59
66
60
For these changes to take effect, we have to perform the following steps:
67
61
68
-
1. Stop sbt and Vite, if they are running
69
-
1. Run `npm install` to install the new npm dependencies
70
62
1. Restart sbt and the `~fastLinkJS` task (this will take a while the first time, as ScalablyTyped performs its magic)
71
-
1. Restart `npm run dev`
63
+
1. Restart `npm run dev` if it was running
72
64
1. Possibly re-import the project in your IDE of choice
73
65
74
66
## Chart configuration
@@ -240,6 +232,7 @@ We store the resulting `chart` instance in a local `var optChart: Option[Chart]`
240
232
We will use it later to update the `chart`'s imperative data model when our FRP `dataSignal` changes.
241
233
242
234
In order to achieve that, we use a `dataSignal -->` binder.
235
+
We give it as an argument to the Laminar `canvas` element to tie the binder to the canvas lifetime, as you may [recall from the Laminar tutorial](laminar.html#editing-prices).
243
236
Once the `canvas` gets mounted, every time the value of `dataSignal` changes, the callback is executed.
244
237
245
238
{% highlight scala %}
@@ -256,15 +249,6 @@ dataSignal --> { data =>
256
249
In the callback, we get access to the `chart: Chart` instance and update its data model.
257
250
This `-->` binder allows to bridge the FRP world of `dataSignal` with the imperative world of Chart.js.
258
251
259
-
Note that we put the `-->` binder as an argument to the Laminar `canvas` element.
260
-
This may seem suspicious, as neither `dataSignal` nor the callback have any direct relationship to the DOM canvas element.
261
-
We do this to tie the lifetime of the binder to the lifetime of the `canvas` element.
262
-
When the latter gets unmounted, we release the binder connection, possibly allowing resources to be reclaimed.
263
-
264
-
In general, every binder must be *owned* by a Laminar element.
265
-
It only gets *activated* when that element is mounted.
266
-
This prevents memory leaks.
267
-
268
252
Our application now properly renders the data model as a chart.
269
253
When we add or remove data items, the chart is automatically updated, thanks to the connection established by the `dataSignal -->` binder.
0 commit comments