クライアント側のスクリプティングの設計と処理

  • リリースバージョン: Xanadu
  • 更新日 2026年03月12日
  • 所要時間:21分
  • クライアントスクリプトを適切に設計すれば、ユーザーのフォーム入力時間を短縮できます。

    クライアント側の処理が適切に行われるようにするには、最初にフォームを読み込みます。フォームの読み込み前にレコードを更新すると、予期しない結果が発生し、クライアント側の処理がバイパスされる可能性があります。

    フォームのフィールド値を制御するクライアントスクリプトを作成する場合は、別の方法を使用してリスト内でこれらのフィールド値を制御する必要があります。以下のようにすることができます。
    • テーブルのリスト編集を無効にします。
    • リスト編集に適したビジネスルールまたはアクセス制御を作成します。
    • データポリシーを作成します。
    • onCellEdit クライアントスクリプトを別に作成します。

    リストの編集の制限

    フォーム上のフィールドに対して UI ポリシーまたはクライアントスクリプトを作成する場合、別の方法を使用して、それらのフィールドのデータがリストで同様に制御されるようにする必要があります。

    onCellEdit クライアントスクリプトを除き、UI ポリシーとクライアントスクリプトはフォームにのみ適用されます。クライアントスクリプトを使用する場合は、次の方法を使用してリストの編集を制限します。
    • テーブルのリスト編集を無効にします。
    • リスト編集に適したビジネスルールまたはアクセス制御を作成します。
    • データポリシーを作成します。
    • onCellEdit クライアントスクリプトを別に作成します。

    サーバールックアップを最小限に抑制

    クライアントデータをできるだけ使用することで、時間のかかるサーバールックアップが必要なくなります。

    クライアントスクリプティングでは、クライアントで利用可能なデータまたはサーバーから取得したデータのいずれかを使用します。サーバーから情報を取得する主な方法は、g_scratchpad と非同期 GlideAjax ルックアップです。

    これらの方法の主な違いは、g_scratchpad ではフォームがロードされたときに 1 回送信される (情報がサーバーからクライアントにプッシュされる) のに対し、GlideAjax はクライアントがサーバーに情報を要求すると動的にトリガーされることです。

    注:
    サーバー情報を取得するためには GlideRecord および g_form.getReference() も利用できます。ただし、パフォーマンスに影響するため、これらの方法は推奨されなくなりました。多くの場合、必要なフィールドは 1 つだけですが、どちらの方法でも要求された GlideRecord 内のすべてのフィールドが取得されます。

    g_scratchpad を使用したサーバーデータの取得

    g_scratchpad オブジェクトは、クライアントがフォーム上で利用できない情報を必要とする場合に、サーバーからクライアントに情報を渡します。

    たとえば、フィールド u_retrieve にアクセスする必要があるクライアントスクリプトがあり、そのフィールドがフォーム上にない場合、クライアントスクリプトはデータを使用できません。この状況の一般的な解決策は、フォームにフィールドを配置してから、クライアントスクリプトまたは UI ポリシーを使用して常に非表示にすることです。このソリューションは素早く構成できますが、実行は遅くなります。

    フォームがロードされる前にクライアントがサーバーから必要とする情報がわかっている場合は、表示ビジネスルールでこの情報を保持する g_scratchpad プロパティを作成できます。g_scratchpad は、フォームが要求されるとクライアントに送信され、クライアント側のすべてのスクリプティングメソッドで使用できるようになります。これは、サーバーからクライアントに情報を送信する非常に効率的な手段です。ただし、この方法でデータをロードできるのは、フォームがロードされている場合のみです。ビジネスルールを動的にトリガーすることはできません。このような場合は、非同期 GlideAjax 呼び出しを使用します。

    たとえば、インシデントをオープンし、次の情報をクライアントに渡す必要があるとします。
    • システムプロパティ css.base.color の値
    • 現在のレコードに添付ファイルがあるかどうか
    • 呼び出し側のマネージャーの名前
    表示ビジネスルールは、次のスクリプトを使用してこの情報をクライアントに送信します。
    g_scratchpad.css = gs.getProperty('css.base.color');
    g_scratchpad.hasAttachments = current.hasAttachments();
    g_scratchpad.managerName = current.caller_id.manager.getDisplayValue();
    クライアントスクリプトを使用してスクラッチパッドデータにアクセスするには、次のようにします。
    // 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);

    非同期 GlideAjax を使用したサーバーデータの取得

    非同期 GlideAjax を使用すると、サーバーからの情報を動的に要求できます。

    このスクリプトは、CI のサポートグループとインシデントのアサイン先グループを名前で比較します。
    //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);
    }
    このスクリプトは、付随するスクリプトインクルードに依存しています。
    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() displayValue パラメーターを使用

    参照フィールドで setValue() を使用する場合は、追加のサーバー呼び出しを回避するために displayValue パラメーターを含めます。

    参照フィールドで setValue() を使用する場合は、必ず参照フィールドの表示値を 3 番目のパラメーターとして含めてください。displayValue なしで値を設定すると、インスタンスは同期呼び出しを実行して、指定したレコードの表示値を取得します。サーバーとの余分なやり取りが発生することで、パフォーマンスに影響する可能性があります。

    この例は、setValue を呼び出す間違った方法を示しています。
    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
    代わりに、表示値をオプションのパラメーターとして setValue() に含めます。
    var id = '5137153cc611227c000bbd1bd8cd2005';
    var name = 'Fred Luddy';
     
    g_form.setValue('assigned_to', id, name); // No server call required

    クライアントスクリプトの代わりに UI ポリシーを使用する

    可能な場合は、クライアントスクリプトの代わりに UI ポリシーを使用することを検討してください。

    UI ポリシーには、クライアントスクリプトに比べて次のメリットがあります。
    • UI ポリシーには、クライアント側の操作が実行される順序を完全に制御できる [順序] フィールドがあります。
    • UI ポリシーでは、フィールドを必須、読み取り専用にしたり、表示させたりするためのスクリプティングは必要ありません。
    注:
    UI ポリシーはクライアントスクリプトの後に適用されます。

    クライアントスクリプトを使用した入力の検証

    クライアントスクリプトは、ユーザーからの入力を検証するのに最適です。

    この検証により、ユーザーは情報を送信する前にデータの問題があるかどうかを確認できるため、ユーザーエクスペリエンスが向上します。

    検証の例として、[影響度] フィールドの値が [優先度] フィールドの値とともに有効であることを確認します。この例では、[低] の影響度を [高] の優先度にすることはできません。
    if (g_form.getValue('impact') == '3' && g_form.getValue('priority') == '1')
       g_form.showFieldMsg('impact', getMessage('Low impact now allowed with High priority'), 'error');
    

    クライアントスクリプトの順序の設定

    [順序] フィールドを使用して、クライアントスクリプトの実行順序を制御します。2 つ以上のクライアントスクリプトが同時に実行されて競合することを避けるために、スクリプトを実行する順序を追加できます。

    始める前に

    必要なロール:admin

    このタスクについて

    クライアントスクリプトに順序を追加すると、番号が小さいものから大きいものの順に処理シーケンスが作成されます。2 つのスクリプトが競合する場合は、番号の小さいクライアントスクリプトが最初に実行されます。

    手順

    1. 移動先 すべて > システム定義 > クライアントスクリプト をクリックし、既存のクライアントスクリプトを開くか、[ 新規] をクリックします。
    2. [順序] フィールドを含むようにフォームレイアウトを構成します。
    3. 他のクライアントスクリプトとの関連で実行する順序に基づいて、[順序] フィールドに番号を追加します。
      最初に実行するスクリプトの数値は小さくしてください。

    DOM 操作の回避

    可能であれば、ドキュメントオブジェクトモデル (DOM) の操作は避けてください。ブラウザーが更新されたときに、保守性の問題が発生する可能性があります。

    代わりに、GlideForm API を使用するか、別の方法での解決を検討してください。一般に、DOM 操作メソッドを使用する場合は、ID または CSS セレクターを使用して DOM 内の要素を参照する必要があります。すぐに利用可能な DOM 要素を参照する場合、DOM 内の要素 ID または配置が変更され、コードが機能しなくなったり、エラーが生成されたりするリスクがあります。事前に慎重に検討し、発生しているリスクを十分に理解してください。これらのオブジェクトを確認し、DOM 操作メソッドの使用をできるだけ減らします。

    グローバルクライアントスクリプトを避ける

    グローバルクライアントスクリプトは、選択したテーブルがグローバルである任意のクライアントスクリプトです。グローバルクライアントスクリプトにはテーブルの制限がないため、システム内のすべてのページでロードされ、プロセスでブラウザーのロード遅延が発生します。

    この種のスクリプトをすべてのページにロードするメリットはありません。

    別の方法として、すべての子/拡張テーブルから派生できるベーステーブル (タスク [task] や構成アイテム [cmdb_ci] など) にクライアントスクリプトを移動する、よりモジュール式でスケーラブルなアプローチを検討してください。これにより、スクリプトをめったに必要としないホームページやサービスカタログ など、UI のすべてのフォームでスクリプトをロードする必要がなくなります。

    関数でコードを囲む

    関数内のクライアントスクリプトでコードを囲みます。

    関数のないクライアントスクリプトは、変数スコープに関する問題の原因となります。コードが関数で囲まれていない場合、変数やその他のオブジェクトは使用可能で、他のすべてのクライアント側のスクリプトで共有されます。同じ変数名を使用している場合は、競合する可能性があります。これにより、トラブルシューティングが困難な予期しない結果が生じる可能性があります。

    次の例を考えてみましょう。
    var state = "6";
     
    function onSubmit() {
     
       if(g_form.getValue('incident_state') == state) {
       		alert("This incident is Resolved");
       }
    }
    state 変数は関数で囲まれていないため、すべてのクライアント側のスクリプトからアクセスできます。他のスクリプトでも、共通の変数名 state を使用できます。重複する名前は競合し、予期しない結果につながる可能性があります。これらの問題は、切り分けて解決することが困難です。この問題を回避するには、すべてのコードが関数で囲まれていることを確認します。
    function onSubmit() {
     
       var state = "6";
     
       if(g_form.getValue('incident_state') == state) {
       		alert("This incident is Resolved");
       }
    }

    このソリューションは、変数 state のスコープが onSubmit() 関数に制限されているため、はるかに安全です。したがって、state 変数は、他のクライアント側のスクリプトの state 変数と競合しません。

    必要なスクリプトのみを実行する

    時間のかかるスクリプトを不必要に実行しないようにするには、クライアントスクリプトが必要なタスクのみを実行するようにします。

    次の例は、最初のコードサンプルの改善を示しています。各例は、パフォーマンスを向上させ、不要な呼び出しを回避するためのスクリプトの特定の拡張を示しています。

    クライアントスクリプトには [条件] フィールドがないことに注意してください。これは、適切なフォームがロードされるたびに、onLoad() および onChange() スクリプト全体が実行されることを意味します。この例は、[構成アイテム] フィールドが変更されたときに実行されるように設定された非効率的な onChange() クライアントスクリプトです。

    //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);
    }

    この例では、getReference() または GlideRecord ルックアップを非同期 GlideAjax 呼び出しに置き換えることで、最初の例を改善しています。

    //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);
    }

    isLoading フラグは、onChange スクリプトでブラウザーが不要なコードに時間を取られないようにする最も簡単な方法です。isLoading フラグは、フォームのロード中に実行する必要のないスクリプトの先頭で使用する必要があります。フィールドが最後に変更されたときにロジックが既に実行されているため、フォームのロード時にこのスクリプトを実行する必要はありません。スクリプトに isLoading チェックを追加すると、フォームをロードするたびに cmdb_ci ルックアップが実行されなくなります。

    isTemplate フラグは、テンプレートがロード中であることを示します。

    //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);
    }
    
    ロード中に onChange スクリプトを実行する必要がある場合は、次の規則を使用します。
    function onChange(control, oldValue, newValue, isLoading, isTemplate) {
     
        if (isLoading) {}; // run during loading
     
        // rest of script here
     
    }
    newValue チェックは、関連するフィールドに有効な値がある場合にのみ続行するようにこのスクリプトに指示します。これにより、フィールド値が削除または空白になったときにスクリプトが実行されなくなります。これにより、残りのスクリプトが実行されたときに常に有効な値が使用可能になります。
    //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);
    }
    フォームのロード後に変更される値にスクリプトが反応するようにするには、newValue != oldValue チェックを使用します。
    注:
    この例では、ユーザーが値を変更してから元の値に戻すことはできません。
    //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);
    }
    この例では、サーバー呼び出しを実行する前にクライアントが利用できるものをできるだけ多くチェックするようにスクリプトを再配置することで、GlideAjax 呼び出しを 1 レベル深く埋めています。スクリプトは、GlideAjax 呼び出しを実行する前にアサインをチェックします。これにより、assignment_group フィールドが既に設定されている場合、サーバールックアップが防止されます。
    //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);
    }