Display a linear list organized in a tree format, showcasing instances where children have multiple parents

I am new to Javascript and programming in general. I am working with a list of "step" objects that have a choice/solution field which references another object in the same list. My goal is to create a tree hierarchy based on this field.

[ Below is the array file that I want to restructure into a tree :

$scope.nodes = {
  "story": {
    "step" : [
      {
        "title": "Begin",
        "id": "0",
        "type": "MultipleChoice",
        "description": "Starting point of the adventure.",
        "choice": [
          {
          "nextStepId": "1",
          "#text": "Born as a troll, tough luck."
        }]
      },
      {
        "title": "Choice",
        "id": "1",
        "type": "MultipleChoice",
        "description": "Time to take control of your life.",
          "choice": [
        {
          "nextStepId": "1001",
          "#text": "Take an apple"
        },
        {
          "nextStepId": "4",
          "#text": "Suicide"
        },
        {
          "nextStepId": "1001",
          "#text": "Use a coin to decide"
        }
        ]
      },
      {
        "title": "Riddle",
        "id": "4",
        "type": "Riddle",
        "description": "Best way to end it all?",
        "solution": {
        "nextStep": "1000",
          "#text": "think"
        }
      },
      {
        "title": "you are dead",
        "id": "1000",
        "type": "End",
        "win": "true",
        "description": "Rest in peace."
      },
      {
        "title": "you are alive",
        "id": "1001",
        "type": "End",
        "win": "false",
        "description": "You survived."

      }
    ]
}
}

My progress so far :

$scope.tree = function tree() {
  var map = {}, node, roots = [];
  for (var i = 0; i < nodes.length; i += 1) {
    node = nodes.story.step[i];
    map[node.id] = i;
    if (node.id !== "0") {
      switch (node.type) {
        case ("MultipleChoice"):
          for (var j = 0; i < node.choice.length; j += 1)
          nodes[map[node.id]].choice[j].nextStepId[j].push(node);
          break;
        case ("Riddle"):
          nodes[map[node.id]].solution.nextStep[j].push(node);
          break;
        case ("End"):
        //TO DO
      }
    }
    else {
      roots.push(node);
    }
  }
}(nodes)

(Note: A child can have multiple parents, and 'choice' may contain an array or single element.)

It seems like there's an issue with the 'choice' being undefined.

I would appreciate any guidance on correcting my code. I prefer to learn from my mistakes but open to suggestions.

Thank you!

Answer №1

My approach to coding this would be different. I find that utilizing the ng-switch directive is quite beneficial in this scenario. This way, you can store the current step in a variable and determine within the ng-switch block what content should be displayed (such as multiple choices, a riddle, or an end message).

If you wish to prevent users from cheating, it's essential to perform solution validation on the server-side since the model data is accessible via the browser console, allowing users to peek at the correct answer before making a selection.

The only aspect of your application that seems unclear to me is the 'riddle' question. It appears that this might not align with your intended design, but it should be relatively straightforward to make adjustments as needed.

Please take a look at the demo provided below or visit this JSFiddle link for further exploration.

angular.module('demoApp', [])
    .controller('mainCtrl', MainCtrl);

function MainCtrl($scope) {
var vm = this;
    
    // Data structure containing the story nodes
    var nodes = {
        "story": {
            "step": [{
                "title": "Begin",
                "id": "0",
                "type": "MultipleChoice",
                "description": "Embark on the adventurous journey from the beginning!",
                "choice": [{
                    "nextStepId": "1",
                    "#text": "You were born as a troll, tough luck! :'("
                }]
            }, {
                "title": "Choice",
                "id": "1",
                "type": "MultipleChoice",
                "description": "It's time to reclaim control over your life and make a decision!",
                "choice": [{ 
                    "nextStepId": "1001",
                    "#text": "Take an apple"
                }, {
                    "nextStepId": "4",
                    "#text": "Suicide"
                }, {
                    "nextStepId": "1001",
                    "#text": "Use a coin to decide"
                }]
            }, {
                "title": "Riddle",
                "id": "4",
                "type": "Riddle",
                "description": "What is the optimal method for suicide?",
                "solution": {
                    "nextStepId": "1000",
                    "#text": "think"
                }
            }, {
                "title": "Game Over",
                "id": "1000",
                "type": "End",
                "win": true,
                "description": "Congratulations, you have met your demise!"
            }, {
                "title": "Survival",
                "id": "1001",
                "type": "End",
                "win": false,
                "description": "Well, looks like you're still alive!"

            }]
        }
    };

// Function to retrieve node by ID
function getById(id) {
    var node;
        for(var i=0; i<nodes.story.step.length; i++) {
        node = nodes.story.step[i];
            if ( node.id === id ) {
            return node;
            }
        }
    }

// Controller properties and methods
angular.extend(vm, {
    nodes: nodes,
        curStep: nodes.story.step[0],
        next: function(id) {
        vm.curStep = getById(id);
        }
    });
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainCtrl as ctrl">
    <div>
        {{ctrl.curStep.description}}
        <div ng-switch="ctrl.curStep.type">
            <div ng-switch-when="MultipleChoice">
                <div ng-repeat="choice in ctrl.curStep.choice">
                    <button ng-click="ctrl.next(choice.nextStepId)">
                    {{choice['#text']}}
                    </button>
                </div>
            </div>
            <div ng-switch-when="Riddle">
                <a href="#" ng-click="ctrl.next(ctrl.curStep.solution.nextStepId)">{{ctrl.curStep.solution['#text']}}</a>
        </div>
        <div ng-switch-when="End">
            Game Over! <strong>{{ctrl.curStep.win ? 'You\'ve won!': 'You\'ve lost'}}</strong>
        </div>
    </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating an HTML button that will execute JavaScript code when clicked

My goal is to create a button that, when clicked, updates the background of another div. These buttons are dynamically generated using PHP from images in a folder. <!DOCTYPE html> <html> <head> <meta charset="UTF-8> <scr ...

Error in Next.js: .env variable not defined

I recently transitioned my project from React to Next.js and encountered an issue where my environment variables are showing as undefined, even though they were functioning correctly in React. Can someone provide some guidance or assistance with this probl ...

Struggling with integrating Skybox in THREE.js

My console is not showing any errors. I am utilizing the live server VS code extension to execute the JS code. Can someone please assist me?" HTML: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"& ...

Emphasize a thumbnail by decorating it when selected in the gallery display page

I have created a gallery.php file with the following code: <div id="galleryImage"> <ul> <li> <a href= "gallery.php?imgName='artistvan'"> <img src="thumbnail/artistvan.jpg" ti ...

Unable to retrieve the value property from document.getElementById as it is null

Can someone help me with reading the input field value in my code? <input type="text" name="acadp_fields[1200]" class="text" placeholder="" value="December 26, 1969"> Here is the code snippet I am us ...

The Javascript array does not function like a typical array

I am currently facing a perplexing issue while working with the Twitter API. Below is the script causing the confusion: const Twitter = require('twitter-api-stream') const twitterCredentials = require('./credentials').twitter const t ...

The Angular model finally refreshes its values after a console.log() is executed

UPDATE After further investigation, I discovered that the issue was not related to Angular itself, but rather a mistake in the update function within the node server controller. I have provided the fix below for reference, and decided to keep this questio ...

What are some techniques for monitoring an Angular promise chain with Jasmine?

Incorporating AngularJS, CoffeeScript, and Jasmine within WebStorm, my goal is to conduct unit testing on a chain of promises. Imagine having the subsequent example service: Angular Service class ExampleService stepData: [] constructor: (@$http) ...

The jspdf function is not displaying any images in the PDF file

I am new to coding and encountered an issue when trying to download images in reactjs. After clicking the download button, I only receive a blank pdf file. https://i.stack.imgur.com/0XJcC.png The function in my react code that attempts to generate the p ...

Contemplate and send an Axios request directly from the browser's URL bar

Seeking JavaScript Logic Assistance I could use some guidance on implementing JavaScript logic, specifically with Vue Router. I don't necessarily need the answer handed to me, just a nudge in the right direction (and apologies if my question is not q ...

React does not recognize data.map as a function

Currently, I am facing an issue with a simple map function in React that is supposed to create a set amount of times. {times.map((time) => ( <Pill value={time} handleTimes={handleTimes} key={time} /> ))} The error being thrown i ...

Is there a way to prevent SignalR from disconnecting when the settings window is moved?

I am currently developing a webpage that utilizes SignalR events to trigger ajax requests to our servers. These requests return a URL with a custom URI scheme that, when accessed, opens up a specific program on the client's device without leaving the ...

Tips for troubleshooting issues with Radio input and ng-repeat functionality in Angular JS

Below is the code in my controller file: 'use strict' angular.module('app.maps.ctrls', []) .controller('radCtrl', [ '$scope', ($scope) -> $scope.radio=[ {value:1,select:true}, { ...

Display picture on webpage in 10 seconds

Hi, I'm working on a website project and I've run into an issue where I need to use JavaScript, but I haven't mastered it yet. I have a background image slideshow set up where a new image appears every 6 seconds. My idea is to have the sec ...

sending object value to directive rather than other data variables

I have been attempting to customize the functionality of this functioning http://jsfiddle.net/markcoleman/JNqqU/. In the current fiddle, the object is directly assigned where I am trying to change it to $scope.obj.items. However, passing the object to the ...

"Enhancing User Experience: Harnessing the Power of jQuery Load and jQuery Tabs for Seamless

Currently, I am working with jQuery Tabs and implementing the loading of tab pages through the tabsbeforeactivate event in order to utilize Ajax and only load contents when necessary. However, I am encountering challenges as I have to manually activate Un ...

What is the best way to trigger UseEffect when new data is received in a material table?

I was facing an issue with calling a function in the material table (https://github.com/mbrn/material-table) when new data is received. I attempted to solve it using the following code. useEffect(() => { console.log(ref.current.state.data); ...

It appears that the JavaScript global dynamic variable is undefined as it changes from function to function, suggesting it might be

I'm encountering an issue with the way these two functions interact when used in onclick calls of elements. Due to external circumstances beyond my control, I need to keep track of when and how elements are hidden. Everything works perfectly as inten ...

React is throwing an error message stating that setCount is not a valid function

Getting an error saying setCount is not a function. I am new to this, please help. import React, { memo, useState } from "react"; export const Container = memo(function Container() { const { count, setCount } = useState(0); return ( ...

Creating interactive rows in a table using AngularJS

I am looking to automatically populate rows in table 2 based on the count value from table 1. Table 1 has a field called count which determines how many rows should be displayed in table 2. I am just starting out with AngularJS, so any guidance on how to ...