All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kreuzberg.extras.LazyLoader.scala Maven / Gradle / Ivy

There is a newer version: 0.10.3
Show newest version
package kreuzberg.extras

import kreuzberg.{
  AssemblerContext,
  Effect,
  EventSink,
  EventSource,
  EventTransformer,
  Html,
  Model,
  ServiceRepository,
  SimpleComponentBase,
  SimpleContext,
  SimpleHtml
}

/** A Base class for components which lazy load stuff from an external service. */
abstract class LazyLoader[T] extends SimpleComponentBase {
  import LazyLoader._

  val model = Model.create[LazyState[T]](LazyState.Init)

  /** Event sink for refreshing the loader. */
  def refresh: EventSink[Any] = EventSink.ModelChange(model, (_, _) => LazyState.Init)

  /** Event sink for refreshing (silently) */
  def silentRefresh(using a: AssemblerContext): EventSink[Any] = {
    EventTransformer
      .AddEffect { _ =>
        load()
      }
      .map {
        _._2.fold(err => LazyState.Failed(err), ok => LazyState.Ok(ok))
      }
      .intoModel(model)
  }

  override def assemble(using c: SimpleContext): Html = {
    val data = subscribe(model)
    data match {
      case LazyState.Init            =>
        add(
          EventSource.Assembled
            .withEffect(_ => load())
            .map {
              _.fold(err => LazyState.Failed(err), ok => LazyState.Ok(ok))
            }
            .intoModel(model),
          EventSource.Assembled.setModelTo(model, LazyState.WaitResponse)
        )
        waiting()
      case LazyState.WaitResponse    =>
        waiting()
      case LazyState.Ok(data)        =>
        ok(data)
      case LazyState.Failed(message) =>
        failed(message)
    }
  }

  /** Load from external service. */
  def load()(using c: AssemblerContext): Effect[T]

  /** Html which is rendered during loading. */
  def waiting()(using c: SimpleContext): Html = {
    SimpleHtml("div").addText("Loading...")
  }

  /** Html which is rendered on error. */
  def failed(error: Throwable)(using c: SimpleContext): Html = {
    SimpleHtml("div").addText(s"Error: ${error.getMessage}")
  }

  /** Html which is rendered after loading. */
  def ok(data: T)(using c: SimpleContext): Html
}

object LazyLoader {

  /** State of [[LazyLoader]] */
  sealed trait LazyState[+T]

  object LazyState {
    // Initial state
    object Init extends LazyState[Nothing]

    /** Waiting for Response */
    object WaitResponse extends LazyState[Nothing]

    /** Data available */
    case class Ok[T](data: T) extends LazyState[T]

    case class Failed(error: Throwable) extends LazyState[Nothing]
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy