Search code examples
jqueryasp.netmodalpopupextender

After ModalPopup closed, jQuery stops working


Scenario
As part of a "View case" page there should be a function to add a new case note.
A case note can be "visible externally" with the option to provide different 'external' text.

What I have done, is to use a ModalPopupExtender from the ASP.NET Ajax Control Toolkit which fires when the 'Add note' button is clicked, to show a panel with a textbox to enter the new note. There is a CheckBox underneath the textbox which the user can tick if the note is available externally.

When ticked, some jQuery should fire, which fades in the 'public note content' box and pre-sets it to the value of the 'note content' text box.

Once the public text is entered, the user should click 'Save note'. The note is written to the database, the GridView of notes is rebound and the ModalPopup hides.

The jQuery is referenced once, on Page_Load as follows.

ScriptManager.RegisterClientScriptInclude(Me, Me.GetType, "BensJQuery", Page.ResolveUrl("~/include/BensJquery.js"))

Problem:
The user might then want to add a second note. They click 'Add note' again, the ModalPopupExtender shows the modal popup again. This time, if they click the 'Available externally' checkbox, the jQuery does NOT fire. The public note content area does not show. The test alert() does not show.

The same problem happens if the user clicks 'Cancel' and does not actually add a note. The ModalPopup will disappear but then they cannot use it properly if they try to subsequently add a note.

Markup

<asp:UpdatePanel ID="updNotes" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <asp:GridView ID="gvNotes" runat="server" AllowPaging="true" PageSize="10" AutoGenerateColumns="false" Width="100%">
            <PagerSettings Mode="NumericFirstLast" Position="TopAndBottom" />
            <Columns>
                <asp:BoundField HeaderText="Date" DataField="CreationDate" />
                <asp:BoundField HeaderText="Author" DataField="CreatedBy" />
                <asp:BoundField HeaderText="Note" DataField="Text" ItemStyle-Width="80%" />
            </Columns>
        </asp:GridView>                                

       <p><asp:Button ID="btnAddNewNote" runat="server" Text="Add note" CssClass="addButton" CausesValidation="false" /></p>

        <asp:Panel ID="pnlNewNote" runat="server" GroupingText="New note" style="display: none;" CssClass="mdlPopupPanel">
            <p>To add a new note, enter the note information here and click 'Add note'</p>

            <scc:TextBox runat="server" ID="txtNewNoteContent" TextMode="MultiLine" CssClass="mainNoteContent input"
            Rows="6" Width="75%" Label="Text" ValidationGroup="NewNote" /> 

            <p>
                <asp:CheckBox ID="chkMakeAvailExternally" CssClass="chkAvailExternally" runat="server" />
                <asp:Label runat="server" Text=" Note is available to public" AssociatedControlID="chkMakeAvailExternally" />
            </p>

            <div class="publicNoteContent" style="display: none;">
                <scc:TextBox ID="txtPublicNoteContent" runat="server" Label="Text to show to public" 
                 TextMode="MultiLine" Rows="6" Width="75%" CssClass="publicNoteContent input" Required="false" />
            </div>

            <p>
                <asp:Button ID="btnSaveNote" runat="server" CssClass="confirmButton" Text="Save note" ValidationGroup="NewNote" />
                <asp:Button ID="btnCancelAddNote" runat="server" CssClass="cancelButton" Text="Cancel" CausesValidation="false" />
            </p>

        </asp:Panel>       
        <act:ModalPopupExtender ID="mpopNewNote" runat="server" TargetControlID="btnAddNewNote" PopupControlID="pnlNewNote" />

    </ContentTemplate>
</asp:UpdatePanel>

jQuery

$(document).ready(function () {
    $(".chkAvailExternally").click(function (event) {
        alert('test'); // This alert displays for the first note added but not subsequent notes

        var publicNoteDiv = $(this).parent().parent().find('div.publicNoteContent');

        if (publicNoteDiv.is(":visible")) {
            publicNoteDiv.fadeOut();
        }
        else {
            var existingText = publicNoteDiv.parent().find('textarea.mainNoteContent').text();
            if (publicNoteDiv.find('textarea.publicNoteContent').text() == '') {
                publicNoteDiv.find('textarea.publicNoteContent').text(existingText);
            }
            publicNoteDiv.fadeIn();
        }
    });    
});

Code-behind

Protected Sub btnSaveNote_Click(sender As Object, e As System.EventArgs) Handles btnSaveNote.Click
    Dim CaseRef As String = Request("CaseReference")
    Using ctx As New CAMSEntities
        Dim c As [Case] = ctx.Cases.Single(Function(x) x.Reference = CaseRef)

        c.AddNote(txtNewNoteContent.Text, chkMakeAvailExternally.Checked, txtPublicNoteContent.Text)

        ctx.SaveChanges()

        gvNotes.DataSource = c.Notes.OrderByDescending(Function(x) x.CreationDate).ToList
        gvNotes.DataBind()

        txtNewNoteContent.Text = String.Empty
        chkMakeAvailExternally.Checked = False
        txtPublicNoteContent.Text = String.Empty
    End Using
End Sub

Solution

  • Instead of using $(".chkAvailExternally").click( directly, use $(".chkAvailExternally").live("click",function(){..

    Read about it here and here. Basically the second time for the modal popup, the elements are not part of DOM anymore, so you have to attach an event handler for those.

    Update: After reading some more on it, perhaps you would be better off using a delegate instead of live to reduce the scope. More info here.