Scala.js 事件处理
Scala.js event handling
我正在编写一个使用两个事件处理程序的 Scala.Js 小应用程序:一个用于输入字段的 onkeyup
事件,另一个用于按钮的 onclick
事件。
这两个事件处理程序共享相当多的通用编码,但是一旦我尝试将事件处理程序编码优化为一个 return 事件处理程序函数的函数,它就可以正确编译,但是事件不再被困在浏览器中。
在函数 main
的以下代码中,btn.onclick
的事件处理程序工作正常,但 cityNameInput.onkeyup
的事件处理程序不再工作。我所做的只是复制直接分配给事件处理程序的代码,并将其放入名为 keystrokeHandler
的函数中,该函数 return 是 Function1[dom.Event, _]
。这编译正常,但 onkeyup
事件不再被困在浏览器中。
def keystrokeHandler(userInput: String, responseDiv: dom.Element): Function1[dom.Event,_] =
(e: dom.Event) => {
// The city name must be at least 4 characters long
if (userInput.length > 3) {
responseDiv.innerHTML = ""
val xhr = buildXhrRequest(userInput, searchEndpoint)
xhr.onload = (e: dom.Event) => {
val data: js.Dynamic = js.JSON.parse(xhr.responseText)
// Can any cities be found?
if (data.count == 0)
// Nope, so show error message
responseDiv.appendChild(p(s"Cannot find any city names starting with ${userInput}").render)
else {
// Build a list of weather reports
buildSearchList(data, responseDiv)
}
}
// Send XHR request to OpenWeather
xhr.send()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Main program
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@JSExport
def main(container: dom.html.Div): Unit = {
container.innerHTML = ""
val cityNameInput = input.render
val btn = button.render
val weatherDiv = div.render
cityNameInput.defaultValue = owmQueryParams.get("q").get
btn.textContent = "Go"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Button onclick event handler
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
btn.onclick = (e: dom.Event) => {
if (cityNameInput.value.length > 3) {
weatherDiv.innerHTML = ""
val xhr = buildXhrRequest(cityNameInput.value, weatherEndpoint)
xhr.onload = (e: dom.Event) => {
val data = js.JSON.parse(xhr.responseText)
// Can the city be found?
if (data.cod == "404")
// Nope, so show error message
weatherDiv.appendChild(p(s"City ${cityNameInput.value} not found").render)
else {
// So first add the div containing both the weather information
// and the empty div that will hold the slippy map.
// This is needed because Leaflet writes the map information to an
// existing DOM element
val report = new WeatherReportBuilder(data)
weatherDiv.appendChild(buildWeatherReport(report, 0))
buildSlippyMap("mapDiv0", report)
}
}
// Send XHR request to OpenWeather
xhr.send()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Input field onkeyup event handler
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cityNameInput.onkeyup = keystrokeHandler(cityNameInput.value, weatherDiv)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Write HTML to the screen
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
container.appendChild(
div(
h1("Weather Report"),
table(
tr(td("Enter a city name (min 4 characters)"), td(cityNameInput)),
tr(td(), td(style := "text-align: right", btn))
),
weatherDiv
).render
)
}
这里有什么问题?
keystrokeHandler
函数 return 应该是一些特殊的 Scala.Js 事件处理程序类型吗?还是别的原因?
谢谢
克里斯·W
我认为问题出在这里:
cityNameInput.onkeyup = keystrokeHandler(cityNameInput.value, weatherDiv)
事件处理程序被触发,但userInput
在创建处理程序时冻结为cityNameInput.value
,而不是随着 cityNameInput.value
的当前值而变化。实际上,该行相当于
val userInput = cityNameInput.value
cityNameInput.onkeyup = keystrokeHandler(userInput, weatherDiv)
这很明显 cityNameInput.value
只计算了一次。
相反,您应该将 cityNameInput
本身作为 keystrokeHandler
的参数,并在匿名函数内部访问 cityNameInput.value
,以便每次函数(处理程序)被评估打电话。
我正在编写一个使用两个事件处理程序的 Scala.Js 小应用程序:一个用于输入字段的 onkeyup
事件,另一个用于按钮的 onclick
事件。
这两个事件处理程序共享相当多的通用编码,但是一旦我尝试将事件处理程序编码优化为一个 return 事件处理程序函数的函数,它就可以正确编译,但是事件不再被困在浏览器中。
在函数 main
的以下代码中,btn.onclick
的事件处理程序工作正常,但 cityNameInput.onkeyup
的事件处理程序不再工作。我所做的只是复制直接分配给事件处理程序的代码,并将其放入名为 keystrokeHandler
的函数中,该函数 return 是 Function1[dom.Event, _]
。这编译正常,但 onkeyup
事件不再被困在浏览器中。
def keystrokeHandler(userInput: String, responseDiv: dom.Element): Function1[dom.Event,_] =
(e: dom.Event) => {
// The city name must be at least 4 characters long
if (userInput.length > 3) {
responseDiv.innerHTML = ""
val xhr = buildXhrRequest(userInput, searchEndpoint)
xhr.onload = (e: dom.Event) => {
val data: js.Dynamic = js.JSON.parse(xhr.responseText)
// Can any cities be found?
if (data.count == 0)
// Nope, so show error message
responseDiv.appendChild(p(s"Cannot find any city names starting with ${userInput}").render)
else {
// Build a list of weather reports
buildSearchList(data, responseDiv)
}
}
// Send XHR request to OpenWeather
xhr.send()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Main program
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@JSExport
def main(container: dom.html.Div): Unit = {
container.innerHTML = ""
val cityNameInput = input.render
val btn = button.render
val weatherDiv = div.render
cityNameInput.defaultValue = owmQueryParams.get("q").get
btn.textContent = "Go"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Button onclick event handler
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
btn.onclick = (e: dom.Event) => {
if (cityNameInput.value.length > 3) {
weatherDiv.innerHTML = ""
val xhr = buildXhrRequest(cityNameInput.value, weatherEndpoint)
xhr.onload = (e: dom.Event) => {
val data = js.JSON.parse(xhr.responseText)
// Can the city be found?
if (data.cod == "404")
// Nope, so show error message
weatherDiv.appendChild(p(s"City ${cityNameInput.value} not found").render)
else {
// So first add the div containing both the weather information
// and the empty div that will hold the slippy map.
// This is needed because Leaflet writes the map information to an
// existing DOM element
val report = new WeatherReportBuilder(data)
weatherDiv.appendChild(buildWeatherReport(report, 0))
buildSlippyMap("mapDiv0", report)
}
}
// Send XHR request to OpenWeather
xhr.send()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Input field onkeyup event handler
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cityNameInput.onkeyup = keystrokeHandler(cityNameInput.value, weatherDiv)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Write HTML to the screen
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
container.appendChild(
div(
h1("Weather Report"),
table(
tr(td("Enter a city name (min 4 characters)"), td(cityNameInput)),
tr(td(), td(style := "text-align: right", btn))
),
weatherDiv
).render
)
}
这里有什么问题?
keystrokeHandler
函数 return 应该是一些特殊的 Scala.Js 事件处理程序类型吗?还是别的原因?
谢谢
克里斯·W
我认为问题出在这里:
cityNameInput.onkeyup = keystrokeHandler(cityNameInput.value, weatherDiv)
事件处理程序被触发,但userInput
在创建处理程序时冻结为cityNameInput.value
,而不是随着 cityNameInput.value
的当前值而变化。实际上,该行相当于
val userInput = cityNameInput.value
cityNameInput.onkeyup = keystrokeHandler(userInput, weatherDiv)
这很明显 cityNameInput.value
只计算了一次。
相反,您应该将 cityNameInput
本身作为 keystrokeHandler
的参数,并在匿名函数内部访问 cityNameInput.value
,以便每次函数(处理程序)被评估打电话。