docs/codelabs/getting_started/4-control_flow_loops.md
Before we start, your component should look something like this.
import { Component } from "valdi_core/src/Component";
import { systemBoldFont, systemFont } from "valdi_core/src/SystemFont";
export class GettingStartedCodelab extends Component {
private msg?: string;
onCreate() {
this.msg = 'Hello valdi on ';
}
onRender() {
const fullMsg = this.msg + new Date().toLocaleTimeString();
<layout padding={24} paddingTop={80}>
<label value='Declarative codelab' font={systemBoldFont(16)} />
<label value={fullMsg} font={systemFont(12)} />
</layout>;
}
}
if statementsYou can conditionally render parts of your UI using if statements.
Add a new boolean class variable.
export class GettingStartedCodelab extends Component {
private msg?: string;
private kitten?: boolean;
...
Now add an if statement checking that variable.
onRender() {
if (this.kitten) {
<image height={50} width={50} src='https://placecats.com/300/300' />
} else {
const fullMsg = this.msg + new Date().toLocaleTimeString();
<layout>
<label value='Declarative codelab' font={systemBoldFont(16)} />
<label value={fullMsg} font={systemFont(12)} />
</layout>;
}
}
You won't see any changes yet. Because kitten is an optional variable and it is still undefined, it evaluates to false.
Set the value of your boolean in onCreate.
onCreate() {
this.msg = 'Hello valdi on ';
this.kitten = true;
}
Now you should see a kitten!
You can iterate through lists in the middle of the TSX.
Start by removing the kitten variable we added for the if statement.
Create a list of kittens.
export class GettingStartedCodelab extends Component {
private msg?: string;
private kittens = [
'https://placecats.com/300/300',
'https://placecats.com/300/301',
'https://placecats.com/300/302',
];
...
The slightly different sizes will give you different kittens.
Then iterate through the kittens with a forEach.
onRender() {
const fullMsg = this.msg + new Date().toLocaleTimeString();
<layout>
<label value='Declarative codelab' font={systemBoldFont(16)} />
<label value={fullMsg} font={systemFont(12)} />
{this.kittens.forEach(kitten => {
<image height={50} width={50} src={kitten} />;
})}
</layout>;
}
if and for caveatYou might think, having seen the examples above, that you can do something similar with inline if and for loops.
Well, you can't.
The contents of a curly brace block inside of the TSX need to be an expression. In the current TypeScript standard, if and for are not expressions.
If you want to do something similar, you have a few options discussed below.
when expressionsGoing back to our if implementation.
onRender() {
if (this.kitten) {
<image height={50} width={50} src='https://placecats.com/300/300' />
} else {
const fullMsg = this.msg + new Date().toLocaleTimeString();
<layout>
<label value='Declarative codelab' font={systemBoldFont(16)} />
<label value={fullMsg} font={systemFont(12)} />
</layout>;
}
}
If you decide you want to keep the "Declarative codelab" title and just swap out the contents of the second line, you can do that with a when expression.
First, import the when utility:
import { when } from 'valdi_core/src/utils/When';
Then use it to conditionally render a component:
onRender() {
const fullMsg = this.msg + new Date().toLocaleTimeString();
<layout>
<label value='Declarative codelab' font={systemBoldFont(16)} />
{when(this.kitten, () => {
<image height={50} width={50} src='https://placecats.com/300/300' />;
})}
<label value={fullMsg} font={systemFont(12)} />
</layout>;
}
The first parameter in when is the conditional, this can be an expression that evaluates to a boolean or just a variable. The second parameter is a lambda that executes when your conditional evaluates to true.
when has no else clause, so if you want that kind of thing, you need to implement a when(!conditional).
onRender() {
const fullMsg = this.msg + new Date().toLocaleTimeString();
<layout>
<label value='Declarative codelab' font={systemBoldFont(16)} />
{when(this.kitten, () => {
<image height={50} width={50} src='https://placecats.com/300/300' />;
})}
{when(!this.kitten, () => {
<label value={fullMsg} font={systemFont(12)} />;
})}
</layout>;
}
Try changing the value of this.kitten and watch what happens.
You can call out to another function from onRender.
Create a new function, onRenderMessage, and call it from onRender.
onRenderMessage(message: string) {
// Render message
}
onRender() {
const fullMsg = this.msg + new Date().toLocaleTimeString();
<layout>
<label value='Declarative codelab' font={systemFont(12)} />
{this.onRenderMessage(fullMsg)}
</layout>;
}
Now we can put whatever we want in that onRenderMessage function.
Add an if statement to swap out the kitten.
onRenderMessage(message: string) {
if (this.kitten) {
<image height={50} width={50} src='https://placecats.com/300/300' />;
} else {
<label value={message} font={systemFont(12)} />;
}
}
This isn't just useful for conditionals that are not expressions, it can make your code more readable and reusable.