handlebars-lang / handlebars.js

Minimal templating on steroids.
http://handlebarsjs.com
MIT License
18.02k stars 2.04k forks source link

Asynnchronous Helper using into express-handlebar #1446

Closed agashish closed 4 years ago

agashish commented 6 years ago

Hi,

Please ignore my english, but ill definitely try to explain.

I am new into nodejs with express and using express-handlebars template engine. But in a case, i want to use helper in which i can use mongoose query to return the result and print into out through handlebars template. I'll appreciate that, and i have read previous issues on this point. It was really great but i tried previous example but no luck. This is my helper function below please have a look.

signup: function (taskId , cb) {

    console.log('hello')
    //return new hbsAsync.SafeString(taskId)
    return new Promise ((resolve, reject) => {
        User.find({}).count().exec((err , count) => {
            if(err) {
                console.log('error comes')
                reject(err)
            }
            console.log('result got it')
            resolve(count)
            console.log(count)
        })
    })
    console.log('cocka')   
}

This is my approach to get the data back into his templet file. I used the helper through {{signup _id}} this return me [object promise]. Really i don't understand. I tried a lot. Please help me out. Many Thanks to everyone.

dhollenbeck commented 6 years ago

Your solution is backwards. Express-handlebars helpers are for synchronous code execution. Therefore, they are NOT suitable for reading data from a database. In fact, the entire Handlebars rendering process is synchronous.

The solution is first read data from the database and pass that data into the express-handlebars.

// express controller function
exports.signup = function(req, res, next) {

    // get user id somehow
    var user_id = req.param.user_id; 

    User.find({
        user_id: user_id
    }).count().exec((err , count) => {
        if(err) next(err);

        res.render('path/to/signup/template', {
            count: count
        });                
    });
};
agashish commented 6 years ago

Hi Dhollenbeck,

Thanks for your time. Yes i agreed i have used many helper and created custom helpers. But this time, i need to be addressed if i need a custom helper where or in which can perform database operation and get back to the handlebar template as i have created above.

***** THIS IS HELPER FILE AND DEFINED THE PATH INTO app.engine. This is just for reference. const mongoose = require('mongoose') const hbsAsync = require('express-hbs') var async = require('async');

module.exports = { // synchronous success if_even: (conditional, options) => { if((conditional % 2) == 0) { return options.fn(this); } else { return options.inverse(this); } }, signup: function (taskId , cb) { //asyncronous trying, please look

    console.log('hello')
    //return new hbsAsync.SafeString(taskId)
    return new Promise ((resolve, reject) => {
        User.find({}).count().exec((err , count) => {
            if(err) {
                console.log('error comes')
                reject(err)
            }
            console.log('result got it')
            resolve(count)
            console.log(count)
        })
    })
    console.log('cocka')   
}

}

Please, help me about the helper with database operation and print into template through {{signup _id}} simple approach. If this could does that means we can do a lot with. Thank You

agashish commented 6 years ago

can help me out

nknapp commented 6 years ago

What @dhollenbeck said is that you should do your database operations before calling Handlebars. Don't use helpers for that.

If you really need to, you should ask your question to the express-hbs-project. I think they have support for async helpers somehow, but that is not part of the Handlebars project itself. Handlebars itself is strictly synchronous.

nknapp commented 6 years ago

There is a promised-handlebars-project which supports helpers returning Promises, but I don't know how to use it with express-hbs. And it might be much slower than Handlebars itself (never made any benchmarks)

agashish commented 6 years ago

HIi, Thank for your time.

I agreed , express-handlebars is synchronous and yes this is the problem. But is there any way to make handlebars async. I'll look into promised-handlebars. I'll come to you shortly.

Thanks once again.

agashish commented 6 years ago

Hi ,

I tried a lot but no luck again.

I have already wrote the query to fetch the data from mongo db through mongoose but when i render the data one by one that time i need to call a helper to pass and _id of task and get all assigned user list to the specific task. This is all i need simple.

Am using express fro server , for templating i use express-handlebars but in knew it this is synchronous and really on this stage i cant change my template engine into whole project. This is really a big problem to me.

I have seen your responses these were awesome. can you please help me out from this situation. Please have a look into the code below : -


From server side i go the the results of task list but i need to get assigned user to task one by one. Thast why i need it this helper to pass _id and get assign user list.

{{#each tasks}}

  • {{!-- {{getAssignUserToTask _id}} --}}  
    {{ task_name }}
      {{> dashboard/task_user_list}}
    ---- When helper called into template Helper will be invoke from helper file : - module.exports = { signup: async function (taskId) { console.log('hello') //return new hbsAsync.SafeString(taskId) await AssignUser.find({}).count().then((err, count) => { return taskId }) } }
  • nknapp commented 6 years ago

    The official way is to get the user list of each task before the template is rendered. I'm not sure about mongoose, but I can imagine that you can create a query that extracts all the necessary information at once. That query might be much faster then extracting each user list one-by-one when the task is rendered. I would try this first.

    But you could also switch to express-hbs. It does support asynchronous helpers through callbacks, although not in all cases.

    aniude commented 9 months ago

    @nknapp Hi, nknapp. is that any advices as Handlebars.registerPartial to implement promise, I have the same problem too.

    tflanagan commented 9 months ago

    async helpers would be helpful for work dependent on a passed in argument.

    handlebars.registerHelper('doAsyncWork', async (someVar) => {
      // Some async work that uses `someVar`, could be anything
    
      return results;
    });