ASP.Net Repeater With Bootstrap 3 Modal Confirmati

2019-08-27 12:46发布

问题:

I have spent all day trying to achieve this but have failed spectacularly.

I have an ASP.Net repeater on my page and have added a LinkButton which pops open a beautiful Bootstrap 3 confirmation modal window (for deletion of a record).

I have tried to cobble together solutions but my Java knowledge is failing me.

This is my Repeater:

<asp:Repeater OnItemCommand="rptImages_ItemCommand" ID="rptImages" OnItemCreated="rptImages_ItemCreated" OnItemDataBound="rptImages_ItemDataBound" runat="server">
                                    <HeaderTemplate>
                                    </HeaderTemplate>
                                    <ItemTemplate>

                                        <asp:Image ID="imgThumb" CssClass="product-image" runat="server" ImageUrl='<%# string.Format("~/{0}", Eval("ImageUrl")) %>' />

                                        <asp:LinkButton ID="lbDelete" runat="server" CommandArgument='<%#Eval("ProductImageId")%>' CommandName="delete" data-toggle="tooltip" data-placement="top" title="Delete this record" OnClientClick="return ConfirmDelete()"><i class="image-button fa fa-trash"></i></asp:LinkButton>

                                    </ItemTemplate>
                                    <FooterTemplate>
                                    </FooterTemplate>
                                </asp:Repeater>

This is my Java Script at the top of the page:

<script>
    function ConfirmDelete() {
        $('#DeleteModal').modal(); // initialized with defaults
        // $('#DeleteModal').modal({ keyboard: false })   // initialized with no keyboard
        // $('#DeleteModal').modal('show')
        return false;
    }
</script>

This is the code of my Bootstrap Pop-up:

<div class="modal fade" id="DeleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                        <h4 class="modal-title" id="H3">Delete this record?</h4>
                    </div>
                    <asp:UpdatePanel ID="upDel" runat="server">

                <ContentTemplate>
                    <div class="modal-body">
                        Are you sure you want to delete this image?
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                        <asp:Button ID="btnDeleteImage" runat="server" OnClick="btnDeleteImage_Click" CssClass="btn btn-danger" Text="Delete" />
                    </div>
                    </ContentTemplate>

                <Triggers>

                    <asp:AsyncPostBackTrigger  ControlID="btnDeleteImage" EventName="Click" />

                </Triggers>

            </asp:UpdatePanel>
                </div>
            </div>
        </div>

When I click the delete button, the bootstrap modal appears. On the "Cancel" button, the modal closes. On the "Delete" button, the modal also closes but my gridview item command never fires.

I would be eternally grateful for any help.

Thank you very much in advance!

回答1:

First, I see some markup for an UpdatePanel which I don't believe is necessary. Generally speaking, when it comes to UpdatePanels it's better to get things working first and then implement them later if truly needed.

So, in looking at this more closely I want to make sure you understand the difference between a synchronous call versus an asynchronous call.

If you took advantage of the built in js confirm() modal things would work as expected:

OnClientClick="return window.confirm('Are you sure you want to delete this image')"

This works because the built-in confirm() function is synchronous, meaning it waits for a user response before returning.

However, Bootstrap modals are asynchronous which means this:

OnClientClick="return ConfirmDelete()"

calls this:

function ConfirmDelete() 
{
  $('#DeleteModal').modal(); // initialized with defaults
  return false;
}

which, because the call to .modal() is asynchronous causes it to return immediately and so ConfirmDelete() exits and returns false, which is good because it prevents the postback and allows the modal to be displayed. Otherwise the page would postback and you'd never see the modal.

Now, at this point, because ConfirmDelete() has already returned, you are now outside the world of the repeater. So the one thing you have to do is pass to the modal the unique key data associated with the repeater row that activated the modal such that on confirmation you delete the appropriate record.

Once you click btnDeleteImage it's going to cause a postback to btnDeleteImage_Click in your code behind. This is where you add the code to delete the appropriate record.

How do you pass along that key data? One possibility is to fill one or more HiddenField that are referenced on postback. Hidden fields are a good way to pass data between Client side and Server side code.

so let's say you add this to your .aspx page:

<asp:HiddenField ID="hfDeleteParameter1" runat="server" ClientIDMode="Static" />

NB: ClientIDMode="Static" prevents the id from getting name mangled so it can be referenced as expected in client side js code.

So then in the ItemDataBound event you can build the OnClientClick function call programmatically where you pass key data as a parameter:

This is VB, if you use C# it should be similar.

Private Sub rptImages_ItemDataBound(sender As Object, e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptImages.ItemDataBound
    If e.Item.ItemType = ListItemType.Item Or 
       e.Item.ItemType = ListItemType.AlternatingItem Then
         Dim lb As LinkButton = e.Item.FindControl("lbDelete")
         lb.OnClientClick = String.Format("return ConfirmDelete('{0}');",
                            row_specific_key_data)
    End If
End Sub

and in the js:

function ConfirmDelete(rowData) {
    $('#hfDeleteParameter1').val( rowData );
    $('#DeleteModal').modal(); // initialized with defaults
    return false;
}

Then when the user confirms delete by clicking btnDeleteImage this will cause a postback and calls the buttons Click event btnDeleteImage_Click where you can access the hidden field:

Private Sub btnDeleteImage_Click(sender As Object, e As EventArgs) Handles btnCustomLookback.Click
    dim keydata as string = hfDeleteParameter1.value

    // do delete 
End Sub

This is one option of many.

For the record you could make a call to the repeaters DataSource Delete operation, but you would need to fill the parameters and then call DataSource.delete() but that's not really how this is suppose to work.

Delete/Update/Insert operations defined in a server control datasource are intended for use by that control, it automatically manages the parameters. To call delete() operations like this, where you have to override those managed parameters, is a bad habit to get into.

So you need to write a custom delete function which acts on the correct key information.



回答2:

Similarly to @fnostro great answer and explanation, I would like to share what exactly I have done to get it to work.

Repeater HTML Tag where it contains the ASP:LinkButton (Used for Delete)

<asp:Repeater runat="server"> 
  <HeaderTemplate>
  </HeaderTemplate>
  <ItemTemplate>
  <asp:Image ID="imgThumb" CssClass="product-image" runat="server" ImageUrl='<%# string.Format("~/{0}", Eval("ImageUrl")) %>' />
  <asp:LinkButton ID="lbDelete" runat="server" data-imageid='<%# Eval("ProductImageId")%>' OnClientClick="return ConfirmDelete(this)"><i class="image-button fa fa-trash"></i></asp:LinkButton> 
  </ItemTemplate>
  <FooterTemplate>
  </FooterTemplate> 
</asp:Repeater>

JavaScript Code, passing HTML5 parameter to an ASP:HiddenField and also passing the value to the modal.

 <script type="text/javascript">
        //Confirm Record Deletion
        function ConfirmDelete(cnt) {
            var doc = document.getElementById("<%= myHiddenField.ClientID%>");
            doc.value = cnt.getAttribute("data-imageid");
            var itemRef = document.getElementById("currentItem");
            itemRef.innerHTML = doc.value
            $('#DeleteModal').modal('show'); // initialized with defaults
            return false;
        }
</script>

ASP:HiddenField shall contain the reference data (placed outside the repeater).

<asp:HiddenField ID="myHiddenField" runat="server" ClientIDMode="Static" />

Bootstrap Modal tags, placed right below your repeater.

<div class="modal fade" id="DeleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalTitle" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered" role="document">
     <div class="modal-content">
        <div class="modal-header">
            <h5 class="modal-title" id="myModalTitle">Confirm Delete</h5>
               <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
               </button>
        </div>
        <div class="modal-body">Please confirm that you want to delete this Image with ID (<strong><span id="currentItem"></span></strong>) ?
        </div>
        <div class="modal-footer">
           <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <asp:Button ID="btnDelete" runat="server" CssClass="btn btn-danger" Text="Delete" />
       </div>
    </div>

Code-Behind for Delete Button.

Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
        //My delete procedure
        //To access your ImageID stored in the HiddenField, use.
        //myHiddenField.Value
End Sub