Externe JavaScript-Dateien in asynchronem Postback laden

Wenn man viel UI-Funktionalität haben will, braucht man hin und wieder ein paar Dateien Javascript, die diese enthalten – da kommt auf die Dauer einiges zusammen. Wenn man nun versucht, gleichzeitig die Seitengröße unter Kontrolle zu behalten, kommt man schnell auf die Idee, bestimmte JavaScript-Dateien erst dann zu laden, wenn die enthaltene Funktionalität tatsächlich auch benötigt wird.

Ein Schlüssel dazu ist die Methode ScriptManager.RegisterClientScriptInclude, aber leider nur einer. Der zweite, entscheidende Schlüssel ist der hier:

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

Diese Zeile muss am Ende jeder auf diesem Wege eingebundenen js-Datei stehen.

Ein ausführliches Beispiel habe ich hier eingestellt, kurz bevor ich dann die Lösung selbst gefunden habe. So ist es manchmal!

Happy coding!

Wenn ihnen der Artikel gefallen hat oder er für sie hilfreich war, bitten "kicken" sie ihn.
kick it on dotnet-kicks.de

Kommentare

Dezember 16. 2009 02:45

Rene Drescher-Hackel

das ist so nicht ganz richtig. Wenn du externe js-Dateien über den Scriptmanager einliest erscheint dieser Eintrag automatisch, inbesondere bei CustomControls. Fügst du diese Zeile manuell ein, kann es zu Fehlern kommen. Ich bin besser damit gefahren, sie nicht einzufügen.

Rene Drescher-Hackel

Dezember 18. 2009 07:02

Oliver

Hallo Rene,

danke für den Kommentar. Das wir kaum Custom Controls benutzen, kann ich dazu leider nicht viel sagen, aber das (komplette) Beispiel auf stackoverflow (Link siehe Artikel) funktioniert _ohne_ diese Zeile leider nicht. Ich benutze dabei die statischen Methoden des ScriptManagers.

Vielleicht hast du ja einen Idee, wie man das Problem auch ohne notifyScriptLoaded() lösen kann?

Gruß, Oliver

Oliver

Dezember 23. 2009 05:20

Rene Drescher-Hackel

Hi Oliver,

du hast im CodeBehinde einen Schreibfehler gehabt - ResolveClientUrl("~/ScriptManager.js"));
Deine Scriptdatei fängt aber nit einem _ (Unterstrich) an.
Bei mir funktionierte das Sample ganz ohne die Zeile "if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();"

Da du mit einem Updatepanel arbeitest, würde ich es allerdings so umsetzen:

        var LoadScript = function(src, id) {
            /// <summary>
            /// Lädt ein Script nach
            /// </summary>
            $("head").append("<script id='" + id + "' type='text/javascript' src='" + src + "' ><\/script>");
        }

        var loadScript = false;

        var InitRequest = function(sender, args) {
            /// <summary>
            /// InitRequest-Eventhandler, der gefeuert wird, wenn
            /// der Request startet
            /// </summary>
            if (args._postBackElement.id == "btnSecond") {
                loadScript = $("#btnSecond_script").length == 0;
            }
        }

        var EndRequest = function(sender, args) {
            /// <summary>
            /// EndRequest-Eventhandler, der gefeuert wird,
            /// wenn die partielle Aktualisierung der Seite abgeschlossen ist.
            /// Der Event wird nach OnPageLoad aufgerufen.
            /// Wenn der PageRequestManger einen Serverfehler empfängt, wird das Error-Handling des
            /// Scriptmanagers ausgelöst und auf die Startseite zurück verwiesen
            /// </summary>
            if (args.get_error() != null) {
                args.set_errorHandled(true);
            }
            if (loadScript == true) {
                LoadScript("_ScriptManager.js", "btnSecond_script");
            }
            setTimeout(function() {
                alert('hi there');
                dynamic();
            }, 1);
        }

        $(document).ready(function() {
            var pmg = Sys.WebForms.PageRequestManager._instance;
            pmg.add_initializeRequest(InitRequest);
            pmg.add_endRequest(EndRequest);
        });

Serverseitig entferne ich die OnPreRender-Methode und füge statt dessen den OnErrorHandler ein:

/// <summary>
        /// Exception Eventhandler des Scriptmangers
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">AsyncPostBackErrorEventArgs</param>
        protected void scm_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
        {
            scm.AsyncPostBackErrorMessage = e.Exception.Message;
        }

Den Page_Load ändere ich wie folgt:

protected void Page_Load(object sender, EventArgs e)
        {
            btnFirst.Click += delegate { mv.SetActiveView(vw1); };
            btnSecond.Click += delegate { mv.SetActiveView(vw2); };
            if (!IsPostBack)
            {
                // Test 1: does not work          
                mv.SetActiveView(vw1);

            }
            else
            {
                // Test 2: works, because required script is loaded on initial page request            
                mv.SetActiveView(vw2);        
            }
        }

Im HTML noch das Attribute im Scriptmanager setzen:

<asp:ScriptManager runat="server" ID="scm" OnAsyncPostBackError="scm_AsyncPostBackError">
    </asp:ScriptManager>

Im Ergebnis liefert es das, was du wolltest - Script dynamisch nachladen. Wink

Statt im Script var loadScript = false; zur Verwaltung zu benutzen kann man hier auch ein komplexes Object anlegen und nutzen. So kann man es dann für n-Fälle einsetzen.
Gruß
Rene

Rene Drescher-Hackel

Kommentar schreiben


(Zeigt dein Gravatar icon)

  Country flag

biuquote
  • Kommentar
  • Live Vorschau
Loading