Intended output: { children: { Display: { children: { … value: 2 } } } }

Real output: { children: {}, Display: {}, … value: 2 }


Code:

// Load default settings
let defaultSettings;

load("/assets/json/default-settings.json", 'json', function(defset) {
	defaultSettings = defset;

	// Create custom settings
	if(!Object.keys(localStorage).includes('settings')) {
		setLs('settings', JSON.stringify({}));
	};

	customiseSetting('Display/UI/Distance', 2)
});

function settingURL(url) {
	return('children/' + url.split('/').join('/children/') + '/value');
}

function customiseSetting(url, value) {
	url = settingURL(url);

	// Split the string by '/' and use reduce to access the nested properties
	const newSettings = url.split('/').reduce(function(accumulator, val, index, array) {
		// If the object does not have the current component as a property, create an empty object for it
	  	// If the current component is the last one, assign the value
	  	if (index == array.length - 1) {
			accumulator[val] = value;
	  	} else if (!accumulator.hasOwnProperty(val)) {
			accumulator[val] = {}; // update the accumulator object
		}

		log([accumulator, val, index, array])
		// Return the updated object
	  	return(accumulator);
	}, JSON.parse(ls('settings')));
	log(newSettings);
	setLs('settings', JSON.stringify(newSettings));
}

I’ve been trying unsuccessfully for several days to fix to what must be a simple error. I’ve looked over it myself, but I can’t find the cause of the bug. I asked Bing, which usually helps, but it was unhelpful. So I’m sorry to be bothering you, but if you could help me solve this problem, I would really appreciate it.

EDIT: I fixed my code by using a recursive function as follows:

function customiseSetting(url, value) {
	url = settingURL(url).split('/');

	let newSettings;

	function recursiveSet(object, list, index, setTo) {
		// If the current component is the last one, assign the value
		if(index == list.length - 1) {
			object[list[index]] = setTo;
			return(object);
		} else {
			// Check if it already contains the value
			if(object.hasOwnProperty(list[index])) {
				object[list[index]] = recursiveSet(object[list[index]], list, index + 1, setTo);
			} else {
				object[list[index]] = recursiveSet({}, list, index + 1, setTo);
			}
			return(object);
		}
	};

	newSettings = recursiveSet(JSON.parse(ls('settings')), url, 0, value);

	log(newSettings);
	setLs('settings', JSON.stringify(newSettings));
}
  • @sleep_deprived
    link
    610 months ago

    The issue is that, in the function passed to reduce, you’re adding each object directly to the accumulator rather than to its intended parent. These are the problem lines:

    if (index == array.length - 1) {
    	accumulator[val] = value;
    } else if (!accumulator.hasOwnProperty(val)) {
    	accumulator[val] = {}; // update the accumulator object
    }
    

    There’s no pretty way (that I can think of at least) to do what you want using methods like reduce in vanilla JS, so I’d suggest using a for loop instead - especially if you’re new to programming. Something along these lines (not written to be actual code, just to give you an idea):

    let curr = settings;
    const split = url.split("/");
    for (let i = 0; i < split.length: i++) {
        const val = split[i];
        if (i != split.length-1) {
            //add a check to see if curr[val] exists
            let next = {};
            curr[val] = next;
            curr = next;
        }
        //add else branch
    }
    

    It’s missing some things, but the important part is there - every time we move one level deeper in the URL, we update curr so that we keep our place instead of always adding to the top level.

    • JackGreenEarthOP
      link
      fedilink
      English
      110 months ago

      I fixed my code by using a recursive function as follows:

      function customiseSetting(url, value) {
      	url = settingURL(url).split('/');
      
      	let newSettings;
      
      	function recursiveSet(object, list, index, setTo) {
      		// If the current component is the last one, assign the value
      		if(index == list.length - 1) {
      			object[list[index]] = setTo;
      			return(object);
      		} else {
      			// Check if it already contains the value
      			if(object.hasOwnProperty(list[index])) {
      				object[list[index]] = recursiveSet(object[list[index]], list, index + 1, setTo);
      			} else {
      				object[list[index]] = recursiveSet({}, list, index + 1, setTo);
      			}
      			return(object);
      		}
      	};
      
      	newSettings = recursiveSet(JSON.parse(ls('settings')), url, 0, value);
      
      	log(newSettings);
      	setLs('settings', JSON.stringify(newSettings));
      }