Skip Navigation

Can you help me with my JavaScript issue?

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

You're viewing a single thread.

11 comments
  • 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.

    • 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));
      }
      
    • What does i < mean in line 3 of your answer?

11 comments