ASP.NET CheckBox to call code behind after js confirm() returns true

29 views Asked by At

i would like to achieve if the checkbox is checked or unchecked, prompt a confirmation message. after that only perform code behind logic to update database. But then i realised that the __doPostBack cant reach out to the GV_SplitPaymentOption_RowCommand function. Why is it?

As i research that CheckBox controls don't inherently support the CommandName and CommandArgument, but __doPostBack function can still be used with CheckBox controls to initiate a postback with additional arguments. So not sure which part i am missing or wrong. Any experts able to help as i am stucked on it quite long.

<script type="text/javascript">
        function confirmCheckBoxChange(checkbox) {
            var currentChecked = checkbox.checked;
            var row = checkbox.closest("tr");

            var message = currentChecked ? "Are you sure you want to activate?" : "Are you sure you want to deactivate?";

            if (!confirm(message)) {
                return false;
            }

            __doPostBack(checkbox.id);

            return true;
        }
</script>           

<asp:GridView ID="GV_Member" runat="server" Width="100%" AutoGenerateColumns="False"
                OnRowDataBound="GV_Member_RowDataBound" OnRowCommand="GV_Member_RowCommand">
                <Columns>
                    <asp:TemplateField HeaderText="No">
                        <ItemTemplate>
                            <asp:Label ID="lblNo" runat="server" Text='<%# Container.DataItemIndex + 1 %>' Visible="true"></asp:Label>
                        </ItemTemplate>
                        <HeaderStyle HorizontalAlign="CENTER" Width="20" />
                        <ItemStyle HorizontalAlign="LEFT" />
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Name">
                        <ItemTemplate>
                            <asp:Label ID="lblName" runat="server" Text='<%# Bind("Name") %>'></asp:Label>
                        </ItemTemplate>
                        <HeaderStyle HorizontalAlign="CENTER" />
                        <ItemStyle HorizontalAlign="CENTER" />
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Active" HeaderStyle-Width="10%" ItemStyle-Width="10%">
                        <ItemTemplate>
                            <label class="switch" style="margin-left: 5px;">
                                <asp:CheckBox ID="chkActive" runat="server" Checked='<%# Bind("Active") %>' CommandName="UpdateActive" onclick="confirmCheckBoxChange(this);" AutoPostBack="false" CommandArgument='<%# Eval("Gender") + "&" + Eval("BirthCode") + "&" + Eval("Address")%>' />
                                <span class="slider round"></span>
                            </label>
                            <asp:Label ID="lblBVStatus" runat="server" Text='<%# Convert.ToBoolean(Eval("Active")) ? "Activate" : "Deactivate" %>' Visible="true" Style="margin-left: 5px;"></asp:Label>
                        </ItemTemplate>
                        <HeaderStyle HorizontalAlign="CENTER" />
                        <%--<ItemStyle HorizontalAlign="CENTER" />--%>
                    </asp:TemplateField>
                </Columns>
</asp:GridView>
1

There are 1 answers

0
Albert D. Kallal On BEST ANSWER

There is no real need to use the row command here.

In any GridView, or ListView or whatever?

You can drop in a standard button, check box, drop down list or whatever, and simply use the standard events for that given control.

However, keep in mind that when you have a check box with auto post-back = true, and you have BOTH a client side click event and a server-side event?

Unlike a button, for a check box, the auto post back code and the click event are "combined" into one click event.

This means that your client side click event has to take above into account and the click expression has to be written in such a way that if the js code returns true, then the code continues.

This example shows the required setup:

    <asp:CheckBox ID="chk1" runat="server" Text="Check me"
        OnCheckedChanged="chk1_CheckedChanged"
        AutoPostBack="true"
        onclick="if (!confirmCheckBoxChange(this)) {return false};"

        />

    <script>

        function confirmCheckBoxChange(chkbox) {

            var message = chkbox.checked ? "Are you sure you want to activate?"
                            : "Are you sure you want to deactivate?";

            if (!confirm(message)) {
                return false;
            }

            return true;
        }
    </script>

So, in above, we have both a server side click event, and a client side click event. With a check box, both events are combined into one client side click event, so note how I changed the client side click event to "continue" the injected code that follows the client side click js code.

So, use this format:

"if (!confirmCheckBoxChange(this)) {return false};"

As opposed to using this:

    "return confirmCheckBoxChange(this)"

Hence, keep in mind for above retuning true, then we want the asp.net server-side expression (injected by asp.net) to run when the function returns true.

So, the next issue of course is do we care, or have to worry about, or use the command methods of the GridView? Or is there a better way to pick up the current GridView ?

And the answer is yes, and thus one will find it better to ignore and not use the GridView command event.

In fact, recommend in most cases you don't bother with the command event of the GridView (or ListView etc.).

Since then, each control can have its own stand-alone event stub (button, combo box, check box etc.), then you don't have to place a mumbo jumbo of code for multiple controls into that one command event of the GridView.

The result is a wonderful easy to use set of standard events for that control in question.

So, assuming we set the check box with auto-post back = true, then we can use the "long time" feature of a button, check box etc. that when the client-side routine returns true, the server-side code runs. And if we return false, then the server-side events do not run.

So, now with the above information, here is a working GridView based on concepts outlined above.

<asp:GridView ID="GVHotels" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ID" CssClass="table table-hover"
    Width="45%">
    <Columns>
        <asp:BoundField DataField="FirstName" HeaderText="FirstName" />
        <asp:BoundField DataField="LastName" HeaderText="LastName" />
        <asp:BoundField DataField="City" HeaderText="City" />
        <asp:BoundField DataField="HotelName" HeaderText="HotelName" />
        <asp:BoundField DataField="Description" HeaderText="Description" />
        <asp:TemplateField HeaderText="Active"
            ItemStyle-HorizontalAlign="Center"
            HeaderStyle-HorizontalAlign="Center" ItemStyle-Width="120px">
            <ItemTemplate>
                <asp:CheckBox ID="chk1" runat="server"
                    Checked='<%# Eval("Active")%>'
                    OnCheckedChanged="chk1_CheckedChanged"
                    AutoPostBack="true"
                    onclick="if (!confirmCheckBoxChange(this)) {return false};" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

<script>

    function confirmCheckBoxChange(chkbox) {

        var message = chkbox.checked ? "Are you sure you want to activate?"
            : "Are you sure you want to deactivate?";

        if (!confirm(message)) {
            return false;
        }

        return true;
    }
</script>

Note how we use just the "regular" event for the check box along with the autopostback= "true" to run the server side code.

Code behind:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadGrid();
    }

    void LoadGrid()
    {
        string strSQL = @"SELECT * FROM tblhotelsA
                        ORDER BY HotelName";

        GVHotels.DataSource = General.MyRst(strSQL);
        GVHotels.DataBind();    
    }

    protected void chk1_CheckedChanged(object sender, EventArgs e)
    {
        CheckBox chk = (CheckBox)sender;
        GridViewRow gRow = (GridViewRow)chk.NamingContainer;

        Debug.Print($"check box checked = {chk.Checked}");
        Debug.Print($"Row index click = {gRow.RowIndex}");

        int PK = (int)GVHotels.DataKeys[gRow.RowIndex]["ID"];
        Debug.Print($"Data base PK value = {PK}");

        // get Hotel Name from Grid view row
        Debug.Print($"Hotel Name = {gRow.Cells[3].Text}");

    }

And the result is this:

enter image description here

Debug output:

check box checked = False
Row index click = 1
Data base PK value = 10
Hotel Name = Canadian Rocky Mountain Resorts

So, as above shows, we can with ease get the row that we clicked on, and from that we have use of row index, the database PK row ID (data keys), and of course the state of the check box. And thus, no real need to use the command object, or the built in GridView events.