Skip to content

Commit 9d2d07e

Browse files
committed
Merge pull request #257 from cquiroz/websockets-example
Add WebSockets example
2 parents 4ea815b + 0ff19bd commit 9d2d07e

File tree

2 files changed

+101
-1
lines changed

2 files changed

+101
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package ghpages.examples
2+
3+
import ghpages.GhPagesMacros
4+
import ghpages.examples.util.SingleSide
5+
import japgolly.scalajs.react._, vdom.prefix_<^._
6+
7+
import org.scalajs.dom.{WebSocket, MessageEvent, Event, CloseEvent, ErrorEvent}
8+
9+
object WebSocketsExample {
10+
11+
def content = SingleSide.Content(source, main())
12+
13+
lazy val main = addIntro(WebSocketsApp, _(
14+
s"Echo messages with WebSockets using ReactJS"))
15+
16+
val source = GhPagesMacros.exampleSource
17+
18+
// EXAMPLE:START
19+
val url = "ws://echo.websocket.org"
20+
21+
case class State(ws: Option[WebSocket], log: List[String], message: String)
22+
23+
class Backend($: BackendScope[Unit, State]) {
24+
def render(p: Unit, s: State) = {
25+
<.div(
26+
<.h3(s"Type a message and get an echo"),
27+
<.form(
28+
^.onSubmit ==> send,
29+
<.input(
30+
^.onChange ==> onChange,
31+
^.value := s.message),
32+
<.button(
33+
^.disabled := s.message.isEmpty && s.ws.isDefined, "Send")), // Enable if the text exist and the WebSocket is connected
34+
<.h4("Connection log"),
35+
<.pre( // Log content
36+
^.width := 200, // Basic style
37+
^.height := 200,
38+
^.border := "1px solid",
39+
s.log.map(<.p(_)))
40+
)
41+
}
42+
43+
def onChange(e: ReactEventI): Callback =
44+
$.modState(_.copy(message = e.target.value))
45+
46+
def send(e: ReactEventI): Callback = {
47+
// Send a message to the WebSocket
48+
val send = $.state.map(s => s.ws.foreach(_.send(s.message)))
49+
val preventSubmit = e.preventDefaultCB
50+
val updateLog = $.modState(s => s.copy(log = s.log :+ s"Sent: ${s.message}", message = ""))
51+
send >> preventSubmit >> updateLog
52+
}
53+
54+
// These are message receiving events from the WebSocket "thread",
55+
// to change the state, you need to call `runNow()` on them
56+
def onopen(e: Event) = {
57+
// Indicate the connection is open
58+
$.modState(s => s.copy(log = s.log :+ "Connected")).runNow()
59+
}
60+
61+
def onmessage(e: MessageEvent) = {
62+
// Echo message received
63+
$.modState(s => s.copy(log = s.log :+ s"Echo: ${e.data.toString}")).runNow()
64+
}
65+
66+
def onerror(e: ErrorEvent) = {
67+
// Display error message
68+
$.modState(s => s.copy(log = s.log :+ s"Error: ${e.message}")).runNow()
69+
}
70+
71+
def onclose(e: CloseEvent) = {
72+
// Close the connection
73+
$.modState(s => s.copy(ws = None, log = s.log :+ s"Closed: ${e.reason}")).runNow()
74+
}
75+
76+
def start: Callback = {
77+
// Create WebSocket and setup listeners
78+
val ws = new WebSocket(url)
79+
ws.onopen = onopen _
80+
ws.onclose = onclose _
81+
ws.onmessage = onmessage _
82+
ws.onerror = onerror _
83+
$.setState(State(Some(ws), List("Connecting"), ""))
84+
}
85+
86+
def end: Callback = {
87+
$.state.map(s => s.ws.foreach(_.close())) >> $.modState(_.copy(ws = None))
88+
}
89+
}
90+
91+
val WebSocketsApp = ReactComponentB[Unit]("WebSocketsApp")
92+
.initialState(State(None, Nil, ""))
93+
.renderBackend[Backend]
94+
.componentDidMount(_.backend.start)
95+
.componentWillUnmount(_.backend.end)
96+
.buildU
97+
98+
// EXAMPLE:END
99+
}

gh-pages/src/main/scala/ghpages/pages/ExamplesPage.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ object ExamplesScala extends ExampleCollection {
5353
case object Reuse extends Example("Reusability", "reusability", ReuseExample .content)
5454
case object EventListen extends Example("EventListener", "event-listener", EventListenerExample .content)
5555
case object CallbackOpt extends Example("CallbackOption", "callback-option", CallbackOptionExample.content)
56+
case object WebSockets extends Example("WebSockets", "websockets", WebSocketsExample .content)
5657

5758
override val values = Vector[Example](
5859
EventListen, CallbackOpt, ExternalVar, Reuse, StateMonad
59-
, Touch
60+
, Touch, WebSockets
6061
).sortBy(_.title)
6162
}

0 commit comments

Comments
 (0)