0

I have an HTML page that contains questions and answers. I want to extract the data (questions/answers) from the HTML page and put it in a JavaScript object.

This is the class structure in my HTML page:

  • question-block
    • question (only 1 question per question block)
    • answer (multiple answers possible per question)

This is my HTML code with the structure:

<div class="question-block">
    <h3>Question 1</h3>
    <label class="question">Name</label>
    <input type="text" class="answer" />

    <div class="question-block" style="margin-left:20px;">
        <h4>Question 1 a</h4>
        <label class="question">What is your gender?</label>
        <div class="radio">
            <input type="radio" class="answer" name="gender" id="radio-male" value="male">
            <label for="radio-male">Male</label>
        </div>
        <div class="radio">
            <input type="radio" class="answer" name="gender" id="radio-female" value="female">
            <label for="radio-female">Female</label>
        </div>
    </div>
</div>

<div class="question-block">
    <h3>Question 2</h3>
    <label class="question">Occupation</label>
    <input type="text" class="answer" />
</div>
<br />

<button id="extract" type="button">Extract HTML data</button>

<pre id="extract-div"></pre>

I want to create a object structure in JavaScript like this:

{
    "questions": [
        {
            "question": "Name",
            "answers": [
                {
                    "answer": "Kristof"
                }
            ]
        },
        {
            "question": "What is your gender?",
            "answers": [
                {
                    "answer": "Male"
                }
            ]
        },
        {
            "question": "Occupation",
            "answers": [
                {
                    "answer": "Student"
                }
            ]
        }
    ]
}

Everything works, except for the nested "question-block" (1a. What is your gender?). The answer of this question is also added to question 1.

How can I select only the answers that are located in the current "question-block" class with JavaScript or JQlite (I'm using angular).

It should be possible to nest my "question-block" classes multiple levels deep. (not only 1 level like in the example)


If you want to test it or check out my JavaScript code, here is my fiddle: https://jsfiddle.net/aywxte23/

4
  • Flipping this round completely, a longer term approach to this would be to already have this structure defined in JavaScript, then use a templating system to generate the HTML. Using something like KnockoutJS or Angular would also allow dynamic updating of the values in the JavaScript when they change in the UI. Commented Dec 30, 2015 at 13:26
  • 1
    If you can change the name attribute values, you could use a JavaScript library I created called Reaper, which grabs all the input, textarea and select elements inside a given element and creates a JavaScript object using the form field name attributes as a guide to the object property names and data types. Commented Dec 30, 2015 at 13:32
  • @JamesThorpe I use AngularJS and I thought of that, but they provided us the output object structure after I created everything. It's a lot of refactoring for me to map this structure with my UI. And the budget doesn't always allow that :) Commented Dec 30, 2015 at 13:47
  • @GregBurghardt Thanks for your library. I will give it a shot! Commented Dec 30, 2015 at 13:49

1 Answer 1

2

I don't usually like posting answers that tout some JavaScript library that I wrote, but it seems appropriate in this case, because I don't see any indication you are using outside libraries or frameworks.

Reaper is a small JavaScript class I wrote with no dependencies that will create a deeply nested object from the form field names.

You could adapt this to your existing user interface, even with using AngularJS, by simply changing the name attribute values in the form fields:

<div id="some-common-parent-element-or-form">
    <div class="question-block">
        <h3>Question 1</h3>
        <label class="question">Name</label>
        <input type="text" class="answer" name="questions[0][answers][0][answer]" />
        <input type="hidden" name="questions[0][question]" value="Name" />

        <div class="question-block" style="margin-left:20px;">
            <h4>Question 1 a</h4>
            <label class="question">What is your gender?</label>
            <input type="hidden" name="questions[1][question]" value="What is your gender?" />
            <div class="radio">
                <input type="radio" class="questions[1][answers][0][answer]" name="gender" id="radio-male" value="male">
                <label for="radio-male">Male</label>
            </div>
            <div class="radio">
                <input type="radio" class="questions[1][answers][0][answer]" name="gender" id="radio-female" value="female">
                <label for="radio-female">Female</label>
            </div>
        </div>
    </div>

    <div class="question-block">
        <h3>Question 2</h3>
        <label class="question">Why do hotdogs come in packages of 10, but hotdog buns come in packages of 8?</label>
        <input type="text" class="answer" name="questions[2][answers][0][answer]" />
        <input type="hidden" name="questions[2][question]" value="Why do hotdogs come in packages of 10, but hotdog buns come in packages of 8?" />
    </div>
</div>

<button id="extract" type="button">Extract HTML data</button>

<pre id="extract-div"></pre>

<script type="text/javascript" src="/path/to/reaper.js"></script>

And the JavaScript to get it working:

var extractor = new Reaper(),
    data = null,
    element = document.getElementById("some-common-parent-element-or-form");

extractor.flat = false;
data = extractor.getData(element);

This should give you the data structure you are looking for.

Sign up to request clarification or add additional context in comments.

4 Comments

How do you avoid setting the questions numbers manually? (questions[0][answers][0]How to Answer) If I add a question in between, I don't want to update every name..
If you generate the HTML using some sort of templating language, whether on the client or the server, you will need to use the index of the current question and index of the current answer. If you are stuck hard coding the HTML, you are stuck hard coding the indices.
Maybe we can add labels to your library? Then we can avoid the duplicate questions or hidden input values..
Nice library. That works really well. I'd like to contribute to it. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.