Search code examples
pythonlistnicegui

I'm populating some cards using for-loop in NiceGUI.Each has a label and a button.Trying to access label id but it prints last label id only on click


When I click on the button it should print the id of the label inside that card only. But it always prints the id of last label no matter which button I click on.

In the code below my_grid is the name of the grid in which I'm trying to populate the cards and listcards is the list of cards labels that I'm trying to put inside the card

Code

with my_grid:   
   for i in range(0,len(listcards)):
       with ui.card() as mycard:
           label_card = ui.label(text=f"{listcards[i]}")
           bt = ui.button("ID", on_click=lambda:print(label_card.id))

When I click on the button I want to print the label id of that card only but it always prints the id of last label. I really want to fix this issue. Any suggestions?


Solution

  • This is a very frequently asked question. We're actually thinking about introducing a FAQ section because of this question. But it is indeed a tricky Python behavior that keeps confusing developers.

    In the following code example, a button click will call the lambda function, which in turn prints the value of label_card.id. Since the for loop has terminated long before the button click, label_card is the label with text "9". Therefore, regardless of which button is clicked, the ID of this last label is printed.

    for i in range(10):
        with ui.card():
            label_card = ui.label(text=i)
            ui.button("ID", on_click=lambda: print(label_card.id))
    

    The trick is to add label_card=label_card to the parameter list of the lambda function. The lambda function is unique for every loop cycle. And so are its parameters. The current value of the label_card variable is written into the parameter list of the unique lambda function. This way a button click prints the ID of the corresponding label_card.

    for i in range(10):
        with ui.card():
            label_card = ui.label(text=i)
            ui.button("ID", on_click=lambda label_card=label_card: print(label_card.id))