Unable to initiate jquery autocomplete after FormView.ChangeMode in ASP.NET Dynamic Data application

StackOverflow https://stackoverflow.com/questions/16925483

Pergunta

I created an ASP.NET Dynamic Data Entities Web Application. I have a foreign key to a table containing 6000+ records. By default this the Dynamic Data application uses the ForeignKey fieldtemplate.

When in edit or insert mode the ForeignKey fieldtemplate results in a dropdown with 6000+ items. This reduces performance and is not userfriendly at all, so I created a custom FieldTemplate to use jquery autocomplete and a WCF REST enabled webservice returning json to fill the autocomplete list with a maximum of 25 items. The custom fieldtemplate contains 2 textboxes, one for the name, the other one for the id. The textbox for the id is hidden using CSS. When typing in the textbox for the name the autocomplete function narrows down the scope and by selecting a name, the id is set using javascript.

function setAutoCompleteCustomerField() {
    if (!window.location.origin) window.location.origin = window.location.protocol + "//" + window.location.host;

    $(function () {
        $("input[id$='<%= txtCustomerName.ClientID %>']").autocomplete({
            source: function (request, response) {
                $.ajax({
                    url: window.location.origin + "/AutocompleteService.svc/CustomerLookup",
                    data: {
                        text: request.term,
                        count: 25
                    },
                    dataType: "json",
                    contentType: "application/json; charset=utf-8",
                    success: function (data) {
                        response($.map(data, function (item) {
                            return {
                                value: item.Name,
                                id: item.Id
                            }
                        }))
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        alert(errorThrown);
                    }
                });
            },
            minLength: 2,
            select: function (event, ui) {
                $("#<%= txtCustomerId.ClientID %>").val(ui.item.id);
                $("#<%= txtCustomerId.ClientID %>").change();
            }
        });
    });
}

I use the ListView pagetemplate to display, edit and insert data. The pagetemplate consists of an UpdatePanel with the GridView and the FormView. When selecting a record in the GridView the data is displayed in the FormView. The DefaultMode of the FormView is set to Edit. When I start typing in the name all works well. I can select other values and update etc. So far so good.

I also have an "Insert new record" linkbutton located within the updatepanel. When clicking this linkbutton, the FormViewMode of the FormView is set to Insert.

protected void lnkInsertNew_Click(object sender, EventArgs e)
{
    FormView1.ChangeMode(FormViewMode.Insert);
}

When in Insert mode the same custom FieldTemplate is loaded but the autocomplete is no longer working. I tried 2 methods to reinitiate the autocomplete functionality.

The first thing I tried was:

if (Sys.WebForms) {
    Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(function (sender, args) {
        setAutoCompleteCustomerField();
    });
}

The second:

$(document).ready(function () {
        Sys.WebForms.PageRequestManager.getInstance().add_endRequest(setAutoCompleteCustomerField);
});

Both resulted in the same behaviour. The setAutoCompleteCustomerField function is executed. However, it's seems that the execution comes to early. When I place an alert within the setAutoCompleteCustomerField function to display the id of the textbox for the customer name the value null is displayed. This indicates that the element is not yet loaded.

alert($("#<%= txtCustomerName.ClientID %>").attr("id"));

How can I overcome this issue? How can I make sure that all elements are loaded before calling the setAutoCompleteCustomerField function? Thanks in advance for you help!

UPDATE Added the code from ListDetails.aspx

<asp:Content ID="headContent" ContentPlaceHolderID="head" Runat="Server">
<% if (false) { %><script src="~/Scripts/jquery-1.5-vsdoc.js" type="text/javascript"></script><% } %>
</asp:Content>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <asp:DynamicDataManager ID="DynamicDataManager1" runat="server" AutoLoadForeignKeys="true">
        <DataControls>
            <asp:DataControlReference ControlID="FormView1" />
            <asp:DataControlReference ControlID="GridView1" />
        </DataControls>
    </asp:DynamicDataManager>

    <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Always">
        <ContentTemplate>

            <div class="DD">               <asp:DynamicValidator runat="server" ID="GridViewValidator" ControlToValidate="GridView1" Display="None" CssClass="validator" />
                <asp:DynamicValidator runat="server" ID="FormViewValidator" ControlToValidate="FormView1" Display="None" CssClass="validator" />

                <div id="filterBox">
                <a href="#" id="filterToggle"><%= GalleryOnline.Globalization.Resources.Common.Label_ShowOrHideFilters %></a>
                    <div id="filters">
                    <asp:QueryableFilterRepeater runat="server" ID="FilterRepeater">
                        <ItemTemplate>
                            <span class="filterItem">
                            <asp:Label runat="server" Text='<%# Eval("DisplayName") %>' OnPreRender="Label_PreRender" />
                            <asp:DynamicFilter runat="server" ID="DynamicFilter" OnFilterChanged="DynamicFilter_FilterChanged" />
                            </span>
                        </ItemTemplate>
                    </asp:QueryableFilterRepeater>
                    </div>
                </div>
            </div>

            <asp:GridView ID="GridView1" runat="server" DataSourceID="GridDataSource" EnablePersistedSelection="true"
                AllowPaging="True" AllowSorting="True" OnDataBound="GridView1_DataBound" AutoGenerateSelectButton="true"
                OnRowEditing="GridView1_RowEditing" OnSelectedIndexChanging="GridView1_SelectedIndexChanging"
                OnRowDeleted="GridView1_RowDeleted" OnRowUpdated="GridView1_RowUpdated" ShowHeaderWhenEmpty="true"
                OnRowCreated="GridView1_RowCreated" CssClass="grid" OnPreRender="GridView1_PreRender"
                RowStyle-CssClass="td" HeaderStyle-CssClass="th" GridLines="None" AutoGenerateColumns="false">
                <PagerStyle CssClass="DDFooter" />
                <SelectedRowStyle CssClass="td selected" />
                <AlternatingRowStyle CssClass="td alternating" />
                <PagerTemplate>
                    <asp:GridViewPager runat="server" />
                </PagerTemplate>
                <EmptyDataTemplate>
                    <%= GalleryOnline.Globalization.Resources.Common.Message_NoData %>
                </EmptyDataTemplate>
            </asp:GridView>

            <div class="gridOptions">
                <asp:LinkButton ID="lnkInsertNew" runat="server" OnClick="lnkInsertNew_Click" CausesValidation="false">+ <%= GalleryOnline.Globalization.Resources.Common.InsertNewItem %></asp:LinkButton>
            </div> 

            <asp:EntityDataSource ID="GridDataSource" runat="server"/>

            <asp:QueryExtender ID="GridQueryExtender" TargetControlID="GridDataSource" runat="server">
                <asp:DynamicFilterExpression ControlID="FilterRepeater" />
            </asp:QueryExtender>

            <asp:Panel ID="DetailsPanel" runat="server" CssClass="tabs">
                <asp:FormView ID="FormView1" runat="server" DataSourceID="DetailsDataSource" RenderOuterTable="false"
                    OnPreRender="FormView1_PreRender" OnModeChanging="FormView1_ModeChanging" OnItemUpdated="FormView1_ItemUpdated"
                    OnItemInserted="FormView1_ItemInserted" OnItemDeleted="FormView1_ItemDeleted" OnDataBound="FormView1_DataBound" DefaultMode="Edit">
                    <ItemTemplate>
                        <asp:DynamicEntity runat="server" />
                        <div class="formActions">
                            <asp:Button runat="server" CommandName="Edit" Text="<%# GalleryOnline.Globalization.Resources.Common.Edit %>" />
                            <asp:Button runat="server" CommandName="Delete" Text="<%# GalleryOnline.Globalization.Resources.Common.Delete %>" OnClientClick='<%# "return confirm(\"" + GalleryOnline.Globalization.Resources.Common.Question_DeleteOrCancel +"\");" %>' />
                            <asp:Button runat="server" CommandName="New" Text="<%# GalleryOnline.Globalization.Resources.Common.New %>" />
                        </div>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:DynamicEntity runat="server" Mode="Edit" />
                        <div class="formActions">
                            <table border="0" cellpadding="0" cellspacing="0">
                                <tr>
                                    <td valign="top"><asp:Button runat="server" CommandName="Update" Text="<%# GalleryOnline.Globalization.Resources.Common.Update %>" ID="btnUpdate" /></td>
                                    <td valign="top"><asp:Button ID="Button5" runat="server" CommandName="Cancel" Text="<%# GalleryOnline.Globalization.Resources.Common.Cancel %>" CausesValidation="false" /></td>
                                    <td valign="top"><asp:Button ID="Button6" runat="server" CommandName="Delete" Text="<%# GalleryOnline.Globalization.Resources.Common.Delete %>" OnClientClick='<%# "return confirm(\"" + GalleryOnline.Globalization.Resources.Common.Question_DeleteOrCancel +"\");" %>' />  </td>
                                    <td valign="top"><asp:Button ID="Button7" runat="server" Text="<%# GalleryOnline.Globalization.Resources.Common.Back %>" CausesValidation="false" OnClientClick='javascript:history.go(-1);' /></td>
                                    <td>
                                        <div id="functionNavBox">
                                            <asp:Button id="btnFunctions" runat="server" OnClientClick="return false;" CssClass="functions" Text="<%# GalleryOnline.Globalization.Resources.Common.Functions %>" />
                                            <ul id="functionNavTree" style="display:none; position:relative; left:80px; bottom:103px; background-color:#fff; border:1px solid #CCC; padding:3px; z-index:1000;">
                                                <li><asp:Button id="Button3" runat="server" OnClientClick='<%# "window.open(\"" + GetRouteUrl("ViewInvoiceDetails", new {invoiceId=Eval("InvoiceId")}) + "\"); return false;" %>' Text="<%# GalleryOnline.Globalization.Resources.Common.PrintProFormaInvoice %>" /></li>
                                                <li><asp:Button ID="btnPrintInvoice" runat="server" CommandArgument='<%# Eval("InvoiceId") %>' OnClick="btnPrintInvoice_Click" OnClientClick='<%# "window.open(\"" + GetRouteUrl("ViewInvoiceDetails", new {invoiceId=Eval("InvoiceId")}) + "\");" %>' Text="<%# GalleryOnline.Globalization.Resources.Common.PrintInvoice %>" /></li>
                                                <li><asp:Button id="btnDelivered" runat="server" CommandArgument='<%# Eval("InvoiceId") %>' OnClick="btnDelivered_Click" Text="<%# GalleryOnline.Globalization.Resources.Common.Delivered %>" /></li>
                                                <li><asp:Button ID="Button2" runat="server" OnClientClick='<%# "window.open(\"" + GetRouteUrl("ViewValuation", new {invoiceId=Eval("InvoiceId")}) + "\"); return false;" %>' Text="<%# GalleryOnline.Globalization.Resources.Common.PrintValuation %>" /></li>
                                            </ul>
                                        </div>
                                    </td>
                                </tr>
                            </table>  
                        </div>
                    </EditItemTemplate>
                    <InsertItemTemplate>
                        <asp:DynamicEntity runat="server" Mode="Insert" />
                        <div class="formActions">
                            <asp:Button runat="server" CommandName="Insert" Text="<%# GalleryOnline.Globalization.Resources.Common.Insert %>" ID="btnInsert" />
                            <asp:Button runat="server" CommandName="Cancel" Text="<%# GalleryOnline.Globalization.Resources.Common.Cancel %>" CausesValidation="false" />
                        </div>
                    </InsertItemTemplate>
                </asp:FormView>

                <asp:Panel ID="InitialInvoiceItemDetailsPanel" runat="server" CssClass="extras" Visible="false">
                    <h4><%= String.Format(GalleryOnline.Globalization.Resources.Common.Label_CreatingInvoiceForArtworkCopy, this.ArtworkSalesPriceContext.Artwork.Name, this.ArtworkSalesPriceContext.CopyNumber) %></h4>
                    <table class="form">
                        <tr>
                            <td class="label"><%= GalleryOnline.Globalization.Resources.EntityMetadata.Price %></td>
                            <td class="value"><%= this.ArtworkSalesPriceContext.Price.ToString("F2") %></td>
                        </tr>
                        <tr>
                            <td class="label"><%= GalleryOnline.Globalization.Resources.EntityMetadata.VatPercentage %></td>
                            <td class="value"><asp:DropDownList ID="VatRateDropDown" runat="server" 
                                    DataValueField="VatPercentageId" DataTextField="Name" /></td>
                        </tr>
                    </table>
                </asp:Panel>

                <asp:EntityDataSource ID="DetailsDataSource" runat="server" EnableDelete="true" 
                    EnableInsert="true" EnableUpdate="true" 
                    oninserting="DetailsDataSource_Inserting" />

                <asp:QueryExtender TargetControlID="DetailsDataSource" runat="server">
                    <asp:ControlFilterExpression ControlID="GridView1" />
                </asp:QueryExtender>
            </asp:Panel>

        </ContentTemplate>
    </asp:UpdatePanel>
    <asp:UpdateProgress AssociatedUpdatePanelID="UpdatePanel1" runat="server" DisplayAfter="0" DynamicLayout="true" ID="UpdateProgress1" Visible="true">
    <ProgressTemplate>
        <div class="loadingProgress"><%# GalleryOnline.Globalization.Resources.Common.Label_Loading %></div>
    </ProgressTemplate>
    </asp:UpdateProgress>


    <script type="text/javascript">

        var gridSelectExtender = new GalleryOnline.UI.EasySelectGridViewExtender('<%= GridView1.ClientID %>', '<%= GridView1.UniqueID %>');

        if (Sys.WebForms)
        {
            Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(function (sender, args)
            {
                if (args.get_panelsUpdated().length > 0)
                    gridSelectExtender.extend();

                GalleryOnline.UI.FilterManager.initializeFilters();
            });
        }

        $().ready(gridSelectExtender.extend);
        $().ready(GalleryOnline.UI.FilterManager.initializeFilterVisibility);

    </script>
</asp:Content>
Foi útil?

Solução

I found a solution for my problem.

I initiated the autocomplate using the id of the textbox:

$("input[id$='<%= txtCustomerName.ClientID %>']").autocomplete({...});

I changed this to a certain css class I set on the textbox, in this case artworkcopylookup. When I intiaite the autocomplete I use the css class to select my textbox:

$("input[class$='artworkcopylookup']").autocomplete({...});

Instead of searching for the previously loaded texbox on id, the script searches for any input with the correct class set. This way the newly loaded texbox is found and everything works like a charme.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top