3

I have a spring-boot-starter-web with Mustache.

I have a user login page, once the credentials are validated I open a partial view with user details, my code looks like this:

//Javascript

function AjaxNoAsyncPOST(urlString, dataObj) {
    return $.ajax({
        headers: {
            "X-Token": token
        },
        type: "POST",
        async: false,
        url: urlString,
        processData: false,
        data: JSON.stringify(dataObj),
        contentType: "application/json; charset=utf-8",
        success: function (data) {
            return true;
        },
        failure: function (errMsg) {
            $(".signupAlert").html("<span style='color: red; display: block; padding-bottom: 5px;'>Please contact the system administrator.</span>");
            return false;
        },
        error: function (errMsg) {
            $(".signupAlert").html("<span style='color: red; display: block; padding-bottom: 5px;'>The username or password you entered is incorrect.</span>");
            return false;
        }
    });
}

function validateLoginForm(loginForm) {
    var loginForm = $(loginForm);
    var dataArray = loginForm.serializeArray(),
        len = dataArray.length,
        dataObj = {};

    if (validateLoginData(dataObj)) {
        var urlString = contextName + 'api/login/token';

        var user = AjaxNoAsyncPOST(urlString, dataObj).responseJSON;

        if (Object.prototype.toString.call(user) == '[object Object]') {
        //The user object is of the following JSON format
        //  var user = {
        //          "user": [
        //              {"name": "London"},
        //              {"token": "Paris"},
        //              {"role": ["USER", "ADMIN"]},
        //              {"isAdmin": true}
        //          ]
        //      },


            showDiv('homebox');

            //get a reference to our HTML template

            var userInSessionTemplate = $('#userInSessionTemplate').html();


            console.log("Before template="+userInSessionTemplate); //blank

            //tell Mustache.js to iterate through the JSON and insert the data into the HTML template
            var output = Mustache.to_html(userInSessionTemplate, userData); //I have tried to user Mustache.render, but no success

            console.log("output="+output); //blank
            console.log("After template="+userInSessionTemplate); //blank

            //append the HTML template to the DOM
            $('#userSessionData').append(output);//empty
        }
    }
}

My index.html

<!-- this is the HTML template -->
<div id="homebox" style="display:none; "
     class="mainbox overviewbox col-sm-8 col-sm-offset-2">
        {{>overviewPartial}}
</div>

My overviewPartial.html

<div class="container">
    <div class="navbar navbar-default" role="navigation">
        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse navbar-ex1-collapse">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#"><i class="icon-home icon-white"></i>Overview</a></li>
            </ul>

            <script id="userInSessionTemplate" type="text/template">

                    <ul class="nav navbar-nav navbar-right">
                        <li class="dropdown">
                            {{#user}}
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">Welcome, {{name}} <b
                                    class="caret"></b></a>
                            {{/user}}
                            <ul class="dropdown-menu">
                                <li><a href="/user/preferences"><i class="icon-cog"></i> Preferences</a></li>
                                <li><a href="/help/support"><i class="icon-envelope"></i> Contact Support</a></li>
                                <li class="divider"></li>
                                <li><a href="/auth/logout"><i class="icon-off"></i> Logout</a></li>
                            </ul>

                        </li>
                    </ul>

            </script>
        </div>
        <!-- /.navbar-collapse -->
    </div>
</div>

I am trying to render the user details, but I am unable to do so. Can someone please help me with this.

Update 1: I have made changes to overviewPartial.html, and now I get the template details, but when I print $('#userInSessionTemplate').html(), it seems that I the {{user}} has already been evaluated, so I don't get the html between the user tags

Update 2: The overviewPartial.html contains a section

     {{#user}}
      <a href="#" class="dropdown-toggle" data-toggle="dropdown">Welcome, {{name}} 
<b class="caret"></b></a>
  {{/user}}

After I get the response and the object, this section is always empty, I cannot seem to find what is wrong. It does not print Welcome Victor.

The User object

Object { token="6psobJJaZvpo1UMyxbyzUIXs...aQLcvCzSADGciNJ7wNFHsvH", name="Victor", roles=["ROLE_API", "ROLE_ADMIN"], isAdmin=true}

Update 3: Output contains:

<ul class="nav navbar-nav navbar-right" style="border: 1px solid black; height: 50px; width: 50%">
                    <li class="dropdown">

                        <ul class="dropdown-menu">
                            <li><a href="/user/preferences"><i class="icon-cog"></i> Preferences</a></li>
                            <li><a href="/help/support"><i class="icon-envelope"></i> Contact Support</a></li>
                            <li class="divider"></li>
                            <li><a href="/auth/logout"><i class="icon-off"></i> Logout</a></li>
                        </ul>

                    </li>
                </ul>

Update 4: I think I found the issue, the issue is the ViewResolver. This is how it looks

@Bean
public ViewResolver getViewResolver(ResourceLoader resourceLoader){
    MustacheViewResolver mustacheViewResolver = new MustacheViewResolver();
    mustacheViewResolver.setPrefix("/WEB-INF/views/");
    mustacheViewResolver.setSuffix(".html");
    mustacheViewResolver.setCache(false);
    mustacheViewResolver.setContentType("text/html;charset=utf-8");

    JMustacheTemplateLoader mustacheTemplateLoader = new JMustacheTemplateLoader();
    mustacheTemplateLoader.setResourceLoader(resourceLoader);

    JMustacheTemplateFactory mustacheTemplateFactory = new JMustacheTemplateFactory();
    mustacheTemplateFactory.setTemplateLoader(mustacheTemplateLoader);

    Mustache.Compiler compiler = Mustache.compiler();

    mustacheTemplateFactory.setCompiler(compiler);

    mustacheViewResolver.setTemplateFactory(mustacheTemplateFactory);

    return mustacheViewResolver;
}

And my index.html contains

<div id="homebox" style="display:none; "
     class="mainbox overviewbox col-sm-8 col-sm-offset-2">
        {{> overviewPartial}}
</div>

Now I get an error:

java.lang.UnsupportedOperationException: Template loading not configured
at com.samskivert.mustache.Mustache$1.getTemplate(Mustache.java:788) ~[jmustache-1.9.jar:na]
at com.samskivert.mustache.Mustache$IncludedTemplateSegment.execute(Mustache.java:663) ~[jmustache-1.9.jar:na]
at com.samskivert.mustache.Template.executeSegs(Template.java:92) ~[jmustache-1.9.jar:na]

Don't know what I am missing

victor
  • 1,013
  • 3
  • 13
  • 21
  • First point the trailing `,` after `var user ` breaks the code. Second point, split your code up into smaller functions; it will make it easier to understand, smaller (some parts are reusable) and easier to bugfix. – Thermatix Nov 21 '14 at 14:42
  • @user3536548, I have updated the code, the second var user was only to explain what the format is when the AJAX responds. I do not understand the small parts, which file or function you think is too big here, please let me know and I shall try and break it down as much as possible. – victor Nov 21 '14 at 14:50
  • are you also aware that your function `validateLoginData` is recursive? it calls itself at `if (validateLoginData(dataObj)) {` which which will never return, as it will continually call itself on `dataObj` which is just an empty object. Any way, I've been making your code more separate, just give me a little longer, need to understand your `validateLoginForm` function – Thermatix Nov 21 '14 at 15:27

1 Answers1

2

I've re-written your code to separate concerns, by moving related code into separate functions.

Now your concerns are separated it should be easier to both understand and debug, I.e. the code that renders the template onto the screen is separate from the code that gets and validates the data.

That said the code isn't finished, you're going to have to do that as I don't know what you were trying to check in the first if statement of your validateLoginForm function, but it should be easier now at least.

function ajaxRequestNoSync(dataobject){
    jquery.each(['url','token'], function (i,toCheck) {
        if(dataobject[toCheck] == 'undefined'){
            throw (toCheck + ' needs to be defined')
        }
    })

    return $.ajax({
        headers: {
            'X-Token' : dataobject.token
        },
        type: dataobject.type || 'GET',
        async: false,
        url: dataobject.url
        processData: false,
        data: getData(dataobject.data),
        contentType: "application/json; charset=urft-8",
        sucess: results,
        failure: results,
        error: results,
    })
}

function getData (data) {
    return null if data == 'undefined'
    return JSON.stringify(data)
}

//determins if results are error or not by checking type of third arg, which would be a string only on failure or error
function results(first,status,third){
    if(third.typeof == 'string'){ 
        flash(third)
        return false
    }else{
        return true
    }
} 

function flash (message){ //flashes the error message on screen
    var element = $(".signupAlert")
        element.html(message)
                    .addClass('errorclass') //change to error css class
        setTimeout(function(){
            element.fadeOut(1000)//fades out over 1 second
            setTimeout(function () {element.html('')},1000)//erases elements html content after it has faded away
        },5000)//will make message faseout after 5 seconds
}

function validateLoginForm(loginForm){
    var form = {}
    form.dataSerial = $(loginForm).serialzeArray()
    form.dataLength = form.dataSerial.length
    form.data = {}

    if(){ //check for somthing here, not quite sure what though
        var urlString = contextName + 'api/login/token'
        var user = ajaxRequestNoSync({
            'url':urlString,
            'data': form.dataSerial,
            'type':'POST',
            'token': token //not sure what the token is or where it comes from
        }).responseJSON

        if(user.typeof == 'object'){
            renderResult(user)
        }
    }
}

function renderResult(userData){
    showDiv('homebox');
    var userInSessionTemplate = $('#userInSessionTemplate').html();
    var output = Mustache.to_html(userInSessionTemplate, userData);
    $('#userSessionData').append(output)
}
Thermatix
  • 2,224
  • 13
  • 36
  • thanks for the help, I am looking into this, but will post back next week now. – victor Nov 21 '14 at 16:34
  • I use your code and ran the application only to get back to the same problem I've been having. I have updated the question with exactly what I need. – victor Nov 24 '14 at 11:06
  • Did you fix `if(){ //check for somthing here, not quite sure what though` also what's the content of `user` after the ajax request is made? – Thermatix Nov 24 '14 at 11:20
  • Yes I add all the missing info and remove the token as that comes from the server (something of a session variable). Was meant to update the ticket with the user object, but forgot; not have update the same. Also I have noticed that when I console.log(userInSessionTemplate), I don't get the code between the user tags, its like its already been evaluated. – victor Nov 24 '14 at 11:42
  • Do I need to add Handlebarsjs & register a helper? – victor Nov 24 '14 at 11:43
  • Ok but what's the value of the variable `user` after the ajax request is made? Umm, as for adding Handelbars.js that would depend, is the html content compiled by the server or does the server only send data to the client which compiles the template? – Thermatix Nov 24 '14 at 11:58
  • user = Object { token="6psobJJaZvpo1UMyxbyzUIXs...aQLcvCzSADGciNJ7wNFHsvH", name="Victor", roles=["ROLE_API", "ROLE_ADMIN"], isAdmin=true}. The server only sends data and client compiles the template. And if I console.log(user["name"]), I get Victor. – victor Nov 24 '14 at 12:01
  • OK, so we can definitely now say that the problem is to do with handlebars compiling the data into a template and returning a html string. In the `renderResult` function what does the `output` variable contain? Also I noticed that `userSessionData` id doesn't exist in the `index.html` or `overviewPartial.html.html`. – Thermatix Nov 24 '14 at 12:20
  • In overviewPartial.html I have a div
    , updated the question
    – victor Nov 24 '14 at 12:26
  • Have you tried it without `{{#user}}{{user}}` ? because according to the tutorial on mustache templating it doesn't have that, I'm guessing it allows you to specify what object to get the information from in the template but I think that's a bit pointless as your only supplying one object. Also try changing `$('#userSessionData').append(output)` to `$('#userSessionData').html(output)` Lastly try render(userInSessionTemplate, userData) as Acourding to :http://stackoverflow.com/questions/10872615/what-is-the-difference-between-mustache-render-and-mustache-to-html `.to_html` has been depreciated. – Thermatix Nov 24 '14 at 12:39
  • updated the question, to answer your specifically, I tried {{#user }}{{user}}, not happened, its like its empty. I tried to change append to html(output), nothing changed, its the same. – victor Nov 24 '14 at 13:40
  • I'm sorry to say but I've got nothing else to suggest, have you tried mocking the data and seeing if that works? as in supplying a pre-made user object not gotten from a ajax call? – Thermatix Nov 24 '14 at 16:05
  • thanks for the help, I have tried that. The funny thing is that when I try and ready the template and print it, the user tag is already evaluated, which is bizarre. Now am am actually look at pre-compile my template using the suggestion at http://stackoverflow.com/questions/8659787/using-pre-compiled-templates-with-handlebars-js-jquery-mobile-environment, but getting an error "Error: Syntax error, unrecognized expression: #[object Object]" – victor Nov 24 '14 at 16:16
  • I think it's returning the value of `Object.prototype.toString.call(user)` – Thermatix Nov 24 '14 at 16:50
  • I think its not the problem with the JS files, I think its the viewResolver that I have written. Please check my update 4 – victor Dec 02 '14 at 13:00
  • 1
    I'm going to be honest, this is now beyond my knowledge so I'm sorry to say but I can't be of much more help. – Thermatix Dec 02 '14 at 18:05
  • Totally understand, I think I might have solved the problem. I shall perform some more testing today and post back. Thanks for your help – victor Dec 03 '14 at 09:16