@@ -62,7 +62,7 @@ And replace the `main` method from the ScalaJSExample:
62
62
```
63
63
Now you should see the map on `localhost:9000`
64
64
65
-
### Add Bindings.scala
65
+
## Add Bindings.scala
66
66
The dependency is already there, so no work there.
67
67
So first we add a textfield and a button:
68
68
```Scala
@@ -85,7 +85,7 @@ And in the `index.scala.html` add `<div id="map-control"></div>` as first div.
85
85
86
86
Now check `localhost:9000` if everything works as expected.
87
87
88
-
### Putting everything together
88
+
## Putting everything together
89
89
We would like to search for an address and see it on the map.
90
90
So first let us <b>prepare the needed Google map</b> code.
91
91
To make the map available, provide it and its options as a variables:
@@ -101,10 +101,10 @@ To make the map available, provide it and its options as a variables:
101
101
```
102
102
103
103
Provide a function that:
104
-
1) takes the address (String) from the input
105
-
2) gets a GeocoderResult (Position) from the Google map API
106
-
3) centers the the map to the position
107
-
4) sets a marker to the position
104
+
1. takes the address (String) from the input
105
+
2. gets a GeocoderResult (Position) from the Google map API
106
+
3. centers the the map to the position
107
+
4. sets a marker to the position
108
108
```Scala
109
109
private def geocodeAddress(address: String) { // 1
110
110
val geocoder = new Geocoder()
@@ -153,12 +153,103 @@ Now the `main` function looks as simple as:
153
153
google.maps.event.addDomListener(window, "load", initialize)
154
154
}
155
155
```
156
+
## Dive a bit deeper
157
+
Ok lets add a list that shows possible Addresses for our input, from where we can select one, or just take the first.
158
+
First we need another datatype where we can pass around the possible addresses:
159
+
```Scala
160
+
private val possibleAddrs: Var[Seq[GeocoderResult]] = Var(Seq())
161
+
```
162
+
We need to redo our Address fetching function a bit:
163
+
```Scala
164
+
private def possibleAddresses(address: String) {
165
+
166
+
val callback = (results: js.Array[GeocoderResult], status: GeocoderStatus) =>
167
+
if (status == GeocoderStatus.OK) {
168
+
possibleAddrs.value = results.to[Seq]
169
+
.take(5)
170
+
} else {
171
+
window.alert("Geocode was not successful for the following reason: " + status)
172
+
}
173
+
174
+
new Geocoder().geocode(GeocoderRequest(address), callback)
175
+
}
176
+
```
177
+
We provide two helper function that will display the Address on the map
178
+
```Scala
179
+
private def selectAddress() {
180
+
val value = possibleAddrs.value
181
+
if(value.nonEmpty)
182
+
selectAddress(value.head)
183
+
else
184
+
window.alert("There is no Address for your input")
185
+
}
186
+
187
+
private def selectAddress(address: GeocoderResult) {
188
+
gmap.setCenter(address.geometry.location)
189
+
val marker = new google.maps.Marker(
190
+
google.maps.MarkerOptions(map = gmap
191
+
, position = address.geometry.location))
192
+
}
193
+
```
194
+
We adjust our render function:
195
+
```Scala
196
+
@dom private lazy val render: Binding[HTMLElement] = {
197
+
<div>
198
+
<input id="searchInput" class="prompt" type="text" placeholder="Address..." oninput={event: Event =>
199
+
val value: String = searchInput.value
200
+
if (value.length > 2)
201
+
possibleAddresses(value)}/>
202
+
<button class="ui primary button" onclick={event: Event =>
203
+
selectAddress()}>
204
+
Search Address
205
+
</button>
206
+
<div>
207
+
<ol>
208
+
{for (addr <- possibleAddrs.bind) yield
209
+
<li>
210
+
{addr.formatted_address}<button onclick={event: Event =>
211
+
selectAddress(addr)}>select</button>
212
+
</li>}
213
+
</ol>
214
+
</div>
215
+
</div>
216
+
}
217
+
```
218
+
Now it gets tricky. If you refresh `localhost:9000` you will get a Compile Exception: `'each' instructions must be inside a SDE block`.
219
+
Ok, that suggest to extract the `<li>` part:
220
+
```Scala
221
+
...
222
+
<ol>
223
+
{for (addr <- possibleAddrs.bind) yield
224
+
renderPosAddr(addr: GeocoderResult).bind}
225
+
</ol>
226
+
...
227
+
228
+
@dom private def renderPosAddr(addr: GeocoderResult): Binding[HTMLElement] = {
229
+
<li>
230
+
{addr.formatted_address}<button onclick={event: Event =>
231
+
selectAddress(addr)}>select</button>
232
+
</li>
233
+
}
234
+
```
235
+
That was not enough - still the same exception!
236
+
Now we need to do it like this (explained here: [Stackoverflow](https://stackoverflow.com/questions/42498968/when-i-use-binding-scala-i-got-the-error-each-instructions-must-be-inside-a-sd/42498969#42498969) )
237
+
```Scala
238
+
...
239
+
<ol>
240
+
{Constants(possibleAddrs.bind.map(addr =>
241
+
renderPosAddr(addr)): _*).map(_.bind)}
242
+
</ol>
243
+
...
244
+
```
245
+
Now everything compiles and we can search our Addresses!
246
+
156
247
## Conclusion
157
248
It's quite interesting to see a stream based Framework (Binding.scala) next to the callback based API (Google maps).
158
249
- The Binding.scala solution is really elegant.
159
250
- I had, still have some problems that there are compile time exceptions shown by the IDE (Intellij). Some I could get rid of by adding implicit conversions.
160
251
- The usage of scala XML to declare the HTML-DOM is really nice. You literally can copy your HTML code directly, just adding the dynamic parts.
161
-
- However for parameters that expect other types than String, you need again implicit conversions.
252
+
- Only drawback: for parameters that expect other types than String, you need again implicit conversions.
162
253
163
254
## Improvements
164
255
Please let me know if there are things:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4