Skip to content

mergeConcatDeep β€” GTM Variable Template for Object

VARIABLES β€Ί OBJECT
mergeConcatDeep EXTENDED Object
Direct (.tpl) Apply (.tpl)

Deep-merges two objects, concatenating arrays at all levels.



Deep arrays concatenated
INPUT
Base Object: {name: 'John', tags: ['user', 'active']}
Additional Object: {age: 30, tags: ['premium']}
OUTPUT
John
Deep non-array override
INPUT
Base Object: {status: 'pending', priority: 1, count: 5}
Additional Object: {status: 'completed', count: 10}
OUTPUT
completed

This is what you'll see when you open this variable in Google Tag Manager. Hover the icons for details.

mergeConcatDeep
Base Object
πŸ’Ύ The base object to merge from. Its properties will be overridden by the additional object.
Additional Object
πŸ’Ύ The object to merge in. Its properties take priority over the base object.
Input Setup
Input Function (optional)
βš™οΈ Optional pre-processing function applied to the base object before merging.
Result Handling
Output Function (optional)
βš™οΈ Optional function to apply to the merged object before returning it.
Base Object object
πŸ’‘ Type any text to see the result update live
🎯 Using special value β€” click input to type instead
Test with:
Falsy
Truthy
Additional Object object
mergeConcatDeep()


πŸ“œ View Implementation Code
/**
* Deep merges two objects recursively, concatenating arrays instead of replacing them.
*
* @param {Object} data.src - The base object to merge from.
* @param {Object} data.add - The additional object to merge in.
* @param {Function|string} [data.out] - Optional output handler.
*
* Direct-mode specific parameters:
* @param {Function} [data.pre] - Optional pre-processor function.
*
* @returns {Object} A new object with deep merged properties. Arrays are concatenated, nested objects are recursively merged.
*
* @framework ggLowCodeGTMKit
*/
const getType = require('getType');
const mergeConcatDeep = function(baseObject, additionalObject) {
const mergedObject = {};
if (!baseObject || typeof baseObject !== 'object') {
return additionalObject || {};
}
if (!additionalObject || typeof additionalObject !== 'object') {
return baseObject;
}
for (let key in baseObject) {
if (baseObject.hasOwnProperty(key)) {
const baseVal = baseObject[key];
const addVal = additionalObject[key];
if (getType(baseVal) === 'array' && getType(addVal) === 'array') {
mergedObject[key] = baseVal.concat(addVal);
} else if (getType(baseVal) === 'object' && getType(addVal) === 'object') {
mergedObject[key] = mergeConcatDeep(baseVal, addVal);
} else if (addVal !== undefined) {
mergedObject[key] = addVal;
} else {
mergedObject[key] = baseVal;
}
}
}
for (let key in additionalObject) {
if (additionalObject.hasOwnProperty(key) && baseObject[key] === undefined) {
mergedObject[key] = additionalObject[key];
}
}
return mergedObject;
};
const safeFunction = fn => typeof fn === 'function' ? fn : x => x;
const out = safeFunction(data.out);
// ===============================================================================
// mergeConcatDeep - Direct mode
// ===============================================================================
const applyCast = (castFn, value) => safeFunction(castFn)(value);
const value = applyCast(data.pre, data.src);
return out(mergeConcatDeep(value, data.add));
// ===============================================================================
// mergeConcatDeep(...) – Apply Mode
// ===============================================================================
/*
return function(baseObject, additionalObject) {
additionalObject = data.rp1 ? additionalObject : data.add;
return out(mergeConcatDeep(baseObject, additionalObject));
};
*/
πŸ§ͺ View Test Scenarios (10 tests)
βœ… '[example] Deep arrays concatenated'
βœ… '[example] Deep non-array override'
βœ… Test adding new properties
βœ… Test empty additional object
βœ… Test array with one empty array
βœ… Test nested objects are recursively merged (deep)
βœ… Test deeply nested objects merged
βœ… Test nested arrays concatenated
βœ… Test additional properties added at all levels
βœ… Test null base returns additional