Skip to content

Instantly share code, notes, and snippets.

@lancewalton
Created July 9, 2022 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lancewalton/d0d8fcdd07df4d0e87223bbfef2f01bf to your computer and use it in GitHub Desktop.
Save lancewalton/d0d8fcdd07df4d0e87223bbfef2f01bf to your computer and use it in GitHub Desktop.
An HTML select element whose options & selected option are determined by a Laminar Signal of an arbitrary type T, emitting the selected T on a WriteBus
import com.raquo.laminar.api.L.*
import org.scalajs.dom.{HTMLOptionElement, html}
object HTMLSelect {
def signalRequiredSelect[T](options: Signal[List[T]], toValue: T => String, toText: T => String, controlledSelection: Signal[T], userSelection: WriteBus[T]): HtmlElement = {
select(
children <--
options
.split(toValue) { case (v, _, updates) =>
option(
value := v,
child.text <-- updates.map(toText),
)
},
onMountBind { ctx =>
val ownedOptions: OwnedSignal[List[T]] = options.observe(ctx.owner)
controlled(
value <-- controlledSelection.map(toValue),
onChange.mapToValue -->
userSelection
.contracomposeWriter[String](_.map(userSelectionValue => ownedOptions.now().find(toValue(_) == userSelectionValue).getOrElse(throw new Exception(s"Unexpected value '$value"))))(ctx.owner)
)
}
)
}
def signalOptionalSelect[T](options: Signal[List[T]], toValue: T => String, toText: T => String, controlledSelection: Signal[Option[T]], userSelection: WriteBus[Option[T]], noSelectionValue: String = "noselection", noSelectionText: String = ""): HtmlElement =
signalRequiredSelect[Option[T]](
options.map(os => None :: os.map(Option(_))),
_.fold(noSelectionValue)(toValue),
_.fold(noSelectionText)(toText),
controlledSelection,
userSelection
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment