ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Waypoint 를 이용해 Router 적용
    web/laminar 2022. 1. 28. 20:36

     

    문제

    Waypoint 를 이용해 Router 를 적용해 본다.

     

    http://localhost:9000/search?engine=google&query=bts 입력 했을 때

    google 이 선택 체크되고, Search Query 에 bts 가 입력된 화면이 노출되어야 한다.

     

    사용자가 Search Engine 으로 naver 를 선택 체크하고, Search Query 로 iphone 을 입력후 submit 버튼을 눌렀을 때 브라우저 URL 이 http://localhost:9000/search?engine=naver&query=iphone 로 변경되어야 한다.

    http://localhost:9000/login 입력 했을 때

    코드

    import com.raquo.laminar.api.L
    import com.raquo.laminar.api.L._
    import com.raquo.laminar.nodes.ReactiveHtmlElement
    import com.raquo.waypoint._
    import org.scalajs.dom
    import org.scalajs.dom.html
    import upickle.default._
    
    class Radio(name: String, items: Seq[String]) {
      val selectedVar: Var[String]            = Var("")
      val elem: ReactiveHtmlElement[html.Div] = div(
        cls := "ui form",
        div(
          cls := "inline fields",
          label(name),
          items.map(item =>
            div(
              cls := "field",
              div(
                cls := "ui radio checkbox",
                input(
                  typ := "radio",
                  checked <-- selectedVar.signal.map(_ == item),
                  onChange.mapTo(item) --> selectedVar
                ),
                label(item)
              )
            )
          )
        )
      )
    }
    
    class TextInput(name: String, description: String) {
      val textVar: Var[String]                = Var("")
      val elem: ReactiveHtmlElement[html.Div] = div(
        label(name),
        cls := "ui input",
        input(
          typ := "text",
          onMountFocus,
          value <-- textVar,
          onInput.mapToValue --> textVar,
          placeholder := description
        )
      )
    }
    
    object Main {
      sealed trait Page
      case class SearchPage(engine: String, query: Option[String]) extends Page
      case object LoginPage                                        extends Page
    
      implicit val SearchPageRW: ReadWriter[SearchPage] = macroRW
      implicit val rw: ReadWriter[Page]                 = macroRW
    
      def main(args: Array[String]): Unit = {
        // path 까지 route 로 사용될 경우 Route.withQuery 사용
        val searchRoute = Route.onlyQuery[SearchPage, (String, Option[String])](
          encode = searchPage => (searchPage.engine, searchPage.query),
          decode = args => SearchPage(args._1, args._2),
          pattern = (root / "search" / endOfSegments) ? (param[String]("engine") & param[String]("query").?)
        )
    
        val loginRoute = Route.static(LoginPage, root / "login" / endOfSegments)
    
        val router = new Router[Page](
          routes = List(searchRoute, loginRoute),
          getPageTitle = (page: Page) => "my title",
          serializePage = page => write(page)(rw),
          deserializePage = pageStr => read(pageStr)(rw)
        )(
          $popStateEvent = L.windowEvents.onPopState,
          owner = L.unsafeWindowOwner
        )
    
        def renderSearchPage($searchPage: Signal[SearchPage]): Div = {
          val radio     = new Radio("Search Engine", List("naver", "google", "yahoo"))
          val textInput = new TextInput("Search Query: ", "Enter query")
    
          div(
            h3("Search Page"),
            $searchPage.map(_.engine) --> radio.selectedVar,
            radio.elem,
            $searchPage.map(_.query.getOrElse("")) --> textInput.textVar,
            textInput.elem,
            br(),
            button(
              "Submit",
              onClick --> (_ => router.pushState(SearchPage(radio.selectedVar.now(), Some(textInput.textVar.now()))))
            ),
            div(
              hr(),
              div(
                "selected engine: ",
                child.text <-- $searchPage.map(_.engine)
              ),
              div(
                "query: ",
                child.text <-- $searchPage.map(_.query.getOrElse(""))
              )
            )
          )
        }
    
        def renderLoginPage: Div =
          div(
            h3("Login Page")
          )
    
        val splitter = SplitRender[Page, HtmlElement](router.$currentPage)
          .collectSignal[SearchPage]($searchPage => renderSearchPage($searchPage))
          .collectStatic(LoginPage)(renderLoginPage)
    
        val content: Div = div(
          h1("Routing App"),
          child <-- splitter.$view
        )
    
        val containerNode = dom.document.getElementById("main_content")
        render(containerNode, content)
      }
    }

    'web > laminar' 카테고리의 다른 글

    EventStream 의 flatMap vs combineWithFn  (0) 2022.10.01
    완성 - 메뉴 구현  (0) 2022.01.29
    children 으로 List 표현하기  (0) 2022.01.20
    Observer 를 사용해 side effect 처리하기  (0) 2022.01.09
    Component - TextInput  (0) 2022.01.09

    댓글

Designed by Tistory.