Search code examples
pythonforeachgridpython-reflex

pynecone cannot get detail information from item in the cards example (grid + foreach)


This is our expected output.
enter image description here

And this is the current output.
enter image description here

And this is the source code for the current output.

import pynecone as pc

def show_items(item):
    return pc.box(
        pc.text(item),
        bg="lightgreen"
    )


class ExampleState(pc.State):
    my_objects = [["item1", "desc1"], ["item2", "desc2"]]
    print(my_objects)


def home():
    homeContainer = pc.container(
        pc.hstack(
            pc.container(
                # watch list
                pc.vstack(
                    pc.container(h="20px"),
                    pc.hstack(
                        pc.heading("Example List", size="md"),
                    ),
                    pc.grid(
                        pc.foreach(ExampleState.my_objects, show_items),
                        template_columns="repeat(5, 1fr)",
                        h="20vh",
                        width="100%",
                        gap=4,
                    ),
                    justifyContent="start",
                    align_items="start",
                ),
                height="100vh",
                maxWidth="auto",
            ),

            bg="#e8e5dc",
        ),
    )

    return homeContainer


app = pc.App(state=ExampleState)
app.add_page(home, route="/")
app.compile()

In this example, we cannot make our expected output. In the above example, if we change the code from

pc.text(item)

to

pc.text(item[0])

, then we will get the following error message

  File "xxxx_some_code.py", line 47, in <module>
    app.add_page(home, route="/")
  File "/xxxx/opt/anaconda3/envs/pynecone-121-py311/lib/python3.11/site-packages/pynecone/app.py", line 261, in add_page
    raise e
  File "/xxxx/opt/anaconda3/envs/pynecone-121-py311/lib/python3.11/site-packages/pynecone/app.py", line 252, in add_page
    component = component if isinstance(component, Component) else component()
                                                                   ^^^^^^^^^^^
  File "xxxx_some_code.py", line 26, in home
    pc.foreach(ExampleState.my_objects, show_items),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/xxxx/opt/anaconda3/envs/pynecone-121-py311/lib/python3.11/site-packages/pynecone/components/layout/foreach.py", line 48, in create
    children=[IterTag.render_component(render_fn, arg=arg)],
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/xxxx/opt/anaconda3/envs/pynecone-121-py311/lib/python3.11/site-packages/pynecone/components/tags/iter_tag.py", line 71, in render_component
    component = render_fn(arg)
                ^^^^^^^^^^^^^^
  File "xxxx_some_code.py", line 5, in show_items
    pc.text(item[0]),
            ~~~~^^^
  File "/xxxx/opt/anaconda3/envs/pynecone-121-py311/lib/python3.11/site-packages/pynecone/var.py", line 181, in __getitem__
    raise TypeError(
TypeError: Could not index into var of type Any. (If you are trying to index into a state var, add a type annotation to the var.)

We also read the document related to pc.grid and pc.foreach.

And still have no idea how to fix this issue from the two documents.

So, what can we do if we want to get detailed information from the item and show it on the layout?


Solution

  • The key point is that the pc.foreach cannot use something like list[list] or list[dict].
    The following code can answer our question.
    It run well and fit the expected output. After testing,
    It runs well on pynecone==0.1.20 and pynecone==0.1.21

    import pynecone as pc
    class MyObject(pc.Model, table=True):
        title:str 
        desc:str
        def __init__(self, title, desc):
            self.title = title
            self.desc = desc
        def __repr__(self) -> str:
            return "("+self.title+","+self.desc+")"
     
    def show_object(object:MyObject):
        return pc.box(
            pc.vstack(
                pc.hstack(
                    pc.text(
                        "title:",
                        font_size="1em",
                    ),
                    pc.text(
                        object.title,
                        font_size="1em",
                    ),
                ),
                pc.hstack(
                    pc.text(
                        "desc:",
                        font_size="1em",
                    ),
                    pc.text(
                        object.desc,
                        font_size="1em",
                    ),
                ),
            ),
            bg="lightgreen"
        )
    
    
    class ExampleState(pc.State):
        # my_objects = [{"item":"item1", "desc":"desc1"}, {"item":"item2", "desc":"desc2"}]
        """
        my_objects:list[MyObject] = [
            MyObject("title1", "desc1"),
            MyObject("title2", "desc2"),
        ]
        """
        # generate objects by loop 
        my_objects:list[MyObject] = [ MyObject("title"+str(i), "desc"+str(i)) for i in range(37)]
        
    
    
    def home():
        homeContainer = pc.container(
            pc.hstack(
                pc.container(
                    # watch list
                    pc.vstack(
                        pc.container(h="20px"),
                        pc.hstack(
                            pc.heading("Example List", size="md"),
                        ),
                        pc.grid(
                            #pc.foreach(ExampleState.my_objects, show_items),
                            pc.foreach(ExampleState.my_objects, show_object),
                            template_columns="repeat(5, 1fr)",
                            h="20vh",
                            width="100%",
                            gap=4,
                        ),
                        justifyContent="start",
                        align_items="start",
                    ),
                    height="100vh",
                    maxWidth="auto",
                ),
    
                bg="#e8e5dc",
            ),
        )
        return homeContainer
    
    app = pc.App(state=ExampleState)
    app.add_page(home, route="/")
    app.compile()
    

    The following is our expected output.
    enter image description here

    The solution is we need to create a class.

    class MyObject(pc.Model, table=True):
        title:str 
        desc:str
        def __init__(self, title, desc):
            self.title = title
            self.desc = desc
        def __repr__(self) -> str:
            return "("+self.title+","+self.desc+")"
    

    And we show the layout by show_object

    def show_object(object:MyObject):
    

    In the show_object function, we get detailed information
    about the item by getting the member from the object.