Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add renderTrue and renderFalse convenience functions #857

Merged
merged 2 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions core/src/jsMain/kotlin/dev/fritz2/core/rendercontext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,44 @@ interface RenderContext : WithJob, WithScope {
}
}

/**
* Renders the data of a boolean [Flow] only if its value is `true`.
*
* @receiver [Flow] containing the data
* @param into target to mount content to. If not set a child div is added to the [Tag] this method is called on
* @param content [RenderContext] for rendering the data to the DOM
*
* @see renderIf
* @see renderFalse
*/
fun Flow<Boolean>.renderTrue(
into: Tag<HTMLElement>? = null,
content: Tag<*>.() -> Unit
) {
renderIf(predicate = { it }, into) { _ ->
content()
}
}

/**
* Renders the data of a boolean [Flow] only if its value is `false`.
*
* @receiver [Flow] containing the data
* @param into target to mount content to. If not set a child div is added to the [Tag] this method is called on
* @param content [RenderContext] for rendering the data to the DOM
*
* @see renderIf
* @see renderTrue
*/
fun Flow<Boolean>.renderFalse(
into: Tag<HTMLElement>? = null,
content: Tag<*>.() -> Unit
) {
renderIf(predicate = { !it }, into) { _ ->
content()
}
}

/**
* Renders the non-null data of a [Flow].
*
Expand Down
78 changes: 78 additions & 0 deletions core/src/jsTest/kotlin/dev/fritz2/core/rendercontext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,84 @@ class RenderContextTests {
assertNull(div(div2))
}

@Test
fun testRenderTrueFunction() = runTest {
val store = storeOf(true)

val id = Id.next()
val expectedContentIfTrue = "rendered"
val expectedContentIfFalse = ""


render {
div(id = id) {
store.data.renderTrue(into = this) {
+expectedContentIfTrue
}
}
}


delay(100)

val divContent = document.getElementById(id)?.textContent
assertEquals(
expected = expectedContentIfTrue,
actual = divContent,
message = "Content must be present"
)


store.update(false)
delay(100)

val divContentAfterUpdate = document.getElementById(id)?.textContent
assertEquals(
expected = expectedContentIfFalse,
actual = divContentAfterUpdate,
message = "Content must be absent"
)
}

@Test
fun testRenderFalseFunction() = runTest {
val store = storeOf(false)

val id = Id.next()
val expectedContentIfFalse = "rendered"
val expectedContentIfTrue = ""


render {
div(id = id) {
store.data.renderFalse(into = this) {
+expectedContentIfFalse
}
}
}


delay(100)

val divContent = document.getElementById(id)?.textContent
assertEquals(
expected = expectedContentIfFalse,
actual = divContent,
message = "Content must be present"
)


store.update(true)
delay(100)

val divContentAfterUpdate = document.getElementById(id)?.textContent
assertEquals(
expected = expectedContentIfTrue,
actual = divContentAfterUpdate,
message = "Content must be absent"
)
}

@Test
fun testRenderNotNullFunction() = runTest {
val store = storeOf<String?>(null)
Expand Down
20 changes: 11 additions & 9 deletions www/src/pages/docs/30_Render HTML.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,17 @@ As you already know, all [state handling](/docs/fundamentals/#state-handling) is
Based upon the `data`-property, which provides a `Flow` of the store's generic data type, there are a variety of
`render*`-functions which can be used to create *reactive* UIs:

| Render-Function | Additional parameters | Description | Default Tag |
|----------------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------|-------------|
| `Flow<T>.render` | - | Creates a mount-point providing the whole store's data value `T` inside `content` expression | `div` |
| `Flow<T>.renderIf` | predicate | Creates a mount-point providing the whole store's data value `T` inside `content` expression when `predicate` is `true` | `div` |
| `Flow<T>.renderNotNull` | - | Creates a mount-point providing the whole store's data value `T` inside `content` expression when `T` is not `null` | `div` |
| `Flow<T>.renderIs` | klass | Creates a mount-point providing the whole store's data value `T` inside `content` expression when `T` is of type `klass` | `div` |
| `Flow<String>.renderText` | - | Creates a mount-point creating a text-node | `span` |
| `Flow<List<T>>.renderEach` | - | Creates a mount-point optimizing changes by `T.equals`. Provides a `T` inside the `content` expression. Use for value objects | `div` |
| `Flow<List<T>>.renderEach` | idProvider | Creates a mount-point optimizing changes by `idProvider`. Provides a `T` inside the `content` expression. Use for entities | `div` |
| Render-Function | Additional parameters | Description | Default Tag |
|-----------------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------|-------------|
| `Flow<T>.render` | - | Creates a mount-point providing the whole store's data value `T` inside `content` expression | `div` |
| `Flow<T>.renderIf` | predicate | Creates a mount-point providing the whole store's data value `T` inside `content` expression when `predicate` is `true` | `div` |
| `Flow<Boolean>.renderTrue` | - | Creates a mount-point rendering the `content` expression with no store data provided when the flow's value is `true` | `div` |
| `Flow<Boolean>.renderFalse` | - | Creates a mount-point rendering the `content` expression with no store data provided when the flow's value is `false` | `div` |
| `Flow<T>.renderNotNull` | - | Creates a mount-point providing the whole store's data value `T` inside `content` expression when `T` is not `null` | `div` |
| `Flow<T>.renderIs` | klass | Creates a mount-point providing the whole store's data value `T` inside `content` expression when `T` is of type `klass` | `div` |
| `Flow<String>.renderText` | - | Creates a mount-point creating a text-node | `span` |
| `Flow<List<T>>.renderEach` | - | Creates a mount-point optimizing changes by `T.equals`. Provides a `T` inside the `content` expression. Use for value objects | `div` |
| `Flow<List<T>>.renderEach` | idProvider | Creates a mount-point optimizing changes by `idProvider`. Provides a `T` inside the `content` expression. Use for entities | `div` |

There is one more `renderEach` variant which is defined as an extension to a `Store` instead of a `Flow`.
This special variant and its application are described in the
Expand Down
Loading