How to populate Content Tree component in UI Builder using data resource?

Sergey6
Tera Contributor

Hello,

I'm trying to add a content tree component to the page. This component should display a tree generated based on the table. The table has a reference key to itself.

Is there any tutorial or example  how to do this using a dynamic binding?

What kind of Data Resource can be used to retrieve data from a table and populate "Items" parameter of the Content Tree component?

Thank you.

1 ACCEPTED SOLUTION

Guido Bernuetz
Giga Guru

Hi Sergey,

I have used the content tree component already. I'm using the Data Broker Server Script (in navigator called: "Transforms". Don't be confused! ;))

You must prepare an array of object(var answer in my script) with the properties "id" and "label".

For additional hints see my article: UI Builder Component: Content Tree

Here an example to work with different tables in one tree.

find_real_file.png

the script (it's working with 4 different tables, yours should be a more simple one):

function transform(input) {
    var piID = input.productID;
    var answer = [];
    var expanded = [];
    var level = 0;
    var MAXLEVEL = 9; // maximum for recursion level

    var inventoryObj = getInventoryObj(piID);
    if (inventoryObj == null) return answer;
    var expPathm = [inventoryObj.id];
    expanded.push(expPathm);

    getchilds(piID, inventoryObj);

    answer.push(inventoryObj);

    var result = {
        titems: answer,
        exp: expanded
    };

    return result;

    function getchilds(sourceID, parentTree) {
        var childs = [];

        var grPI = new GlideRecord('sn_prd_invt_product_inventory');
        if (grPI.get(sourceID)) {
            var specObj = getSpecObj(grPI.getValue('specification'));
            if (specObj != null) {
                childs.push(specObj);
            }
        }
        getCIs(sourceID, childs);

        var gr = new GlideRecord('sn_prd_invt_product_inventory');
        gr.addQuery('parent_sold_product', sourceID);
        gr.query();
        while (gr.next()) {
            var childID = gr.getValue('sys_id');
            var inventoryObj2 = getInventoryObj(childID);
            if (level < 2) {
                var expPath = [expPathm[0], inventoryObj2.id];
                expanded.push(expPath);
            }
            if (level < MAXLEVEL && hasChildren(childID)) {
                level++;
                getchilds(childID, inventoryObj2);
                level--;
            }
            childs.push(inventoryObj2);
        }

        parentTree.children = childs;
    }

    function getInventoryObj(piID) {
        var record = null;
        var grSpec = new GlideRecord('sn_prd_invt_product_inventory');
        if (grSpec.get(piID)) {
            var specLabel = "PI: " + grSpec.getValue('name');
            record = {
                id: grSpec.getValue('sys_id') + '#sn_prd_invt_product_inventory',
                label: specLabel
            };
        }
        return record;
    }

    function getCIs(piID, childArray) {
        var ciItem = null;
        var grIBI2SP = new GlideRecord('sn_install_base_m2m_installed_product');
        grIBI2SP.addQuery('sold_product', piID);
        grIBI2SP.query();
        while (grIBI2SP.next()) {
            var grIBI = new GlideRecord('sn_install_base_item');
            if (grIBI.get(grIBI2SP.getValue('install_base_item'))) {
                ciItem = {
                    id: grIBI.getValue('configuration_item') + '#cmdb_ci',
                    label: "CI:" + grIBI.getDisplayValue('configuration_item')
                };
                childArray.push(ciItem);

            }
        }
    }

    function getSpecObj(piID) {
        var record = null;
        var grSpec = new GlideRecord('sn_prd_pm_specification');
        if (grSpec.get(piID)) {
            var clName = grSpec.getValue('sys_class_name');
            var spPrefix = "SP";
            if (clName == 'sn_prd_pm_resource_specification') {
                spPrefix = 'RS';
            } else if (clName == 'sn_prd_pm_product_specification') {
                spPrefix = 'PS';
            } else if (clName == 'sn_prd_pm_service_specification') {
                spPrefix = 'CFSS';
            }
            var specLabel = spPrefix + ': ' + grSpec.getValue('number') + " " + grSpec.getValue('name');
            record = {
                id: grSpec.getValue('sys_id') + '#' + clName,
                label: specLabel
            };
        }
        return record;
    }

    // returns number of children
    function hasChildren(sourceID) {
        var result = false;
        var gaRels = new GlideAggregate('sn_prd_invt_product_inventory');
        gaRels.addQuery('parent_sold_product', sourceID);
        gaRels.addAggregate('COUNT');
        gaRels.query();
        if (gaRels.next()) {
            var cnt = gaRels.getAggregate('COUNT');
            if (cnt > 0) {
                result = true;
            }
        }
        return result;
    }
}

The definition of the output schema:

[
	{
		"name": "tree",
		"label": "Tree Content",
		"description": "",
		"readOnly": true,
		"fieldType": {
			"titems": {
				"name": "titems",
				"label": "Array of Tree Items",
				"description": "",
				"readOnly": true,
				"fieldType": "array"
			},
			"exp": {
				"name": "exp",
				"label": "Expanded Items",
				"description": "Array of expanded items",
				"readOnly": true,
				"fieldType": "array"
			}
		}
	}
]

Data binding to the content tree:

find_real_file.png

I hope that helps you.

I am not a helpful hunter.
I will always try to give a meaningful and valid answer.

View solution in original post

6 REPLIES 6

Guido Bernuetz
Giga Guru

Hi Sergey,

I have used the content tree component already. I'm using the Data Broker Server Script (in navigator called: "Transforms". Don't be confused! ;))

You must prepare an array of object(var answer in my script) with the properties "id" and "label".

For additional hints see my article: UI Builder Component: Content Tree

Here an example to work with different tables in one tree.

find_real_file.png

the script (it's working with 4 different tables, yours should be a more simple one):

function transform(input) {
    var piID = input.productID;
    var answer = [];
    var expanded = [];
    var level = 0;
    var MAXLEVEL = 9; // maximum for recursion level

    var inventoryObj = getInventoryObj(piID);
    if (inventoryObj == null) return answer;
    var expPathm = [inventoryObj.id];
    expanded.push(expPathm);

    getchilds(piID, inventoryObj);

    answer.push(inventoryObj);

    var result = {
        titems: answer,
        exp: expanded
    };

    return result;

    function getchilds(sourceID, parentTree) {
        var childs = [];

        var grPI = new GlideRecord('sn_prd_invt_product_inventory');
        if (grPI.get(sourceID)) {
            var specObj = getSpecObj(grPI.getValue('specification'));
            if (specObj != null) {
                childs.push(specObj);
            }
        }
        getCIs(sourceID, childs);

        var gr = new GlideRecord('sn_prd_invt_product_inventory');
        gr.addQuery('parent_sold_product', sourceID);
        gr.query();
        while (gr.next()) {
            var childID = gr.getValue('sys_id');
            var inventoryObj2 = getInventoryObj(childID);
            if (level < 2) {
                var expPath = [expPathm[0], inventoryObj2.id];
                expanded.push(expPath);
            }
            if (level < MAXLEVEL && hasChildren(childID)) {
                level++;
                getchilds(childID, inventoryObj2);
                level--;
            }
            childs.push(inventoryObj2);
        }

        parentTree.children = childs;
    }

    function getInventoryObj(piID) {
        var record = null;
        var grSpec = new GlideRecord('sn_prd_invt_product_inventory');
        if (grSpec.get(piID)) {
            var specLabel = "PI: " + grSpec.getValue('name');
            record = {
                id: grSpec.getValue('sys_id') + '#sn_prd_invt_product_inventory',
                label: specLabel
            };
        }
        return record;
    }

    function getCIs(piID, childArray) {
        var ciItem = null;
        var grIBI2SP = new GlideRecord('sn_install_base_m2m_installed_product');
        grIBI2SP.addQuery('sold_product', piID);
        grIBI2SP.query();
        while (grIBI2SP.next()) {
            var grIBI = new GlideRecord('sn_install_base_item');
            if (grIBI.get(grIBI2SP.getValue('install_base_item'))) {
                ciItem = {
                    id: grIBI.getValue('configuration_item') + '#cmdb_ci',
                    label: "CI:" + grIBI.getDisplayValue('configuration_item')
                };
                childArray.push(ciItem);

            }
        }
    }

    function getSpecObj(piID) {
        var record = null;
        var grSpec = new GlideRecord('sn_prd_pm_specification');
        if (grSpec.get(piID)) {
            var clName = grSpec.getValue('sys_class_name');
            var spPrefix = "SP";
            if (clName == 'sn_prd_pm_resource_specification') {
                spPrefix = 'RS';
            } else if (clName == 'sn_prd_pm_product_specification') {
                spPrefix = 'PS';
            } else if (clName == 'sn_prd_pm_service_specification') {
                spPrefix = 'CFSS';
            }
            var specLabel = spPrefix + ': ' + grSpec.getValue('number') + " " + grSpec.getValue('name');
            record = {
                id: grSpec.getValue('sys_id') + '#' + clName,
                label: specLabel
            };
        }
        return record;
    }

    // returns number of children
    function hasChildren(sourceID) {
        var result = false;
        var gaRels = new GlideAggregate('sn_prd_invt_product_inventory');
        gaRels.addQuery('parent_sold_product', sourceID);
        gaRels.addAggregate('COUNT');
        gaRels.query();
        if (gaRels.next()) {
            var cnt = gaRels.getAggregate('COUNT');
            if (cnt > 0) {
                result = true;
            }
        }
        return result;
    }
}

The definition of the output schema:

[
	{
		"name": "tree",
		"label": "Tree Content",
		"description": "",
		"readOnly": true,
		"fieldType": {
			"titems": {
				"name": "titems",
				"label": "Array of Tree Items",
				"description": "",
				"readOnly": true,
				"fieldType": "array"
			},
			"exp": {
				"name": "exp",
				"label": "Expanded Items",
				"description": "Array of expanded items",
				"readOnly": true,
				"fieldType": "array"
			}
		}
	}
]

Data binding to the content tree:

find_real_file.png

I hope that helps you.

I am not a helpful hunter.
I will always try to give a meaningful and valid answer.

Hi Guido,

Thank you for this information!

I used JavaScript to build the tree but I use it on the Content Tree component level.

Using "Transforms" is more accurate.

 

Rivka Br
Tera Contributor

Thanks you for Information,

maybe you can know why when select on row in tree or narrow one of the parents

all the parents become narrowed?

RivkaBr_0-1689838118745.png

RivkaBr_1-1689838144830.png

 

 

 

The selection of items in the tree is an extra JSON string and can be controlled also by client script.
Maybe that there is such a part of logic in your page.

I am not a helpful hunter.
I will always try to give a meaningful and valid answer.