Handlebars nested 'each' syntax - not iterating over each element

Cronk picture Cronk · Jun 19, 2013 · Viewed 29.9k times · Source

I am brand new at this Javascript/JSON/Handlebars thing, and I am having trouble getting a JSON object, with two nested levels, to work in a Handlebars template.

I have validated the JSON object with JSONLint, so it is valid JSON code, but I don't know if I have the correct JSON format to make the template work correctly. :) (I am building the JSON manually in another system.) Or perhaps it is the syntax of the template that I have incorrect. That's what I hope to find out...

The short description: this object is a table of contents. I have Chapters and then the movies within each Chapter. So the Movies are nested elements of each Chapter element.

I want HTML output similar to:

Chapter1:  ChapterName
       Movie1: MovieName
       Movie2: MovieName
Chapter2:  Chaptername
       Movie1: MovieName
       Movie2: MovieName
       Movie3: MovieName

I seem to end up with only 1 instance of the data (the last element in my JSON object), or I get nothing at all. (Depends on which little tweak or version I try.) The browser console doesn't show any errors.

Here's all the code that I have been trying to use so far (scripts, HTML, template, etc):

<!DOCTYPE html>
<html>
<head>  <meta charset="UTF-8">
    <title>Handlebars Demo</title>
    <!-- dependant files -->
    <script src="Handlebars.js"></script>
</head>

<!-- template -->
<script id="template2" type="text/x-handlebars-template">
    <div>Chapter stuff:</div>
    <ul>{{#each Chapter}}
        <ol>{{@index}} {{ChapterName}}
        {{#each movies}}
            <li>Movie ID:{{movieIDnum}}</li>
        {{/each}}
        </ol>
        {{/each}}
    </ul>
</script>


<body><div id="main"></div></body>

<script>
    var source = document.getElementById('template2').innerHTML;
    var template = Handlebars.compile(source);
    var data = {
        "Chapter" : {
                "ChapterName" : "Introduction",
                "chapterNum" : "1",
                "movies" : [
                        {
                        "movieIDnum" : "16244028",
                        "movieName" : "Update Test Movie 0",
                        "movieFileName" : "Test0.mov",
                        "moviePositionInChapter" : "1"
                        }
                ]
        },

        "Chapter" : {
            "ChapterName" : "Welcome",
            "chapterNum" : "2",
            "movies" : [
                    {
                    "movieIDnum" : " 17322365",
                    "movieName" : "Update Test movie 1",
                    "movieFileName" : "Test1.mov",
                    "moviePositionInChapter" : "1"
                    },
                    {
                    "movieIDnum" : " 17326267",
                    "movieName" : "Update Test movie 3",
                    "movieFileName" : "Test3.mov",
                    "moviePositionInChapter" : "2"
                    }
            ]
        },

        "Chapter" : {
            "ChapterName" : "The new Interface",
            "chapterNum" : "2",
            "movies" : [
                {
                "movieIDnum" : " 1732123476",
                "movieName" : "Update Test movie 12",
                "movieFileName" : "Test12.mov",
                "moviePositionInChapter" : "1"
                },
                {
                "movieIDnum" : " 173262373",
                "movieName" : "Update Test movie 9",
                "movieFileName" : "Test9.mov",
                "moviePositionInChapter" : "2"
                },
                {
                "movieIDnum" : " 173273474",
                "movieName" : "Update Test movie 10",
                "movieFileName" : "Test10.mov",
                "moviePositionInChapter" : "3"
                }
            ]
        },

        "Chapter" : {
            "ChapterName" : "What is an Update?",
            "chapterNum" : "4",
            "movies" : [
                {
                "movieIDnum" : " 177342131",
                "chapterNum" : "4",
                "chapterName" : "What is an Update?",
                "movieName" : "Test movie again",
                "movieFileName" : "Test13.mov",
                "moviePositionInChapter" : "1"
                }
                ]
                },
        "Chapter" : {
            "ChapterName" : "Editing",
            "chapterNum" : "5",
            "movies" : [
                {
                "movieIDnum" : " 173290878",
                "movieName" : "Update Test movie 14",
                "movieFileName" : "Test14mov",
                "moviePositionInChapter" : "1"
                },
                {
                "movieIDnum" : " 177344914",
                "movieName" : " Movie 15 Test",
                "movieFileName" : "Test233.mov",
                "moviePositionInChapter" : "2"
                }
            ]
        }

    }

    var result = template(data);
    document.write(result);

</script>
</html>

I would like to know why THIS doesn't work, not just a "Here's how to solve your problem using 4 other different things in a totally different format". It is my understanding that this SHOULD be workable with the tools I am trying to use. I would like to better understand these tools and learn from the process, not just get a solution. (You know, teach a man to fish... :) )

Thanks, J

Answer

pdjota picture pdjota · Jun 19, 2013

There are a couple of changes to suggest, first you shouldn't write an object with several keys { Chapter:, Chapter:, etc...}

The other suggestion is to review the way Handlebars works, it doesn't need each in every case. Hope it clarifies.

Try these changes:

<!DOCTYPE html>
<html>
<head>  <meta charset="UTF-8">
    <title>Handlebars Demo</title>
    <!-- dependant files -->
    <script src="handlebars.js"></script>
</head>

<!-- template -->
<script id="template2" type="text/x-handlebars-template">
    <div>Chapter stuff:</div>
    <ul>{{#Chapters}}
        <ol>{{@index}} {{ChapterName}}
        {{#movies}}
            <li>Movie ID:{{movieIDnum}}</li>
        {{/movies}}
        </ol>
        {{/Chapters}}
    </ul>
</script>


<body><div id="main"></div></body>

<script>
    var source = document.getElementById('template2').innerHTML;
    var template = Handlebars.compile(source);
    var data = [
        {
                "ChapterName" : "Introduction",
                "chapterNum" : "1",
                "movies" : [
                        {
                        "movieIDnum" : "16244028",
                        "movieName" : "Update Test Movie 0",
                        "movieFileName" : "Test0.mov",
                        "moviePositionInChapter" : "1"
                        }
                ]
        },
        {
            "ChapterName" : "Welcome",
            "chapterNum" : "2",
            "movies" : [
                    {
                    "movieIDnum" : " 17322365",
                    "movieName" : "Update Test movie 1",
                    "movieFileName" : "Test1.mov",
                    "moviePositionInChapter" : "1"
                    },
                    {
                    "movieIDnum" : " 17326267",
                    "movieName" : "Update Test movie 3",
                    "movieFileName" : "Test3.mov",
                    "moviePositionInChapter" : "2"
                    }
            ]
        },
        {
            "ChapterName" : "The new Interface",
            "chapterNum" : "2",
            "movies" : [
                {
                "movieIDnum" : " 1732123476",
                "movieName" : "Update Test movie 12",
                "movieFileName" : "Test12.mov",
                "moviePositionInChapter" : "1"
                },
                {
                "movieIDnum" : " 173262373",
                "movieName" : "Update Test movie 9",
                "movieFileName" : "Test9.mov",
                "moviePositionInChapter" : "2"
                },
                {
                "movieIDnum" : " 173273474",
                "movieName" : "Update Test movie 10",
                "movieFileName" : "Test10.mov",
                "moviePositionInChapter" : "3"
                }
            ]
        },
        {
            "ChapterName" : "What is an Update?",
            "chapterNum" : "4",
            "movies" : [
                {
                "movieIDnum" : " 177342131",
                "chapterNum" : "4",
                "chapterName" : "What is an Update?",
                "movieName" : "Test movie again",
                "movieFileName" : "Test13.mov",
                "moviePositionInChapter" : "1"
                }
                ]
        },
        {
            "ChapterName" : "Editing",
            "chapterNum" : "5",
            "movies" : [
                {
                "movieIDnum" : " 173290878",
                "movieName" : "Update Test movie 14",
                "movieFileName" : "Test14mov",
                "moviePositionInChapter" : "1"
                },
                {
                "movieIDnum" : " 177344914",
                "movieName" : " Movie 15 Test",
                "movieFileName" : "Test233.mov",
                "moviePositionInChapter" : "2"
                }
            ]
        }
    ];

    var result = template({Chapters: data});
    document.write(result);

</script>
</html>