Design und Verarbeitung von clientseitigem Skripting

  • Freigeben Version: Zurich
  • Aktualisiert 13. März 2026
  • 11 Minuten Lesedauer
  • Durchdacht programmierte Client-Skripts können die Zeit verringern, die Benutzer zum Ausfüllen eines Formulars benötigen.

    Für eine korrekte clientseitige Verarbeitung muss das Formular zunächst geladen werden. Wird der Datensatz vor dem Laden des Formulars aktualisiert, kann das zu unerwarteten Ergebnissen führen, die bei der clientseitigen Verarbeitung nicht berücksichtigt werden.

    Wenn Sie ein Client-Skript erstellen, um Feldwerte in einem Formular zu steuern, müssen Sie zur Steuerung dieser Feldwerte in einer Liste eine andere Methode verwenden. Sie haben folgende Möglichkeiten:
    • Deaktivieren der Listenbearbeitung für die Tabelle
    • Erstellen passender Business Rules oder Zugriffssteuerungen für die Listenbearbeitung
    • Erstellen von Datenrichtlinien
    • Erstellen eines separaten Client-Skripts des Typs „onCellEdit“

    Einschränken der Listenbearbeitung

    Wenn Sie UI-Richtlinien oder Client-Skripts für Formularfelder erstellen, müssen Sie eine andere Methode verwenden, um sicherzustellen, dass die Daten in diesen Feldern in einer Liste ähnlich gesteuert werden.

    Mit Ausnahme von Client-Skripts des Typs „onCellEdit“ werden UI-Richtlinien und Client-Skripts ausschließlich auf Formulare angewendet. Verwenden Sie beim Einsatz von Client-Skripts die folgenden Methoden, um die Listenbearbeitung einzuschränken:
    • Deaktivieren der Listenbearbeitung für die Tabelle
    • Erstellen passender Business Rules oder Zugriffssteuerungen für die Listenbearbeitung
    • Erstellen von Datenrichtlinien
    • Erstellen eines separaten Client-Skripts des Typs „onCellEdit“

    Serversuchen auf ein Minimum reduzieren

    Verwenden Sie wann immer möglich Client-Daten, um zeitaufwendige Serversuchen zu vermeiden.

    Client-Skripts verwenden entweder Daten auf dem Client oder Daten, die vom Server abgerufen werden. Die wichtigsten Methoden zum Abrufen von Informationen vom Server sind „g_scratchpad“ und asynchrone Suchen des Typs „GlideAjax“.

    Der Hauptunterschied zwischen beiden Methoden: „g_scratchpad“ wird einmalig beim Laden eines Formulars gesendet (Informationen werden vom Server an den Client gesendet), während „GlideAjax“ dynamisch ausgelöst wird, sobald der Client Informationen vom Server anfordert.

    Hinweis:
    Serverinformationen können auch über „GlideRecord“ und „g_form.getReference()“ abgerufen werden. Von diesen Methoden raten wir jedoch mittlerweile ab, da sie sich negativ auf die Leistung auswirken. Beide Methoden rufen alle Felder im angeforderten Objekt des Typs „GlideRecord“ ab, obwohl in den meisten Fällen nur ein einziges Feld erforderlich ist.

    Serverdaten abrufen mit „g_scratchpad“

    Das Objekt „g_scratchpad“ übergibt Informationen vom Server an den Client, beispielsweise wenn der Client Informationen benötigt, die im Formular nicht verfügbar sind.

    Angenommen ein Client-Skript muss auf das Feld „u_retrieve“ zugreifen, dieses Feld existiert aber im Formular nicht. Die Daten sind dann für das Client-Skript nicht verfügbar. Eine gängige Lösung für einen solchen Fall besteht darin, das Feld zwar im Formular zu platzieren, es jedoch per Client-Skript oder UI-Richtlinie permanent auszublenden. Diese Lösung mag sich schneller konfigurieren lassen, wird aber langsamer ausgeführt.

    Wenn Sie bereits vor dem Laden des Formulars wissen, welche Informationen der Client vom Server benötigt, können Sie über eine beim Anzeigen ausgeführte Business Rule Eigenschaften des Typs „g_scratchpad“ erstellen. Die Informationen werden dann in diesen Eigenschaften hinterlegt. Das Objekt „g_scratchpad“ wird an den Client gesendet, sobald das Formular angefordert wird. Damit ist es für alle clientseitigen Skriptmethoden verfügbar. Dies ist eine sehr effiziente Möglichkeit, Informationen vom Server an den Client zu senden. Allerdings können Daten nur auf diese Weise geladen werden, während das Formular geladen wird. Die Business Rule kann nicht dynamisch ausgelöst werden. In solchen Fällen müssen Sie einen asynchronen Aufruf des Typs „GlideAjax“ verwenden.

    Angenommen Sie erstellen einen Incident und müssen folgende Informationen an den Client übergeben:
    • Den Wert der Systemeigenschaft „css.base.color“
    • Ob der aktuelle Datensatz Anhänge enthält
    • Den Namen des Vorgesetzten des Anrufers
    Eine beim Anzeigen ausgeführte Business Rule nutzt folgendes Skript, um diese Informationen an den Client zu senden:
    g_scratchpad.css = gs.getProperty('css.base.color');
    g_scratchpad.hasAttachments = current.hasAttachments();
    g_scratchpad.managerName = current.caller_id.manager.getDisplayValue();
    So greifen Sie mit einem Client-Skript auf Scratchpad-Daten zu:
    // Check if the form has attachments
    if (g_scratchpad.hasAttachments)
        // do something interesting here
    else
        alert('You need to attach a form signed by ' + g_scratchpad.managerName);

    Serverdaten mit asynchronen Aufrufen des Typs „GlideAjax“ abrufen

    Mit asynchronen Aufrufen des Typs „GlideAjax“ können Sie Informationen dynamisch vom Server anfordern.

    Dieses Skript vergleicht den Namen der Support-Gruppe des CI mit dem Namen der Zuweisungsgruppe des Incident:
    //Alert if the assignment groups name matches the support group
    function onChange(control, oldValue, newValue, isLoading) {
     
        if (isLoading)
            return;
     
        var ga = new GlideAjax('ciCheck');
     
        ga.addParam('sysparm_name', 'getCiSupportGroup');
        ga.addParam('sysparm_ci', g_form.getValue('cmdb_ci'));
        ga.addParam('sysparm_ag', g_form.getValue('assignment_group'));
        ga.getXML(doAlert); // Always try to use asynchronous (getXML) calls rather than synchronous (getXMLWait)
    }
     
    // Callback function to process the response returned from the server
    function doAlert(response) {
     
        var answer = response.responseXML.documentElement.getAttribute("answer");
     
        alert(answer);
    }
    Dieses Skript basiert auf der zugehörigen Skripteinbindung:
    var ciCheck = Class.create();
     
    ciCheck.prototype = Object.extendsObject(AbstractAjaxProcessor, {
     
        getCiSupportGroup: function() {
     
            var retVal = ''; // Return value
            var ciID   = this.getParameter('sysparm_ci');
            var agID   = this.getParameter('sysparm_ag');		
            var ciRec  = new GlideRecord('cmdb_ci');
     
            // If we can read the record, check if the sys_ids match
            if (ciRec.get(ciID)) {
                if (ciRec.getValue('support_group') == agID)
                    retVal = 'CI support group and assignment group match';
                else
                    retVal = 'CI support group and assignment group do not match';
     
                // Can't read the CI, then they don't match
            } else {
                retVal = 'CI support group and assignment group do not match';
            }
     
            return retVal;
        }
     
    });

    „setValue()“ mit Parameter „displayValue“ auf Referenzfelder anwenden

    Wenn Sie „setValue()“ auf ein Referenzfeld anwenden, können Sie den Parameter „displayValue“ einfügen, um zusätzliche Serveraufrufe zu vermeiden.

    Wenn Sie setValue() auf ein Referenzfeld anwenden, sollten Sie also den Anzeigewert des Referenzfelds als dritten Parameter angeben. Wenn Sie den Wert ohne den Anzeigewert festlegen, führt die Instanz einen synchronen Aufruf durch, um den Anzeigewert des angegebenen Datensatzes abzurufen. Dieser zusätzliche Roundtrip zum Server kann sich negativ auf die Leistung auswirken.

    In diesem Beispiel sehen Sie, wie „setValue“ nicht aufgerufen werden darf:
    var id = '5137153cc611227c000bbd1bd8cd2005';
     
    g_form.setValue('assigned_to', id); // Client needs to go back to the server to
                                        // fetch the name that goes with this ID
    Fügen Sie stattdessen den Anzeigewert als optionalen Parameter in setValue() ein:
    var id = '5137153cc611227c000bbd1bd8cd2005';
    var name = 'Fred Luddy';
     
    g_form.setValue('assigned_to', id, name); // No server call required

    UI-Richtlinien statt Client-Skripts verwenden

    Falls möglich sollten Sie statt Client-Skripts UI-Richtlinien verwenden.

    UI-Richtlinien haben gegenüber Client-Skripts folgenden Nutzen:
    • UI-Richtlinien verfügen über ein Feld Reihenfolge, über das Sie vollständig steuern können, in welcher Reihenfolge clientseitige Vorgänge ausgeführt werden sollen.
    • Bei UI-Richtlinien ist kein Skript erforderlich, um Felder obligatorisch, schreibgeschützt oder sichtbar zu machen.
    Hinweis:
    UI-Richtlinien werden nach Client-Skripts angewendet.

    Validieren der Eingabe mithilfe eines Client-Skripts

    Eine ausgezeichnete Verwendung für ein Clientskript ist die Validierung der Eingabe des Anwenders.

    Eine solche Validierung verbessert die Benutzererfahrung, da der Benutzer bereits vor dem Absenden der Informationen über Datenprobleme informiert wird.

    Ein Beispiel für eine Validierung ist die Überprüfung, ob der Wert des Felds Auswirkung zum Wert des Felds Priorität passt. In diesem Beispiel darf als Auswirkung nicht Niedrig gesetzt sein, wenn als Priorität Hoch angegeben ist.
    if (g_form.getValue('impact') == '3' && g_form.getValue('priority') == '1')
       g_form.showFieldMsg('impact', getMessage('Low impact now allowed with High priority'), 'error');
    

    Client-Skript-Reihenfolge festlegen

    Über das Feld „Reihenfolge“ können Sie festlegen, in welcher Reihenfolge Ihre Client-Skripts ausgeführt werden sollen. Durch die Festlegung einer Reihenfolge für die Ausführung der Skripts vermeiden Sie, dass zwei oder mehr Client-Skripts gleichzeitig ausgeführt werden und Konflikte entstehen.

    Vorbereitungen

    Erforderliche Rolle: admin

    Warum und wann dieser Vorgang ausgeführt wird

    Wenn Sie Client-Skripts eine Nummer in der Reihenfolge zuweisen, wird eine Verarbeitungssequenz erstellt. Sie ist von der niedrigsten zur höchsten Nummer geordnet. Stehen zwei Skripts in Konflikt zueinander, wird zuerst das Client-Skript mit der niedrigeren Nummer ausgeführt.

    Prozedur

    1. Navigieren zu Alle > Systemdefinition > Client-Skript Und öffnen Sie ein vorhandenes Client-Skript, oder klicken Sie auf Neu .
    2. Konfigurieren des Formularlayouts Um einzubeziehen Reihenfolge Feld.
    3. Tragen Sie eine Nummer in das Feld „Reihenfolge“ ein, die angibt, wann das Client-Skript in der Client-Skript-Reihenfolge ausgeführt werden soll.
      Wählen Sie eine niedrigere Nummer für das Skript, das zuerst ausgeführt werden soll.

    DOM-Änderungen vermeiden

    Vermeiden Sie nach Möglichkeit Änderungen am DOM (Document Object Model). Solche Änderungen können zu Wartungsproblemen führen, wenn Browser aktualisiert werden.

    Verwenden Sie stattdessen die API „GlideForm“, oder ziehen Sie einen anderen Lösungsansatz in Betracht. Im Allgemeinen gilt: Wenn Sie Methoden zur Änderung des DOM verwenden, müssen Sie ein Element im DOM referenzieren. Dazu müssen Sie entweder die ID oder eine CSS-Auswahl verwenden. Beim Referenzieren von vordefinierten DOM-Elementen besteht das Risiko, dass sich die Element-ID oder die Platzierung innerhalb des DOM ändern. Ist das der Fall, funktioniert der Code nicht mehr und/oder generiert Fehler. Machen Sie sich die Auswirkungen von Änderungen klar, gehen Sie mit Bedacht vor und bedenken Sie alle Risiken. Überprüfen Sie diese Objekte, und greifen Sie so wenig wie möglich auf Methoden zur Änderung des DOM zurück.

    Globale Client-Skripts vermeiden

    Ein globales Client-Skript ist ein Client-Skript, in dem als ausgewählte Tabelle „Global“ festgelegt ist. Für globale Client-Skripts gelten keine Tabelleneinschränkungen. Daher werden sie auf jeder Seite im System geladen, was zu Ladeverzögerungen im Browser führt.

    Es hat keinen Nutzen, Skripts dieses Typs auf jeder Seite zu laden.

    Als Alternative und für einen modulareren und skalierbareren Ansatz sollten Sie Client-Skripts in eine Basistabelle verschieben (z. B. „Aufgabe[task]“ oder „Configuration Item[cmdb_ci]“), die für alle untergeordneten/erweiterten Tabellen abgeleitet werden kann. Dadurch muss das System die Skripts nicht in jedem UI-Formular laden, beispielsweise nicht auf Homepages oder im Servicekatalog, wo sie wenn überhaupt nur selten benötigt werden.

    Code in Funktionen einschließen

    Schließen Sie Code in Client-Skripts in Funktionen ein.

    Client-Skripts ohne Funktion führen zu Problemen mit dem Bereich von Variablen. Wenn Code nicht in eine Funktion eingeschlossen ist, sind Variablen und andere Objekte auch für alle anderen clientseitigen Skripts verfügbar und freigegeben. Verwenden Sie dann identische Variablennamen, kann es zu Konflikten kommen. Das wiederum kann unerwartete Folgen haben, die schwer zu diagnostizieren und zu beheben sind.

    Betrachten wir folgendes Beispiel:
    var state = "6";
     
    function onSubmit() {
     
       if(g_form.getValue('incident_state') == state) {
       		alert("This incident is Resolved");
       }
    }
    Da die Variable state nicht in eine Funktion eingeschlossen ist, haben alle clientseitigen Skripts Zugriff auf sie. Einige dieser Skripts verwenden möglicherweise ebenfalls den gängigen Variablennamen state. Diese doppelt verwendeten Namen können Konflikte verursachen und zu unerwarteten Ergebnissen führen. Probleme dieser Art sind schwer zu isolieren und zu beheben. Um sie zu vermeiden, sollte sämtlicher Code in eine Funktion eingeschlossen sein:
    function onSubmit() {
     
       var state = "6";
     
       if(g_form.getValue('incident_state') == state) {
       		alert("This incident is Resolved");
       }
    }

    Diese Lösung ist sehr viel sicherer, da der Bereich der Variablen state auf die Funktion „onSubmit()“ beschränkt ist. So kann es nicht zu Konflikten zwischen dieser Variable state und Variablen namens state in anderen clientseitigen Skripts kommen.

    Nur notwendige Skripts ausführen

    Damit Skripts mit langer Ausführungsdauer nicht unnötigerweise ausgeführt werden, sollten Client-Skripts nur notwendige Aufgaben ausführen.

    Die nachfolgend aufgeführten Beispiele zeigen, wie sich der jeweilige ursprüngliche Codeausschnitt verbessern lässt. Dabei demonstriert jedes Beispiel eine spezifische Skriptverbesserung, die die Leistung steigert und unnötige Aufrufe vermeidet.

    Bedenken Sie dabei dass Client-Skripts kein Feld Bedingung haben. Das bedeutet, dass Skripts des Typs „onLoad()“ und des Typs „onChange()“ bei jedem Laden des entsprechenden Formulars vollständig ausgeführt werden. Dieses Beispiel ist ein ineffizientes Client-Skript des Typs „onChange()“, das immer dann ausgeführt wird, wenn das Feld Configuration Item geändert wird.

    //Set Assignment Group to CI's support group if assignment group is empty
    function onChange(control, oldValue, newValue, isLoading) {
     
        var ciSupportGroup = g_form.getReference('cmdb_ci').support_group;
     
        if (ciSupportGroup != '' && g_form.getValue('assignment_group) != '')
            g_form.setValue('assignment_group', ciRec.support_group.sys_id);
    }

    In diesem Beispiel haben wir den vorherigen Codeausschnitt verbessert, indem wir die Suche des Typs „getReference()“ bzw. „GlideRecord“ durch einen asynchronen Aufruf des Typs „GlideAjax“ ersetzt haben.

    //Set Assignment Group to support group if assignment group is empty
    function onChange(control, oldValue, newValue, isLoading) {
     
        var ga = new GlideAjax('ciCheck');
     
        ga.addParam('sysparm_name', 'getSupportGroup');
        ga.addParam('sysparm_ci', g_form.getValue('cmdb_ci'));
        ga.getXML(setAssignmentGroup);
    }
     
    function setAssignmentGroup(response) {
     
        var answer = response.responseXML.documentElement.getAttribute("answer");
     
        g_form.setValue('assignment_group', answer);
    }

    Die isLoadingDie Kennzeichnung ist die einfachste Möglichkeit, um zu verhindern, dass unnötiger Code in onChange-Skripts Browserzeit beansprucht. Die isLoadingDie Kennzeichnung sollte am Anfang eines Skripts verwendet werden, das beim Laden des Formulars nicht ausgeführt werden muss. Dieses Skript muss nicht beim Laden des Formulars ausgeführt werden, weil die Logik bereits bei der letzten Änderung des Felds ausgeführt wurde. Hinzufügen von isLoadingWenn Sie das Skript überprüfen, wird verhindert, dass bei jedem Laden des Formulars eine cmdb_ci-Suche durchgeführt wird.

    Die isTemplateKennzeichnung gibt an, dass eine Vorlage geladen wird.

    //Set Assignment Group to CI's support group if assignment group is empty
    function onChange(control, oldValue, newValue, isLoading, isTemplate) {
     
        if (isLoading)
            return;
     
        var ga = new GlideAjax('ciCheck');
     
        ga.addParam('sysparm_name', 'getSupportGroup');
        ga.addParam('sysparm_ci', g_form.getValue('cmdb_ci'));
        ga.getXML(setAssignmentGroup);
    }
     
    function setAssignmentGroup(response) {
     
        var answer = response.responseXML.documentElement.getAttribute("answer");
     
        g_form.setValue('assignment_group', answer);
    }
    
    Soll das Skript des Typs „onChange“ während des Ladens ausgeführt werden, müssen Sie folgende Konvention verwenden:
    function onChange(control, oldValue, newValue, isLoading, isTemplate) {
     
        if (isLoading) {}; // run during loading
     
        // rest of script here
     
    }
    Die Prüfung „newValue“ weist dieses Skript an, nur dann fortzufahren, wenn das entsprechende Feld einen gültigen Wert enthält. So wird verhindert, dass das Skript ausgeführt wird, wenn der Feldwert entfernt wird oder kein Feldwert gesetzt ist. Außerdem wird sichergestellt, dass immer ein gültiger Wert verfügbar ist, wenn der Rest des Skripts ausgeführt wird.
    //Set Assignment Group to CI's support group if assignment group is empty
    function onChange(control, oldValue, newValue, isLoading, isTemplate) {
     
        if (isLoading)
            return;
     
        if (newValue) {
            var ga = new GlideAjax('ciCheck');
     
            ga.addParam('sysparm_name', 'getSupportGroup');
            ga.addParam('sysparm_ci', g_form.getValue('cmdb_ci'));
            ga.getXML(setAssignmentGroup);
        }
    }
     
    function setAssignmentGroup(response) {
     
       var answer = response.responseXML.documentElement.getAttribute("answer");
     
       g_form.setValue('assignment_group', answer);
    }
    Damit das Skript auf Werte reagiert, die nach dem Laden des Formulars geändert werden, müssen Sie die Prüfung „newValue != oldValue“ verwenden.
    Hinweis:
    Dieses Beispiel berücksichtigt keine Fälle, in denen Benutzer einen Wert ändern und dann wieder den ursprünglichen Wert einsetzen.
    //Set Assignment Group to CI's support group if assignment group is empty
    function onChange(control, oldValue, newValue, isLoading, isTemplate) {
     
        if (isLoading)
            return;
     
        if (newValue) {
            if (newValue != oldValue) {
                var ga = new GlideAjax('ciCheck');
     
                ga.addParam('sysparm_name', 'getSupportGroup');
                ga.addParam('sysparm_ci', g_form.getValue('cmdb_ci'));
                ga.getXML(setAssignmentGroup);
            }
        }
    }
     
    function setAssignmentGroup(response) {
     
       var answer = response.responseXML.documentElement.getAttribute("answer");
     
       g_form.setValue('assignment_group', answer);
    }
    In diesem Beispiel wird der Aufruf des Typs „GlideAjax“ eine Ebene tiefer platziert. Dazu wird das Skript so angeordnet, dass möglichst viele der für den Client verfügbaren Daten geprüft werden, bevor die Serveraufrufe ausgeführt werden. Das Skript überprüft die Zuweisung, bevor der Aufruf des Typs „GlideAjax“ ausgeführt wird. Das verhindert, dass eine Serversuche durchgeführt wird, wenn im Feld assignment_group bereits ein Wert gesetzt ist.
    //Set Assignment Group to CI's support group if assignment group is empty
    function onChange(control, oldValue, newValue, isLoading, isTemplate) {
     
        if (isLoading)
           return;
     
        if (newValue) {
            if (newValue != oldValue) {
                if (g_form.getValue('assignment_group') == '') {
                    var ga = new GlideAjax('ciCheck');
     
                    ga.addParam('sysparm_name', 'getSupportGroup');
                    ga.addParam('sysparm_ci', g_form.getValue('cmdb_ci'));
                    ga.getXML(setAssignmentGroup);
                }
            }
        }
    }
     
    function setAssignmentGroup(response) {
     
       var answer = response.responseXML.documentElement.getAttribute("answer");
     
       g_form.setValue('assignment_group', answer);
    }