In meinem letzten Artikel UserControls mit Properties/Konstruktoren dynamisch laden (Server und Client)
habe ich dargestellt, mit welch relativ geringem Aufwand man komplexe ASP.NET-Steuerelemente auch per Javascript über einen WebService in eine Seite
injizieren kann. Es geht aber noch besser...
Das Update
Mein Javascript-Code ist, für die mehrmalige Verwendung innerhalb eines Projekts, schon ein ziemlicher Brocken (20-30 Zeilen,
ja nachdem wie leserlich man es haben möchte) und so drängt sich ein Refactoring quasi schon auf. Grund dafür ist natürlich der recht umfangreiche
AJAX-Aufruf mittels jQuery.
Zudem fiel mir auf, dass ich einen inhaltlichen Fehler begangen habe. In der Javascript-Methode getElementHtml wird im Erfolgfall
das Element direkt an den Container gehängt, was man bei dem gewählten Methodennamen nicht direkt erwarten würde. Shame on me...
Um nun die Routine zu entzerren und allgemeingültiger zu halten, habe ich ihr zwei weitere Eingabeargumente namens successFunction und
errorFunction verpasst, die definieren was im Erfolgs- bzw. Fehlerfall passieren soll.
function getElementHtml(iElementNo,
sElementText,
sElementClass,
successFunction,
errorFunction) {
...
//Abruf des WebService
$.ajax({
...
success:
function(sMsg) {
successFunction(sMsg.d);
},
error:
function(XMLHttpRequest,
textStatus,
errorThrown) {
errorFunction(XMLHttpRequest.responseText);
}
});
}
Aufgerufen wird die Methode nun folgendermaßen:
getElementHtml(iElementNo,
sElementText,
sElementClass,
function(sHtml) {
$("#container").append(sHtml)
},
handleServiceError);
Eine weitere Refaktorisierung ist in Bezug auf die in Methode enthaltenen "hard-gecodeten" Variablen wie sUrl,
sCtlPath, usw. sicherlich möglich, aber ich verzichte zu diesem Zeitpunkt einmal darauf, denn die Methode heißt ja
immer noch GetElementHtml, weil das Steuerelement element.ascx heißt.
Das jQuery-Plugin
Bei der Recherche zum o.g. Artikel,
bin ich über einen Beitrag von Roberto Bez mit dem hübschen Namen
jQuery Plugin selbstgemacht - Dynamisches laden von ASP.NET Controls
gestolpert, der direkt mein Aufsehen erregte und von mir umgesetzt werden wollte.
Na denn ... hier ist es, ascxLoader im zerbit-Style:
(function($) {
$.fn.ascxLoader = function(params) {
//Referenz auf den Container
var obj = $(this);
//Standardwerte
var defaults = {
servicePath: "",
serviceMethod: "",
controlPath: "",
properties: {},
successFunction: function(sHtml){obj.html(sHtml)},
errorFunction: alert
};
//Standards und Parameter zusammenführen
var config = $.extend(defaults, params);
//JSON-String erzeugen
var sData = JSON.stringify({
controlLocation: config.controlPath,
properties: config.properties
});
//Abruf des WebService
$.ajax({
type: "POST",
url: config.servicePath + '/' + config.serviceMethod,
contentType: "application/json; charset=utf-8",
data: sData,
dataType: "json",
success:
function(result) {
config.successFunction(result.d);
},
error:
function(xmlReq,
textStatus,
errorThrown) {
config.errorFunction(xmlReq.responseText);
}
});
}
})(jQuery);
Ein paar Worte zum Plugin-Code...
Im Gegensatz zu Roberto, verwende ich nur einen Eingabeparameter namens param, in den alles gepackt wird, was
das Plugin braucht.
Die WebService-Url habe ich in zwei Teile (servicePath und serviceMethod) zerlegt, denn oftmals ist
es so, dass man nur einen WebService mit vielen darin enthaltenen Methoden entwickelt und dann reduziert sich die Parameterliste um einen Punkt,
sofern man im Plugin einen Standard im default-Objekt definiert hat. In meinem Beispiel habe ich die Standards einfach mal leer gelassen.
Weitere Parameter sind properties, welches das Objekt entgegennimmt, in dem die Eigenschaften des UserControls enthalten sind,
errorFunction mit dem man definieren kann, welche Fehlerroutine ausgeführt werden soll, wenn der Service-Abruf scheitert und
successFunction für den Erfolgsfall, d.h. die Verarbeitung des abkommenden Html-Codes.
Der Aufruf des Plugins ist, wie bei jQuery üblich, leicht zu überschauen:
$("#container").ascxLoader({
servicePath: "service/ScriptService.asmx",
serviceMethod: "GetControlHtmlWithProperties",
controlPath: "~/controls/element.ascx",
properties: {
'ElementNo': iElementNo,
'ElementText': sElementText,
'ElementClass': sElementClass },
successFunction:
function(sHtml) {
$("#container").append(sHtml)
},
errorFunction: handleServiceError
});
Voilá ... ein Einzeiler!
Dirty Code
Einem geübten Betrachter wird der besondere Parameter manupulation aufgefallen sein und wie er im Plugin
verarbeitet wird. Er ist dazu da, zu bestimmen, mit welcher jQuery-Methode nach dem erfolgreichen Abruf des Steuerelement-Codes weiterverfahren werden soll.
...
ich habe bislang keine bessere Idee...!?
Oh doch ...!
Für alle die den Artikel schon gelesen haben: es gibt eine bessere Lösung als mit eval irgendwelche jQuery-Methoden
ausführen zu lassen! Manchmal ist es einfach schlicht zu spät, um noch geradeaus denken zu können ;)
Ich hatte es weiter oben bereits vorgeführt: Übergabe einer Function mit einem String-Parameter. Standard-Methode ist html, also das
Ersetzen des kompletten Container-Inhalts. Der oben stehende Code und der Download sind bereits aktualisiert.
Happy Coding ;)
Downloads
LoadControlWithParameter2.zip