클라이언트 측 스크립팅 설계 및 처리

  • 릴리스 버전: Xanadu
  • 업데이트 날짜 2026년 01월 09일
  • 읽기18분
  • 클라이언트 스크립트를 잘 디자인하면 사용자가 양식을 완성하는 데 걸리는 시간을 줄일 수 있습니다.

    적절한 클라이언트 측 처리는 양식 로드에 따라 먼저 달라집니다. 양식 로드 전에 기록을 업데이트하면 클라이언트 측 처리를 우회하는 예기치 않은 결과가 발생할 수 있습니다.

    양식의 필드 값을 제어하는 클라이언트 스크립트를 만드는 경우 다른 방법을 사용하여 목록에서 이러한 필드 값을 제어해야 합니다. 다음을 수행할 수 있습니다.
    • 테이블에 대한 목록 편집을 비활성화합니다.
    • 목록 편집을 위한 적절한 비즈니스 규칙 또는 액세스 통제를 생성합니다.
    • 데이터 정책을 생성합니다.
    • 별도의 onCellEdit 클라이언트 스크립트를 만듭니다.

    목록 편집 제한

    양식의 필드에 대한 UI 정책 또는 클라이언트 스크립트를 만드는 경우 다른 방법을 사용하여 해당 필드의 데이터가 목록에서 유사하게 제어되도록 해야 합니다.

    onCellEdit 클라이언트 스크립트를 제외하고 UI 정책 및 클라이언트 스크립트는 양식에만 적용됩니다. 클라이언트 스크립트를 사용할 때 다음 방법을 사용하여 목록 편집을 제한합니다.
    • 테이블에 대한 목록 편집을 비활성화합니다.
    • 목록 편집을 위한 적절한 비즈니스 규칙 또는 액세스 통제를 생성합니다.
    • 데이터 정책을 생성합니다.
    • 별도의 onCellEdit 클라이언트 스크립트를 만듭니다.

    서버 조회 최소화

    클라이언트 데이터를 최대한 많이 사용하여 시간이 많이 걸리는 서버 조회의 필요성을 제거합니다.

    클라이언트 스크립팅은 클라이언트에서 사용할 수 있는 데이터 또는 서버에서 검색된 데이터를 사용합니다. 서버에서 정보를 얻는 가장 좋은 방법은 g_scratchpad 및 비동기 GlideAjax 조회입니다.

    이러한 방법의 주요 차이점은 양식이 로드될 때(정보가 서버에서 클라이언트로 푸시됨) g_scratchpad 한 번 전송되는 반면 GlideAjax는 클라이언트가 서버에서 정보를 요청할 때 동적으로 트리거된다는 것입니다.

    주:
    GlideRecord 및 g_form.getReference()도 서버 정보를 검색하는 데 사용할 수 있습니다. 그러나 이러한 방법은 성능에 미치는 영향으로 인해 더 이상 권장되지 않습니다. 두 방법 모두 대부분의 케이스에 하나의 필드만 필요할 때 요청된 GlideRecord의 모든 필드를 검색합니다.

    g_scratchpad를 사용하여 서버 데이터 검색

    g_scratchpad 개체는 클라이언트가 양식에서 사용할 수 없는 정보를 필요로 하는 경우와 같이 서버에서 클라이언트로 정보를 전달합니다.

    예를 들어, 필드 u_retrieve에 액세스해야 하는 클라이언트 스크립트가 있고 필드가 양식에 없으면 클라이언트 스크립트에서 데이터를 사용할 수 없습니다. 이 상황에 대한 일반적인 해결 방법은 필드를 폼에 배치한 다음 클라이언트 스크립트나 UI 정책으로 항상 숨기는 것입니다. 이 솔루션은 구성 속도가 빠를 수 있지만 실행 속도가 느립니다.

    양식이 로드되기 전에 클라이언트가 서버에서 필요로 하는 정보를 알고 있는 경우 표시 비즈니스 규칙에서 이 정보를 저장할 g_scratchpad 속성을 만들 수 있습니다. 양식이 요청될 때 Theg_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() 를 사용하는 경우 참조 필드 표시 값을 세 번째 매개변수로 포함해야 합니다. 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');
    

    클라이언트 스크립트 순서 설정

    순서 필드를 사용하여 클라이언트 스크립트의 실행 순서를 제어합니다. 두 개 이상의 클라이언트 스크립트를 동시에 실행한 후 충돌하지 않도록 하려면 스크립트 실행 순서를 추가할 수 있습니다.

    시작하기 전에

    필요한 역할: admin

    이 태스크 정보

    클라이언트 스크립트에 순서를 추가하면 가장 낮은 번호에서 가장 높은 번호로 정렬된 처리 순서가 생성됩니다. 두 스크립트가 충돌하는 경우 번호가 낮은 클라이언트 스크립트가 먼저 실행됩니다.

    프로시저

    1. 다음으로 이동 모두 > 시스템 정의 > 클라이언트 스크립트 을 클릭하고 기존 클라이언트 스크립트를 열거나 [새로 만들기]를 클릭합니다.
    2. 주문 필드를 포함하도록 양식 레이아웃 구성
    3. 다른 클라이언트 스크립트와 관련하여 실행하려는 순서에 따라 순서 필드에 숫자를 추가합니다.
      먼저 실행할 스크립트에 대해 더 낮은 숫자를 선택합니다.

    DOM 조작 방지

    가능하면 DOM(문서 개체 모델) 조작을 피하십시오. 브라우저가 업데이트될 때 유지 관리 문제가 발생할 수 있습니다.

    대신 GlideForm API를 사용하거나 솔루션에 대한 다른 접근 방식을 고려하십시오. 일반적으로 DOM 조작 메서드를 사용할 때는 ID로 또는 CSS 선택기를 사용하여 DOM의 요소를 참조해야 합니다. 기본 DOM 요소를 참조할 때 DOM 내의 요소 ID 또는 배치가 변경되어 코드 작동이 중지되거나 오류가 발생할 위험이 있습니다. 미리 생각하고, 주의를 기울이고, 발생하는 위험을 완전히 이해하십시오. 이러한 개체를 검토하고 가능한 한 DOM 조작 메서드의 사용을 줄이십시오.

    전역 클라이언트 스크립트 방지

    전역 클라이언트 스크립트는 선택한 테이블이 전역인 모든 클라이언트 스크립트입니다. 전역 클라이언트 스크립트에는 테이블 제한이 없으므로 시스템의 모든 페이지에 로드되어 프로세스에서 브라우저 로드 지연이 발생합니다.

    모든 페이지에 이런 종류의 스크립트를로드하는 것은 아무런 이점이 없습니다.

    대안으로, 그리고 보다 모듈화되고 확장 가능한 접근 방식을 위해 클라이언트 스크립트를 모든 하위/확장 테이블에 대해 파생될 수 있는 기본 테이블(예: Task[task] 또는 Configuration Item[cmdb_ci])로 이동하는 것이 좋습니다. 이렇게 하면 시스템이 UI의 모든 양식(예: 홈 페이지 또는 Service Catalog와 같이 스크립트가 거의 필요하지 않은 경우)에 스크립트를 로드할 필요가 없습니다.

    함수에 코드 포함

    클라이언트 스크립트의 코드를 함수 안에 넣습니다.

    기능이 없는 클라이언트 스크립트는 변수 범위에 문제를 일으킵니다. 코드가 함수로 묶여 있지 않으면 변수 및 기타 개체를 사용할 수 있으며 다른 모든 클라이언트 측 스크립트에서 공유됩니다. 동일한 변수 이름을 사용하는 경우 충돌할 수 있습니다. 이로 인해 문제를 해결하기 어려운 예기치 않은 결과가 발생할 수 있습니다.

    다음 예를 고려하십시오.
    var state = "6";
     
    function onSubmit() {
     
       if(g_form.getValue('incident_state') == state) {
       		alert("This incident is Resolved");
       }
    }
    상태 변수는 함수로 묶여 있지 않기 때문에 모든 클라이언트 측 스크립트에서 액세스할 수 있습니다. 다른 스크립트도 공통 변수 이름 state를 사용할 수 있습니다. 중복된 이름이 충돌하여 예기치 않은 결과가 발생할 수 있습니다. 이러한 문제는 격리 및 해결하기가 어렵습니다. 이 문제를 방지하려면 모든 코드가 함수에 래핑되어 있는지 확인합니다.
    function onSubmit() {
     
       var state = "6";
     
       if(g_form.getValue('incident_state') == state) {
       		alert("This incident is Resolved");
       }
    }

    이 솔루션은 변수 상태 의 범위가 onSubmit() 함수로 제한되기 때문에 훨씬 더 안전합니다. 따라서 상태 변수는 다른 클라이언트 측 스크립트의 상태 변수와 충돌하지 않습니다.

    필요한 스크립트만 실행

    시간이 많이 걸리는 스크립트를 불필요하게 실행하지 않으려면 클라이언트 스크립트가 필요한 작업만 수행하도록 하십시오.

    다음 예제에서는 초기 코드 샘플의 향상된 기능을 보여 줍니다. 각 예제에서는 성능을 향상시키고 불필요한 호출을 방지하기 위한 스크립트의 특정 개선 사항을 보여 줍니다.

    클라이언트 스크립트에는 조건 필드가 없습니다. 즉, 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 검사를 사용합니다.
    주:
    이 예제에서는 사용자가 값을 변경한 다음 원래 값으로 다시 변경하는 것을 catch하지 않습니다.
    //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 호출은 서버 호출을 실행하기 전에 클라이언트가 사용할 수 있는 가능한 한 많은 항목을 확인하기 위해 스크립트를 다시 정렬하여 한 수준 더 깊이 묻혀 있습니다. 스크립트는 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);
    }