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

Support easy conditional layout #7569

Open
MarcSkovMadsen opened this issue Dec 24, 2024 · 2 comments
Open

Support easy conditional layout #7569

MarcSkovMadsen opened this issue Dec 24, 2024 · 2 comments
Labels
type: enhancement Minor feature or improvement to an existing feature
Milestone

Comments

@MarcSkovMadsen
Copy link
Collaborator

MarcSkovMadsen commented Dec 24, 2024

React has ways to conditionally layout. Reflex has rx.cond too https://reflex.dev/docs/library/dynamic-rendering/cond/:

class CondState(rx.State):
    show: bool = True

    @rx.event
    def change(self):
        self.show = not (self.show)


def cond_example():
    return rx.vstack(
        rx.button("Toggle", on_click=CondState.change),
        rx.cond(
            CondState.show,
            rx.text("Text 1", color="blue"),
            rx.text("Text 2", color="red"),
        ),
    )

With Panel we can also conditionally render. But we have to stop the layout process to write some wrapper code like cond below.

import param
import panel as pn

pn.extension()

def cond(show1, comp1, comp2):
    if isinstance(show1, param.Parameter):
        return pn.bind(cond, show1, comp1, comp2)
    
    if show1:
        return comp1
    return comp2

class CondState(param.Parameterized):
    show: bool = param.Boolean()

    def change(self, event):
        self.show = not (self.show)

def cond_example():
    state=CondState()

    return pn.Column(
        pn.widgets.Button(name="Toggle", on_click=state.change),
        cond(
            state.param.show,
            pn.pane.Str("Text 1", styles={"color": "blue"}),
            pn.pane.Str("Text 2", styles={"color": "red"}),
        ),
        state.param.show
    )

cond_example().servable()

Basic users of Panel would not know how to write cond and intermediate user would have to write more boilerplate code.

Please add cond layout or in other ways make this more easy.

As a first step please confirm if a PR with functionality like this would be welcome and even better explain your requirements for a feature like this.

@MarcSkovMadsen
Copy link
Collaborator Author

MarcSkovMadsen commented Dec 24, 2024

Here are some alternative ways this can be implemented:

Reactive not_

import param
import panel as pn

pn.extension()

class CondState(param.Parameterized):
    show: bool = param.Boolean()

    def change(self, event):
        self.show = not (self.show)

def cond_example():
    state=CondState()

    return pn.Column(
        pn.widgets.Button(name="Toggle", on_click=state.change),
        pn.pane.Str("Text 1", styles={"color": "blue"}, visible=state.param.show),
        pn.pane.Str("Text 2", styles={"color": "red"}, visible=state.param.show.rx.not_()),
    )

cond_example().servable()

I prefer cond above as its feel simpler/ easier to read and it makes it clear that we want to show one of the two components.

Reactive where (Recommended?):

You can use .rx.where:

import param
import panel as pn

pn.extension()

class CondState(param.Parameterized):
    show: bool = param.Boolean()

    def change(self, event):
        self.show = not (self.show)

def cond_example():
    state=CondState()

    return pn.Column(
        pn.widgets.Button(name="Toggle", on_click=state.change),
        state.param.show.rx.where(
            pn.pane.Str("Text 1", styles={"color": "blue"}),
            pn.pane.Str("Text 2", styles={"color": "red"}),
        )
    )

cond_example().servable()

Its still not as easy to comprehend though. But maybe its worth saying this is the feature we have to not implement more features? To make it work for a simple bool value you will have to wrap it with param.rx: param.rx(value).rx.where(...,...).

@MarcSkovMadsen MarcSkovMadsen added this to the Wishlist milestone Dec 24, 2024
@MarcSkovMadsen MarcSkovMadsen added the type: enhancement Minor feature or improvement to an existing feature label Dec 24, 2024
@MarcSkovMadsen MarcSkovMadsen changed the title Support conditional layout Support easy conditional layout Dec 24, 2024
@philippjfr
Copy link
Member

.rx.where is indeed what I'd use here. What we might be able to think about is to allow the rx object to create expressions via the namespace accessor directly, so instead of pn.rx(condition).rx.where(v1, v2) you can do pn.rx.where(condition, v1, v2).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement Minor feature or improvement to an existing feature
Projects
None yet
Development

No branches or pull requests

2 participants