Ag grid row change dynamically

@app.callback(
    Output('ag-grid-tab1', 'rowData'),
    Output('feedback-store', 'data'),
    Output("no-data-message-tab1", "style", allow_duplicate=True),
    [
        Input('ag-grid-tab1', 'rowData'), 
        Input("ag-grid-tab1", "cellRendererData"),
        State('feedback-store', 'data')
    ],
    prevent_initial_call=True,
)
def update_row_data(rowData, cellClicked, feedback_store):
    if cellClicked:
        clicked_row = cellClicked.get('rowIndex')
        action = cellClicked.get('value', {}).get('action', "")
        # print("action", action)
        # print("clicked_row", clicked_row)
        if feedback_store is None:
          feedback_store = {}
        if clicked_row is not None:
      
            if action == 'downVote':
                rowData[clicked_row]['downVote_clicked'] = True
            elif action == 'upVote':             
                rowData[clicked_row]['upVote_clicked'] = True                
        for row in rowData:
            if row.get('downVote_clicked', True) or row.get('upVote_clicked', True):
                
                article_date = rowData[clicked_row].get('Article Date')
                company = rowData[clicked_row].get('Company')
                quote = rowData[clicked_row].get('Quote')
                unique_key = generate_unique_key(article_date, company, quote)
                if unique_key not in feedback_store:
                    feedback_store[unique_key] = {
                        'Article Date': article_date,
                        "DocId": rowData[clicked_row].get('docId'),
                        'Company': company,
                        'Quote': quote,
                        # 'News Category': rowData[clicked_row].get('News Category'),
                        # 'Quote Signal': rowData[clicked_row].get('Quote Signal'),
                        # 'company_url': rowData[clicked_row].get('company_url'),
                        # 'article_url': rowData[clicked_row].get('article_url'),
                        'upVote_clicked': rowData[clicked_row].get('upVote_clicked', False),
                        'downVote_clicked': rowData[clicked_row].get('downVote_clicked', False)
                    }
                # print("unique_key=====", unique_key)
                # print("feedback_store  =============", feedback_store)
   
    return rowData, feedback_store, styl_msg_none_tab1



dagcomponentfuncs.Button = function (props) {
    const { setData, data } = props;

    const [upClicked, setUpClicked] = React.useState(data.upVote_clicked || false);
    const [downClicked, setDownClicked] = React.useState(data.downVote_clicked || false);

    const [isDisabled, setIsDisabled] = React.useState(data.upVote_clicked || data.downVote_clicked); 
    const [isUpHovered, setUpHovered] = React.useState(false);
    const [isDownHovered, setDownHovered] = React.useState(false);

    console.log("downVote_clicked", downClicked);
    console.log("upVote_clicked", upClicked);

    const DEFAULT_DOWNVOTE_IMAGE = data.DEFAULT_DOWNVOTE_IMAGE;
    const CLICKED_DOWNVOTE_IMAGE = data.CLIKED_DOWNVOTE_IMAGE;
    const DEFAULT_UPVOTE_IMAGE = data.DEFAULT_UPVOTE_IMAGE;
    const CLICKED_UPVOTE_IMAGE = data.CLIKED_UPVOTE_IMAGE;

    function onUpClick() {
        if (isDisabled) return; 

        const newUpClicked = !upClicked;
        setUpClicked(newUpClicked);
        setDownClicked(false);  
        setIsDisabled(true); 
      
        setData({ action: "upVote", upVote_clicked: newUpClicked, downVote_clicked: false, data });
    }

    function onDownClick() {
        if (isDisabled) return; 

        const newDownClicked = !downClicked;
        setDownClicked(newDownClicked);
        setUpClicked(false); 
        setIsDisabled(true); 

        setData({ action: "downVote", upVote_clicked: false, downVote_clicked: newDownClicked, data });
    }

    const buttonClass = (upClicked || downClicked) ? 'clicked' : '';
    return React.createElement(
        'div',
        { className: `custom-buttons ${buttonClass}` },
        React.createElement(
            'img',
            {
                onClick: onDownClick,
                onMouseEnter: () => !isDisabled && setDownHovered(true),  
                onMouseLeave: () => setDownHovered(false),
                src: (downClicked || isDownHovered) ? CLICKED_DOWNVOTE_IMAGE : DEFAULT_DOWNVOTE_IMAGE,
                style: {
                    width: '16px',
                    height: '16px',
                    marginRight: '10px',  // Adjust this value to change the spacing
                    cursor: isDisabled ? 'not-allowed' : 'pointer',
                    opacity: isDisabled ? 0.5 : 1
                }
            }
        ),
        React.createElement(
            'img',
            {
                onClick: onUpClick,
                onMouseEnter: () => !isDisabled && setUpHovered(true),  
                onMouseLeave: () => setUpHovered(false),
                src: (upClicked || isUpHovered) ? CLICKED_UPVOTE_IMAGE : DEFAULT_UPVOTE_IMAGE,
                style: {
                    width: '16px',
                    height: '16px',
                    cursor: isDisabled ? 'not-allowed' : 'pointer',
                    opacity: isDisabled ? 0.5 : 1
                }
            }
        )
    );
};

After clicking the vote buttons(up/down) in ag grid . That vote(up/down) should persist if user scroll or do any filter in ag grid … That value are persisting if reload the rodata in aggrid… Without callback is that possible ?

Hello @sushma,

Welcome to the community!

You should be able to manipulate the data from the cellRenderer without needing to perform a callback. And yes, this should also persist when the user is scrolling.

Could you please create an MRE for this?

Can you provide any example cellRenderer without needing to perform a callback.

Check here:

Pay attention to the props.node.setDataValue(colId, checked); this is what will update data directly in the rowData and also triggers a cellValueChanged event.

Thanks for your feedback. I will check if any help required posted here.