如何在ServiceNow中创建重复表单部分

时间:2018-02-21 03:56:23

标签: servicenow

我是ServiceNow的新手,并开始创建新表单。其中一个要求是创建一个重复的表单部分(下面的图像是组件的设计)。

我是否知道ServiceNow中的任何默认组件,或者我们需要为此创建自定义小部件?

enter image description here

2 个答案:

答案 0 :(得分:0)

没有OOB方法可以做到这一点。

我过去解决问题的方式如下:

  1. 创建表示要捕获的数据的单个变量或变量集
  2. 创建UI宏/按钮“添加”
  3. 单击时,该按钮应触发一个脚本,该脚本将字段中的数据添加到JSON对象中,然后用于使用一些友好的数据表示来填充HTML元素。

    以下是我保存的一些代码,但请记住,我必须像一年前那样做,所以它不是超级新鲜的。

    “添加”按钮:

    <?xml version="1.0" encoding="utf-8" ?>
    
    <!--
        UI Page
        Name: http_addServerButton_loadBalancer
        Category: General
        Direct: false
    
        Note that this will change slightly in name, and in the argument being passed, depending on whether the button is for the http, https, or TCP
        sections.
    -->
    
    <j:jelly trim="false"
             xmlns:j="jelly:core"
             xmlns:g="glide"
             xmlns:j2="null"
             xmlns:g2="null" >
        <script language="javascript"
                src="addServerButtonClicked.jsdbx" />
        <button name="add"
                onclick="addServerButtonClicked('http')" >Add
        </button >
    </j:jelly >
    

    处理添加操作的UI脚本:

    /*
        UI Script
        Name: addServerButtonClicked
        Category: General
        Direct: false
    */
    
    /***********BEGIN***********/
    
    // todo: Create onSubmit validation. Make sure users don't submit a form with existing server name/port data filled out but not added to the JSON.
    // todo: Change add new button name to "add server".
    
    /**
     * This function is called when the "Add Server" button is clicked
     */
    function addServerButtonClicked(protocol) {
        g_form.hideFieldMsg('server_name_' + protocol, true);
        g_form.hideFieldMsg('server_port_' + protocol, true);
    
        //todo: validate the server AND port are filled out for the specific protocol selected, using "'server_name_' + protocol" and "'server_port_' + protocol"
        //todo: If not BOTH populated, then add field mesage and tell the user that they are a bad user and should feel bad about their life choices.
    
        var isFormValid = validateForm(protocol);
        if (isFormValid) {
            var fieldName = 'server_name_' + protocol;
            g_form.getReference(fieldName, function(gr) {
                //cheap way to combine relevant objects from differing scope without writing a gigantic anonymous inline function.
                buildDataObject(gr, protocol);
            });
        } else {
            alert('form invalid'); // todo: remove
            // todo: throw some error or something
        }
    }
    
    /**
     * This function is called whenever a new server is added to the request. It parses the existing JSON data into an object, and then goes about adding on to it.
     * @param serverGR {GlideRecord} - The GlideRecord object returned from the asynchronous nonHireATSCandidatesEncodedQuery that's run when add button is clicked. This param is auto-populated.
     */
    function buildDataObject(serverGR, protocol) {
        if (!serverGR) {
            console.error('No valid server was found.');
        }
        // Grab the value of the JSON Data field
        var existingJsonData = g_form.getValue('json_data');
        // If the JSON Data field already contains some existing JSON data, use that as the starting
        // point for our object. Otherwise (if this is the first entry), declare a new object.
        var dataObject = existingJsonData ? JSON.parse(existingJsonData) : {
            http: {},
            https: {},
            tcp: {}
        };
    
        //todo: write and call a function to get the protocol header info crap and append it to the object.
    
    
        // Set the "serverName" property to either the server's name, or (if no name exists for this server),
        // its' IP address of (if no name OR IP address exists for this server), its' sys_id.
    
        var requestedFor = g_form.getValue('requested_for');
        var serverSysId = serverGR.getValue('sys_id');
        var serverIP = serverGR.getValue('ip_address');
    
        var serverName = serverGR.getValue('name') ? serverGR.getValue('name') : serverGR.getValue('ip_address') ? serverGR.getValue('ip_address') : serverSysId = serverGR.getValue('sys_id');
    
        var serverPort;
        var tcpIPPort;
        var lbMethod;
        var persistence;
        var monitorRequest;
        var monitorResponse;
        //Okay, yeah, so I could've used one line to set each of these vars, and used syntax like "'server_port_' + protocol.toLowerCase()".
        //But instead of that, I did it this way. Why? Because I thought for a minute at 2AM that this would help future-me, in the event that
        //we ever had stupid variable names to compete with. Sooo... behold, the pointless switch-case block.
        switch (protocol.toLowerCase()) {
            case 'http':
                serverPort = g_form.getValue('server_port_http');
                tcpIPPort = g_form.getValue('tcp_ip_http');
                lbMethod = g_form.getValue('lb_method_http');
                persistence = g_form.getValue('persistence_http');
                monitorRequest = g_form.getValue('monitor_request_http');
                monitorResponse = g_form.getValue('monitor_response_http');
                // Clear the data from these two fields so it's clear that they need to be re-populated.
                g_form.setValue('server_port_http', '');
                g_form.setValue('server_name_http', '');
                break;
            case 'https':
                serverPort = g_form.getValue('server_port_https');
                tcpIPPort = g_form.getValue('tcp_ip_https');
                lbMethod = g_form.getValue('lb_method_https');
                persistence = g_form.getValue('persistence_https');
                monitorRequest = g_form.getValue('monitor_request_https');
                monitorResponse = g_form.getValue('monitor_response_https');
                // Clear the data from these two fields so it's clear that they need to be re-populated.
                g_form.setValue('server_port_https', '');
                g_form.setValue('server_name_https', '');
                break;
            case 'tcp':
                serverPort = g_form.getValue('server_port_tcp');
                tcpIPPort = g_form.getValue('tcp_ip_tcp');
                lbMethod = g_form.getValue('lb_method_tcp');
                persistence = g_form.getValue('persistence_tcp');
                monitorRequest = g_form.getValue('monitor_request_tcp');
                monitorResponse = g_form.getValue('monitor_response_tcp');
                // Clear the data from these two fields so it's clear that they need to be re-populated.
                g_form.setValue('server_port_tcp', '');
                g_form.setValue('server_name_tcp', '');
                break;
        }
    
    
    
    
    
        if (!serverIP || !serverSysId || !serverPort || !serverName) {
            // return; //Halt execution, since we don't have some of the data we need.
            // todo: re-enable the above line after testing. Need to figure out how to handle errors, and what constitutes an error.
            console.error('Not able to get one of these important values: [IP, Sys ID, Port, Server]')
        }
    
        // Populate the data object.
        // Using bracket-notation here, in order to use a variable name as the object property name.
        dataObject[protocol][serverSysId] = {};
        dataObject[protocol][serverSysId].name = serverName;
        dataObject[protocol][serverSysId].port = serverPort;
        dataObject[protocol][serverSysId].sysid = serverSysId;
        dataObject[protocol][serverSysId].ip = serverIP;
    
    
        console.log(dataObject);
        var dataSummary = '';
    
        /*
            This bit's pretty complex.
            For each "prot" (protocol) in the outermost object,
            check if the object corresponding to that protocol is truthy (not empty).
            If it isn't empty, insert a header (H3) for that protocol/section.
            Then, for each "prop" (server element) in that protocol object, print out some details about it.
        */
        for (var prot in dataObject) {
            if (!isObjEmpty(dataObject[prot]) && dataObject.hasOwnProperty(prot) && prot !== 'requestor' && prot !== 'generalInfo') {
                dataSummary += '<h3>' + prot.toUpperCase() + '</h3>';
                for (var prop in dataObject[prot]) {
                    if (dataObject[prot].hasOwnProperty(prop) && prop !== 'protocolDetails') {
                        dataSummary += '<b>Server name</b>: ' + dataObject[prot][prop].name + '<br />Server Sys ID: ' + dataObject[prot][prop].sysid + '<br />IP: ' + dataObject[prot][prop].ip + '<br />Port: ' + dataObject[prot][prop].port + '<br /><br />';
                    }
                }
            }
        }
    
        dataObject = populateObjectMeta(dataObject);
    
        g_form.setValue('request_summary', dataSummary);
        g_form.setValue('json_data', JSON.stringify(dataObject));
    
        g_form.setVisible('request_summary', true);
    
    }
    
    function populateObjectMeta(dataObject) {
        var i;
        //Get boolean values for the three check-boxes representing whether the user wants HTTP, HTTPS, or TCP.
        var httpSelected = isThisTrueOrWhat(g_form.getValue('http_select'));
        var httpsSelected = isThisTrueOrWhat(g_form.getValue('https_select'));
        var tcpSelected = isThisTrueOrWhat(g_form.getValue('tcp_select')); //todo: use these to populate more metadata in the relevant object
    
        //Populate requestor details
        dataObject.requestor = {};
        dataObject.requestor.name = g_form.getReference('requested_by').getValue('name');
        dataObject.requestor.sysID = g_form.getValue('requested_by');
        dataObject.requestor.email = g_form.getValue('email');
        //Populate general load balancing details
        dataObject.generalInfo = {};
        dataObject.generalInfo.dnsHost = g_form.getValue('dns_host');
        dataObject.generalInfo.domainName = g_form.getValue('domain_name');
        dataObject.generalInfo.application = isThisTrueOrWhat(g_form.getValue('application_not_found')) ? g_form.getValue('application_name_text') : g_form.getReference('application_name_ref').getValue('name');
        dataObject.generalInfo.lifeCycle = g_form.getValue('lifecycle');
        dataObject.generalInfo.site = g_form.getReference('site').getValue('name');
        //Populate protocol details for HTTP, HTTPS, and TCP.
        var selectedProtocols = getSelectedProtocols();
        console.log(selectedProtocols);
        for (i = 0; i < selectedProtocols.length; i++) {
            console.log('Adding data to dataObj with selected protocol ' + [selectedProtocols[i]]);
            dataObject[selectedProtocols[i]].protocolDetails = {};
            dataObject[selectedProtocols[i]].protocolDetails.tcpIPPort = g_form.getValue('tcp_ip_' + selectedProtocols[i]);
            dataObject[selectedProtocols[i]].protocolDetails.lbMethod = g_form.getValue('lb_method_' + selectedProtocols[i]);
            dataObject[selectedProtocols[i]].protocolDetails.persistence = g_form.getValue('persistence_' + selectedProtocols[i]);
            dataObject[selectedProtocols[i]].protocolDetails.monitorRequest = g_form.getValue('monitor_request_' + selectedProtocols[i]);
            dataObject[selectedProtocols[i]].protocolDetails.monitorResponse = g_form.getValue('monitor_response_' + selectedProtocols[i]);
        }
    
        return dataObject;
    }
    
    function getSelectedProtocols() {
        var selectedProtocols = [];
        var httpSelected = isThisTrueOrWhat(g_form.getValue('http_select'));
        var httpsSelected = isThisTrueOrWhat(g_form.getValue('https_select'));
        var tcpSelected = isThisTrueOrWhat(g_form.getValue('tcp_select'));
        if (httpSelected) {
            selectedProtocols.push('http');
        }
        if (httpsSelected) {
            selectedProtocols.push('https');
        }
        if (tcpSelected) {
            selectedProtocols.push('tcp');
        }
        return selectedProtocols;
    }
    
    function validateForm(protocol) {
        var port;
    
        switch (protocol.toLowerCase()) {
            case 'http':
                port = g_form.getValue('server_port_http');
                break;
            case 'https':
                port = g_form.getValue('server_port_https');
                break;
            case 'tcp':
                port = g_form.getValue('server_port_tcp');
                break;
        }
    
        //todo: validate port, and a bunch of other stuff.
        return true;
    }
    
    /**
     * Adds one object to another, nesting the child object into the parent.
     * this is to get around javascript's immutable handling of objects.
     * @param name {String} - The name of the property of the parent object, in which to nest the child object. <br />For example, if the name parameter is set to "pickles" then "parent.pickles" will return the child object.
     * @param child {Object} - The object that should be nested within the parent object.
     * @param [parent={}] {Object} - The parent object in which to nest the child object. If the parent object is not specified, then the child object is simple nested into an otherwise empty object, which is then returned.
     * @returns {Object} - A new object consisting of the parent (or an otherwise empty object) with the child object nested within it.
     * @example
     * //sets myNewObject to a copy of originalObject, which now also contains the original (yet un-linked) version of itself as a child, under the property name "original"
     * var myNewObject = addObjToObj("original", originalObj, originalObj);
     */
    function addObjToObj(name, child, parent) {
        if (!parent) {
            parent = {};
        }
        parent[name] = child;
        return parent;
    }
    
    function isObjEmpty(o) {
        for (var p in o) {
            if (o.hasOwnProperty(p)) {
                return false;
            }
        }
        return true;
    }
    
    function isThisTrueOrWhat(b) {
        return ((typeof b == 'string') ? (b.toLowerCase() == 'true') : (b == true)); //all this just to properly return a bool in JS. THERE'S GOT TO BE A BETTER WAY!
    }
    

答案 1 :(得分:0)

只需创建一个具有您想要的功能的 UI 页面即可。 例如,点击新按钮会打开重复的表单视图。

从已填充的表单中获取作为对象列表的输入,将它们发送到处理创建的客户端可调用脚本 include(GlideAjax)。