The Zurich release has arrived! Interested in new features and functionalities? Click here for more

Copy widget data into catalog variable

Anup9431
Tera Contributor

Hello Community,

Please review my code and suggest why my widget is not transferred to my catalog variable.

api.controller = function($scope, $timeout) {
    var c = this;

    // ----- safe context & options -----
    c.field = ($scope && $scope.field) || {};
    c.options = ($scope && $scope.options) || {};
    c.g_form = ($scope && typeof $scope.getGlideForm === "function") ? $scope.getGlideForm() : null;
    c.readOnly = !!(c.field.isReadonly ||
        c.field.read_only ||
        c.field.displayValueOnly ||
        ($scope && $scope.data && $scope.data.isReadOnly) ||
        c.options.force_readonly);

    c.backupVarName =
        (c.options && c.options.backup_variable_name) ? c.options.backup_variable_name : "";

    // ----- model -----
    c.model = {
        version: 1,
        columns: [],
        rows: []
    };

    // helpers
    function slugify(s) {
        return (
            (String(s || "")
                .toLowerCase()
                .replace(/[^a-z0-9]+/g, "_")
                .replace(/^_+|_+$/g, "")
                .substring(0, 30)) ||
            "col_" + Math.random().toString(36).substr(2, 5)
        );
    }

    function uniqueKey(base) {
        var key = base,
            i = 1;
        var existing = c.model.columns.map(function(x) {
            return x.key;
        });
        while (existing.indexOf(key) !== -1) {
            key = base + "_" + i++;
        }
        return key;
    }

    // ----- fixed column definitions -----
    function seedColumns() {
        var defs = [{
                key: "name",
                label: "Name",
                type: "string"
            },
            {
                key: "surname",
                label: "Surname",
                type: "string"
            },
            {
                key: "birthday",
                label: "Birthday",
                type: "date"
            },
            {
                key: "email",
                label: "Email",
                type: "string"
            },
            {
                key: "telephone",
                label: "Telephone",
                type: "string"
            },
            {
                key: "id_card",
                label: "No. ID Card",
                type: "string"
            },
            {
                key: "frontpage_id",
                label: "Frontpage ID card",
                type: "attachments"
            },
            {
                key: "backpage_id",
                label: "Backpage ID card",
                type: "attachments"
            }
        ];

        c.model.columns = defs.map(function(d) {
            var key = d.key ? slugify(d.key) : slugify(d.label);
            return {
                key: uniqueKey(key),
                label: d.label || d.key || "Column",
                type: d.type || "string"
            };
        });
    }

    // ----- restore from existing value if editing -----
    function seedFromValue() {
        if (!c.field || !c.field.value) return false;
        try {
            var obj = JSON.parse(c.field.value);
            if (obj && obj.columns && obj.rows) {
                c.model.columns = obj.columns;
                c.model.rows = obj.rows.map(function(r) {
                    r.__id = r.__id || "row_" + Math.random().toString(36).substr(2, 9);
                    c.model.columns.forEach(function(col) {
                        if (col.type === "attachments" && !r[col.key]) r[col.key] = [];
                    });
                    return r;
                });
                return true;
            }
        } catch (e) {}
        return false;
    }

    // initialize
    if (!seedFromValue()) seedColumns();

    // ensure at least one row exists
    if (!c.model.rows.length) {
        var r = {
            __id: "row_" + Math.random().toString(36).substr(2, 9)
        };
        c.model.columns.forEach(function(col) {
            if (col.type === "number") r[col.key] = null;
            else if (col.type === "boolean") r[col.key] = false;
            else if (col.type === "attachments") r[col.key] = [];
            else r[col.key] = "";
        });
        c.model.rows.push(r);
    }

    // ----- row operations -----
    c.addRow = function() {
        if (c.options.max_rows && c.model.rows.length >= c.options.max_rows) return;
        var r = {
            __id: "row_" + Math.random().toString(36).substr(2, 9)
        };
        c.model.columns.forEach(function(col) {
            if (col.type === "number") r[col.key] = null;
            else if (col.type === "boolean") r[col.key] = false;
            else if (col.type === "attachments") r[col.key] = [];
            else r[col.key] = "";
        });
        c.model.rows.push(r);
        c.save();
    };

    c.removeRow = function(index) {
        if (index >= 0 && index < c.model.rows.length) {
            c.model.rows.splice(index, 1);
            c.save();
        }
    };

    // ----- attachment handling -----
    c.handleFile = function(files, rowIndex, colKey) {
        if (!files || !files.length) return;
        var f = files[0];
        var reader = new FileReader();
        reader.onload = function(evt) {
            $scope.$apply(function() {
                var attachment = {
                    name: f.name,
                    size: f.size,
                    type: f.type || "application/octet-stream",
                    dataUrl: evt.target.result,
                    uploadedAt: new Date().toISOString()
                };
                var row = c.model.rows[rowIndex];
                if (!row) return;
                row[colKey] = row[colKey] || [];
                row[colKey].push(attachment);
                c.save();
            });
        };
        reader.readAsDataURL(f);
    };

    c.removeAttachment = function(rowIndex, colKey, attIndex) {
        var row = c.model.rows[rowIndex];
        if (!row) return;
        var arr = row[colKey] || [];
        if (attIndex >= 0 && attIndex < arr.length) {
            arr.splice(attIndex, 1);
            c.save();
        }
    };

    c.downloadAttachment = function(att) {
        if (!att || !att.dataUrl) return;
        var a = document.createElement("a");
        a.href = att.dataUrl;
        a.download = att.name || "download";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    };

    c.renderCell = function(value, col) {
        if (!col) return "";
        if (col.type === "boolean") return value ? "Yes" : "No";
        if (col.type === "attachments")
            return (value || []).map(function(a) {
                return a.name;
            }).join(", ");
        return value == null ? "" : value;
    };

    // ----- persist model -----
    c.save = function() {
        try {
            var payload = JSON.stringify(c.model || []);
            if (c.field && c.field.name) c.field.value = payload;
            if (c.g_form && c.field && c.field.name) {
                c.g_form.setValue(c.field.name, payload);
            }
            if (c.backupVarName) {
                if (c.g_form) c.g_form.setValue(c.backupVarName, payload);
            }
        } catch (err) {
            console.error("save() error", err);
        }
    };

    // watch model changes
    $scope.$watch(
        function() {
           return JSON.stringify(c.model);
         
        },
        function(n, o) {
            if (n !== o) c.save();
        }
    );

    // initial save
    c.save();
    $scope.c = c;

    $timeout(function() {
        console.log("CUSTOM VARIABLE DEBUG:", {
            field: c.field && c.field.name,
            g_form: !!c.g_form,
            backup: c.backupVarName
        });
    }, 300);
};
4 REPLIES 4

Ankur Bawiskar
Tera Patron
Tera Patron

@Anup9431 

Sorry didn't get your question.

you are unable to add this widget to your catalog item when variable is of type Custom?

share some screenshots and what's your business requirement?

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

Hi Ankur,

I need the data of the widget to be transferred to another catalog variable.

I have 2 variables : 1 custom type with widget added and 2  a simple multi-line text.

I want the custom variable's data to be copied to multi-line text.

Initial requirement was to transfer the custom variable to RITM. Since it didn't work, I opted for copying the custom variable into multi-line and transferring to RITM.

Hope it is clear.

@Anup9431  Below has worked from me in past.

 

$scope.page.g_form.setValue('target_catalog_variable_name', 'any data from widget');

Raghav
MVP 2023
LinkedIn

RaghavSh
Kilo Patron

@Anup9431 Your question is not quite clear but below is mostly used to add data from widget (called in custom variable) to service catalog variables.

 

// used in widget client scripi

var val = document.getElementByID() ; // get the value from HTML 
$scope.page.g_form.setValue('catalog_variable_name', val);

Raghav
MVP 2023
LinkedIn