Mustache is replacing my tags with empty strings

- 1 answer

Ad

The Problem

(Since posting this, I've gotten a little closer to solving it, but I'm still stuck. Please check the update at the end of the question).

I have a site that's been template using Mustache.js. When the site is run locally, it works fine. The templates are loaded, Mustache replaces the mustache tags with the given data, and the page renders as expected.

When the site is run from my (school) server however, it develops an odd issue. For whatever reason, Mustache.render is replacing all the mustache tags in my template with nothing (as in empty strings). Obviously, this is causing my site to load very wrong.

What I've Tried To Diagnose It

Using console logging, I tracked the loaded templates, and what Mustache produces. The results are below:

The data to plug into the templates (siteData.json):

{
  "headerClasses":              "mainHeader",
  "headerTitle":                "Uromastyces Fact Site",

  "sideBarClasses":             "mainSideBar",
  "sideBarImgClasses":          "sideBarImage",
  "sideBarImgAlt":              "A Picture of Pascal",
  "sideBarImgSrc":              "../images/pascal-cropped-shrunk.jpg",

  "navBarClassNames":           "navBar",
  "navLinks":                   [
                                    {
                                        "name":     "Home",
                                        "link":     "index.html"
                                    }, {
                                        "name":     "Enclosure",
                                        "link":     "enclosure.html"
                                    }, {
                                        "name":     "Diet",
                                        "link":     "diet.html"
                                    }, {
                                        "name":     "Behavior and Life",
                                        "link":     "behaviorAndLife.html"
                                    }, {
                                        "name":     "About Me",
                                        "link":     "aboutMe.html"
                                    }
                                ],

  "uniqueBodyClasses":          "uniqueBody",
  "uniqueBodyContent":          "DEFAULT UNIQUE BODY",

  "footerClasses":              "mainFooter",
  "authorWrapperClasses":       "footerAuthor footerWrapper",
  "dateModifiedWrapperClasses": "footerModified footerWrapper",

  "authorName":                 "Brendon Williams",
  "lastModifiedDate":           "DEFAULT LAST MODIFIED DATE",

  "indexNavBarClasses":         "indexNavBar"
}

Body Template (BodyTemplate.mustache):

<header class="{{headerClasses}}">
    <h1>
        {{headerTitle}}
    </h1>
</header>

<aside class="{{sideBarClasses}}">
    <img class="{{sideBarImgClasses}}" src="{{sideBarImgSrc}}" alt="{{sideBarImgAlt}}">
    <nav class="{{navBarClassNames}}">
        <ul>
            {{#navLinks}}
                <li><a href="{{link}}" tabindex="1">{{name}}</a></li>
            {{/navLinks}}
        </ul>
    </nav>
</aside>

<section class="{{uniqueBodyClasses}}">
    <div id="indexDiv">
        <div id="indexContents"></div>
    </div>
    {{> uniqueBodyContent}}
</section>

<footer class="{{footerClasses}}">
    <span class="{{authorWrapperClasses}}">
        Author: {{authorName}}
    </span>

    <span class="{{dateModifiedWrapperClasses}}">
        Last Modified: {{> lastModifiedDate}}
    </span>
</footer>

<script src="./js/Indexer.js"></script>

Here's where it differs. After running the above files through Mustache.render locally, here are the results:

<header class="mainHeader">
    <h1>
        Uromastyces Fact Site
    </h1>
</header>

<aside class="mainSideBar">
    <img class="sideBarImage" src="..&#x2F;images&#x2F;pascal-cropped-shrunk.jpg" alt="A Picture of Pascal">
    <nav class="navBar">
        <ul>
                <li><a href="index.html" tabindex="1">Home</a></li>
                <li><a href="enclosure.html" tabindex="1">Enclosure</a></li>
                <li><a href="diet.html" tabindex="1">Diet</a></li>
                <li><a href="behaviorAndLife.html" tabindex="1">Behavior and Life</a></li>
                <li><a href="aboutMe.html" tabindex="1">About Me</a></li>
        </ul>
    </nav>
</aside>

<section class="uniqueBody">
    <div id="indexDiv">
        <div id="indexContents"></div>
    </div>

        <h4>Introduction</h4>
        <h5>Hi...</h5>
        <p>
            I created this site to...
        </p>
        <p>
            ...
        </p>
        <p>
            ...
        </p>

        <h4>Contact Me</h4>
        <p>
            Want to send me a message? Use the form below:
        </p>
        <form enctype="text/plain" method="post" action="mailto:[email protected]">
            <label class="contactLabel">Subject:</label>
            <input class="contactInput" type="text" name="subject">

            <label class="contactLabel">Body:</label>
            <input class="contactInput" type="text" name="body">

            <input type="submit" name="submit" value="Submit">
        </form>

    </section>

<footer class="mainFooter">
    <span class="footerAuthor footerWrapper">
        Author: Brendon Williams
    </span>

    <span class="footerModified footerWrapper">
        Last Modified: 15.12.26
    </span>
</footer>

<script src="./js/Indexer.js"></script>

Exactly as I'd expect. All the mustache tags were removed, and replaced with the corresponding data from the JSON

However, here's the results when run from my school's server (The exact same code):

<header class="">
    <h1>
        
    </h1>
</header>

<aside class="">
    <img class="" src="" alt="">
    <nav class="">
        <ul>
        </ul>
    </nav>
</aside>

<section class="">
    <div id="indexDiv">
        <div id="indexContents"></div>
    </div>

        <h4>Introduction</h4>
        <h5>Hi...</h5>
        <p>
            I created this site to...
        </p>
        <p>
            ...
        </p>
        <p>
            ...
        </p>

        <h4>Contact Me</h4>
        <p>
            Want to send me a message? Use the form below:
        </p>
        <form enctype="text/plain" method="post" action="mailto:[email protected]">
            <label class="contactLabel">Subject:</label>
            <input class="contactInput" type="text" name="subject">

            <label class="contactLabel">Body:</label>
            <input class="contactInput" type="text" name="body">

            <input type="submit" name="submit" value="Submit">
        </form>

    </section>

<footer class="">
    <span class="">
        Author: 
    </span>

    <span class="">
        Last Modified: 15.12.26
    </span>
</footer>

<script src="./js/Indexer.js"></script>

Notice how all of the mustache tags were simply removed instead of being replaced by the data.

I know everything is being downloaded fine, so it's not a path issue:

enter image description here

While I've been using mustache for about a week, I have no idea how to diagnose a problem like this. The above snippets were the result of console logging, so I've verified the input going into Mustache.render, and it all checks out. And again, this only happens when it's hosted remotely.

Here's my rendering module (templateLoader.js) (The chunk of console logs in the middle of renderPage is the source of the above snippets via the Developer Cosole):

var TemplateLoader = {
    /**
     * Draws the templated page, along with the given unique body.
     *
     * @param {string|Node} uniqueBodyElement Data representing the unique body to display. Should either be a string
     * of HTML, or a DOM element containing the HTML.
     * @param {string} lastModifiedDate The date that the page was last modified.
     */
    renderPage: function(uniqueBodyElement, lastModifiedDate) {
        var data;
        var headTemplate;
        var bodyTemplate;
        var articleTemplate;

        //Wait until all data is available
        $.when(
                $.get("./templates/siteData.json", function(d){ data = d }),
                $.get("./templates/HeadTemplate.mustache", function(hT){ headTemplate = hT }),
                $.get("./templates/BodyTemplate.mustache", function(bT){ bodyTemplate = bT }),
                $.get("./templates/ArticleTemplate.mustache", function(aT){ articleTemplate = aT })

        ).done(function() {
            Helpers.doWithMustache(function() {
                var partial = TemplateLoader.getTemplatePartial(uniqueBodyElement);
                partial.lastModifiedDate = lastModifiedDate;

                var renderedHead = Mustache.render(headTemplate, data);
                var renderedBody = Mustache.render(bodyTemplate, data, partial);

                var renderedArticleBody = Mustache.render(articleTemplate, {}, { articleBody: renderedBody });

                console.group();
                console.log("Data: \n" + data);
                console.log("Body Template: \n" + bodyTemplate);
                console.log("Article Template: \n" + articleTemplate);
                console.log("Rendered Body: \n" + renderedBody);
                console.log("Rendered Article Body: \n" + renderedArticleBody);
                console.groupEnd();

                $('head').append(renderedHead);
                $('body').html(renderedArticleBody);

                console.log("Templates Loaded.");
            });

        }).fail(function() {
            console.error("Failed to fetch templates or site data.")
        });

    },

    getTemplatePartial: function(templateData) {
        var uniqueBodyString;

        if (typeof templateData === "string") {
            uniqueBodyString = templateData

        } else {
            uniqueBodyString = templateData.innerHTML;
        }

        return {
            uniqueBodyContent: uniqueBodyString
        };
    }

};

var Helpers = {
    doWithMustache: function(f) {
        $.getScript("./js/mustache.min.js", function() {
            f();

        }).fail(function() {
            console.error("Failed to fetch mustache script.")
        });
    }
};

And here's the full results of the log:

Data: 
{
  "headerClasses":              "mainHeader",
  headerTitle:              "Uromastyces Fact Site",

  "sideBarClasses":             "mainSideBar",
  "sideBarImgClasses":          "sideBarImage",
  "sideBarImgAlt":              "A Picture of Pascal",
  "sideBarImgSrc":              "../images/pascal-cropped-shrunk.jpg",

  "navBarClassNames":           "navBar",
  "navLinks":                   [
                                    {
                                        "name":     "Home",
                                        "link":     "index.html"
                                    }, {
                                        "name":     "Enclosure",
                                        "link":     "enclosure.html"
                                    }, {
                                        "name":     "Diet",
                                        "link":     "diet.html"
                                    }, {
                                        "name":     "Behavior and Life",
                                        "link":     "behaviorAndLife.html"
                                    }, {
                                        "name":     "About Me",
                                        "link":     "aboutMe.html"
                                    }
                                ],

  "uniqueBodyClasses":          "uniqueBody",
  "uniqueBodyContent":          "DEFAULT UNIQUE BODY",

  "footerClasses":              "mainFooter",
  "authorWrapperClasses":       "footerAuthor footerWrapper",
  "dateModifiedWrapperClasses": "footerModified footerWrapper",

  "authorName":                 "Brendon Williams",
  "lastModifiedDate":           "DEFAULT LAST MODIFIED DATE",

  "indexNavBarClasses":         "indexNavBar"
}
templateLoader.js (41,14)

Body Template: 
<header class="{{headerClasses}}">
    <h1>
        {{headerTitle}}
    </h1>
</header>

<aside class="{{sideBarClasses}}">
    <img class="{{sideBarImgClasses}}" src="{{sideBarImgSrc}}" alt="{{sideBarImgAlt}}">
    <nav class="{{navBarClassNames}}">
        <ul>
            {{#navLinks}}
                <li><a href="{{link}}" tabindex="1">{{name}}</a></li>
            {{/navLinks}}
        </ul>
    </nav>
</aside>

<section class="{{uniqueBodyClasses}}">
    <div id="indexDiv">
        <div id="indexContents"></div>
    </div>
    {{> uniqueBodyContent}}
</section>

<footer class="{{footerClasses}}">
    <span class="{{authorWrapperClasses}}">
        Author: {{authorName}}
    </span>

    <span class="{{dateModifiedWrapperClasses}}">
        Last Modified: {{> lastModifiedDate}}
    </span>
</footer>

<script src="./js/Indexer.js"></script>
templateLoader.js (42,14)

Article Template: 
<section>
    {{> articleBody}}
</section>
templateLoader.js (43,14)

Article Template: 
<section>
    {{> articleBody}}
</section>
templateLoader.js (43,14)

Rendered Article Body: 
<section>
<header class="">
    <h1>
        
    </h1>
</header>

<aside class="">
    <img class="" src="" alt="">
    <nav class="">
        <ul>
        </ul>
    </nav>
</aside>

<section class="">
    <div id="indexDiv">
        <div id="indexContents"></div>
    </div>

        <h4>Introduction</h4>
        <h5>Hi, I'm Brendon, and I'm a long-time reptile and Uromastyx owner.</h5>
        <p>
            I created this site to act as a centralized collection of facts on Uromastyces. The conditions that Uromastyces should be housed in are quite different than most other reptiles, so it can be confusing to new owners as to what the correct conditions are, and what they can be fed.
        </p>
        <p>
            To the best of my ability, I will reference external sites and provide links to the original information. Note though that new information about Uromastyces may come to light after the publication of this site, so I can't guarantee that this information will forever remain in-date, and that contradictory information won't appear later; although I'll do my best to evaluate all of the sources I use.
        </p>
        <p>
            In the top-left of every page is my current Uromastyx, <em>Pascal</em>. She was injured in-transit on the way to my Dad's wholesale warehouse (her right eye was damaged) and was deemed unsellable, so I adopted her to ensure that she can still live a long-life. Besides her lack-of a left eye, she's so healthy, you'd never know that she's injured (except when she
            walks in circles looking for food).
        </p>

        <h4>Contact Me</h4>
        <p>
            Want to send me a message? Use the form below:
        </p>
        <form enctype="text/plain" method="post" action="mailto:[email protected]">
            <label class="contactLabel">Subject:</label>
            <input class="contactInput" type="text" name="subject">

            <label class="contactLabel">Body:</label>
            <input class="contactInput" type="text" name="body">

            <input type="submit" name="submit" value="Submit">
        </form>

    </section>

<footer class="">
    <span class="">
        Author: 
    </span>

    <span class="">
        Last Modified: 15.12.26
    </span>
</footer>

<script src="./js/Indexer.js"></script></section>
templateLoader.js (45,14)

Templates Loaded.
templateLoader.js (51,14)

Any guidance at all here would be appreciated.

Update:

So, while debugging it, I found out the potential source of the problem, but have no idea how to resolve it. When debugging it locally, the data object (inside renderPage) is interpreted by Edge as a JS object, and lists each of its attributes. When it's remote however, the data object is being interpreted as a String (local is on the left, remote on the right):

enter image description here

So, the issue seems to be that the data.json isn't being read properly on the server side.

I should note that locally, I'm using Windows, but the school server is "Apache/2.2.3 (Red Hat)" (according to Edge's Network tab). I changed the returns from \r\n to \n to adhere to Unix standards, but it didn't change anything.

I've run the JSON file through all of the top JSON validators, and it checks out in all of them, so it doesn't seem to be a formatting issue.

Ad

Answer

Ad

It looks like you're not parsing JSON data from the AJAX response. The document is read as plain text. (Take a look at your data variable.)

You can use JSON.parse(txt) or jQuery's AJAX shorthand $.getJSON(...).

Ad
source: stackoverflow.com
Ad