How can I add an input that is selected by a click

hi

I have this cards rank:


cards = ['2s','3s','4s','5s','6s','7s','8s','9s','Ts','Js','Qs','Ks','As',
        '2h','3h','4h','5h','6h','7h','8h','9h','Th','Jh','Qh','Kh','Ah',
        '2d','3d','4d','5d','6d','7d','8d','9d','Td','Jd','Qd','Kd','Ad',
        '2c','3c','4c','5c','6c','7c','8c','9c','Tc','Jc','Qc','Kc','Ac']

how can I make an input of this cards rank, to select the cards by a click?

Can i ask for some more detail? Are you looking for a text input or a dropdown to click on? Is there an output once you click/type a card option?

I’m starting … it will have callbacks, inputs and outputs … but dont have clear how to.

Just need to know how to make the imput, with just a click from a table (for example)

I suggest you show us what you tried so far and describe where exactly you are stuck.

I don’t have much … but I think I’m clear …

I need to do a table and select the imputs by clicking over the cards.

How can I do that or with what?

Hm, unfortunately I still do not understand what your goal is.

Hello @topotaman,

If you are looking to select from these options, a dropdown would work well I think.

After selection, it would trigger a callback if you set it up. You could even allow for multiple selections.

hi

Im not looking for a dropdown … I’m looking to have objects to select, each object should be a card … and select them … is this possible?

You can make divs, which have the ability to have “n_clicks” attached, which can trigger an event.

How you use it is up to you. It is more tricky to implement because you would have to feedback which one is active and which one isnt, unless you dont have multiple options.

Keep in mind, an output (id, prop) can only be used once. That was why I suggested the dropdown.

If these dont work, you can also look into event listeners via dash-extensions.

1 Like

If you go the div route, I’d recommend passing them a className for your cards. Something so that you can style your css sheet with them.

Something like this:

html.Div([html.Div(i, id=i, n_clicks=0, className='myCustomCard') for i in cards], id='myCardHolder')

Then in your css file:

.myCustomCard {
     display: inline-block; /* if you want them to be together (could use flex as well) */
     border-radius: 5px; /* rounded edges */
     border: 2pt solid black;
     box-shadow: 2px 2px 10px silver; /* gives a nice diffusion */
     cursor: pointer;
}

.myCustomCard:hover {
     filter: brightness(1.05) /* gives it a hover effect if you have a background color you want to use */
}


/* active inversion */
.myCustomCard.active {
    background: black;
    color: white;
}

Edited to make the css file classes instead of tags.

thanks a lot @jinnyzor u r the best!

1 Like

each card should have their own id? a div for each card group (Aces … AKs … etc?)

This inspired me and I started playing around:

import dash
from dash import html, Input, Output, callback_context
import numpy as np
import dash_bootstrap_components as dbc

# raw input
cards = ['2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As',
         '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', 'Th', 'Jh', 'Qh', 'Kh', 'Ah',
         '2d', '3d', '4d', '5d', '6d', '7d', '8d', '9d', 'Td', 'Jd', 'Qd', 'Kd', 'Ad',
         '2c', '3c', '4c', '5c', '6c', '7c', '8c', '9c', 'Tc', 'Jc', 'Qc', 'Kc', 'Ac']

# convert to array
card_array = np.asarray(cards)

# reshape into desired layout
card_array = card_array.reshape((4, 13))

rows, _ = card_array.shape

content = []
for r in range(rows):
    row = card_array[r, :]
    row_content = []
    for c in row:
        row_content.append(
            dbc.Col(
                dbc.Card(
                    children=html.Button(c, id=c),
                )
            )
        )
    dbc_rows = dbc.Row(
        id=f'row{r}',
        children=row_content
    )
    content.append(dbc_rows)

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div(
    [
        dbc.Container(
            id='container',
            children=content,
            fluid=True
        ),
        html.Br(),
        html.Div(id='output')
    ]
)


@app.callback(
    Output('output', 'children'),
    [
        Input(card_name, 'n_clicks')
        for card_name in cards
    ],
    prevent_initial_call=True
)
def update(*args):
    trigger = callback_context.triggered_id
    return f'you clicked button {trigger}'


if __name__ == '__main__':
    app.run(debug=True)

I used dbc.Cards so you could give the cards the ID instead of the buttons if needed. Or you could change the dbc.Cards to something different. Maybe that’s not what you were after, in the end I still do not fully understand your question :sweat_smile:

thanks, this is perfect, I just started this new proyect, and didn’t know from where to start. This is a good beginning

Here is what would happen if you followed my suggestion:

Coded (used Aimped for initial):

import dash
from dash import html, Input, Output, callback_context
import numpy as np
import dash_bootstrap_components as dbc

# raw input
cards = ['2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As',
         '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', 'Th', 'Jh', 'Qh', 'Kh', 'Ah',
         '2d', '3d', '4d', '5d', '6d', '7d', '8d', '9d', 'Td', 'Jd', 'Qd', 'Kd', 'Ad',
         '2c', '3c', '4c', '5c', '6c', '7c', '8c', '9c', 'Tc', 'Jc', 'Qc', 'Kc', 'Ac']

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div([html.Div(i, id=i, n_clicks=0, className='myCustomCard') for i in cards] +
                      [html.Div(id='output')], id='myCardHolder')


@app.callback(
    Output('output', 'children'),
    [
        Input(card_name, 'n_clicks')
        for card_name in cards
    ],
    prevent_initial_call=True
)
def update(*args):
    trigger = callback_context.triggered_id
    return f'you clicked button {trigger}'


if __name__ == '__main__':
    app.run(debug=True)
1 Like

haha - this is a lot of fun! I was trying to think of an example for pattern matching callback for the Dash Example Index and this topic inspired me.

By using pattern matching callbacks, you can avoid having 52 inputs in the callback.

I’ll probably turn this into some type of simple game for the Example Index, but in the meantime, here’s my version:

card_game

import random
from dash import Dash, html, Input, Output, ALL, ctx
import dash_bootstrap_components as dbc
from dash_iconify import DashIconify

app = Dash(__name__, external_stylesheets=[dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP])

SUITS = ["spades", "clubs", "diamonds", "hearts"]
RANKS = ["ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "jack", "queen", "king"]


def create_deck(shuffle=False):
    """Create a  deck of 52 cards"""
    deck = [(s, r) for s in SUITS for r in RANKS]
    if shuffle:
        random.shuffle(deck)
    return deck


def make_card(card):
    """format the card as a button"""
    suit, rank = card
    color = "black" if suit in ["spades", "clubs"] else "red"
    card_icon = DashIconify(
        icon=f"game-icons:card-{rank}-{suit}", color=color, height=60
    )
    return dbc.Button(
        [card_icon], color="white", className="p-0", id={"index": f"{suit}-{rank}"}
    )


def deck_layout(deck):
    """make card layout"""
    return [dbc.Row(dbc.Col([make_card(c) for c in deck if s in c])) for s in SUITS]


deck = create_deck()

app.layout = dbc.Container(
    [
        html.H1("Select a Card"),
        html.Div(deck_layout(deck)),
        html.H2("You Selected:"),
        html.Div(id="card-selected"),
    ]
)


@app.callback(
    Output("card-selected", "children"),
    Input({"index": ALL}, "n_clicks"),
    prevent_initial_call=True,
)
def selected(_):
    selected_card = ctx.triggered_id.index
    suit, _, rank = selected_card.partition("-")
    color = "black" if suit in ["spades", "clubs"] else "red"
    return DashIconify(icon=f"game-icons:card-{rank}-{suit}", color=color, height=60)

if __name__ == "__main__":
    app.run_server(debug=True)


3 Likes

really cool!

you R all the best!

how do I change to 4 colors?

color = “black” if suit is [“spades”] or “green” if suit is [“clubs”] or “blue” if suit is [“diamonds”]else “red”

(correctly)

You do like on-liners, don’t you? :rofl:

I’ll have to take a look into pattern matching callbacks, looks interesting.

So neat. Wow. Thanks Ann. It’s amazing how much can be done with so few lines of code.