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