简体   繁体   中英

How can I add many sections of dynamic content in express-handlebars?

I want to use templates in express-handlebars, i've got a file named "layout.hbs" in a folder called "layouts" inside my views folder for express, i've specified in express view engine config that i want to use handlebars as view engine and i want to use a layout:

app.set("port", process.env.PORT || 3000);
app.set("views", path.join(__dirname, "resources/views"));
app.engine(".hbs", exphbs({
  defaultLayout : "template",
  layoutsDir : path.join(app.get("views"), "layouts"),
  partialsDir : path.join(app.get("views"), "partials"),
  extname : ".hbs",
  helpers : require("./helpers/handlebars/handlebars")
}));
app.set("view engine", ".hbs");

It works fine, i can use the layout in my handlebars files, for now i know that i can use the {{{ body }}} syntax to put the variable HTML content on the template, so, in my layout.hbs file i have this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="http://localhost:3000/css/style.min.css">
    <title>Welcome!!</title>
</head>
<body>
    {{{ body }}}
</body>
</html>

And in my main.hbs file i have this:

<h1>Hello from main!!!</h1>

So the final result is:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="http://localhost:3000/css/style.min.css">
    <title>Welcome!!</title>
</head>
<body>
    <h1>Hello from main!!!</h1>
</body>
</html>

And that's fine, it puts the dynamic content oh the {{{ body }}} tag, but now i need to add more sections of dynamic content to my template like styles and scripts that are different for every page, for example, in my main.hbs i want to add this style:

<link rel="stylesheet" href="http://localhost:3000/css/main.min.css">

But in contact.hbs i want to add:

<link rel="stylesheet" href="http://localhost:3000/css/contact.min.css">

I don't want to add both tags in the layout 'cause when i load the main page i will be loading the contact styles that i don't need and it will make more slower the load of the page.

In Laravel Blade i can do something like:

Layout.blade.php

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="http://localhost:3000/css/style.min.css">

    @yield('css', "") 

    <title>Welcome!!</title>

</head>
<body>
    @yield('main', "") 
</body>
</html>

main.blade.php

@section('css')
    <link rel="stylesheet" href="{{ asset("css/main.min.css") }}">
@endsection

@section('main')
    <h1>Hello from main!!!</h1>
@endsection

And it works, how can i do the same in express-handlebars?

I found the solution here .

Basically, we have to add this helper function to your helpers of express-handlebars:

section: (name, options) => { 
        if (!this._sections) this._sections = {};
         this._sections[name] = options.fn(this); 
         return null;
}

And then in your layouts file you can do something like this:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="http://localhost:3000/css/style.min.css">

    {{{_sections.css}}}

    <title>Welcome!!</title>

</head>
<body>
    {{{body}}}

    {{{_sections.scripts}}}
</body>
</html>

And in your files you can do this:

<h1>Hello from main!!!</h1>


{{#section 'css'}}
    <link rel="stylesheet" href="http://localhost:3000/css/main.min.css">
{{/section}}

{{#section 'scripts'}}
    <script src="http://localhost:3000/js/main.min.js"></script>
{{/section}}

And it will results in:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="http://localhost:3000/css/style.min.css">

    <link rel="stylesheet" href="http://localhost:3000/css/main.min.css">

    <title>Welcome!!</title>

</head>
<body>
    <h1>Hello from main!!!</h1>

    <script src="http://localhost:3000/js/main.min.js"></script>
</body>
</html>

Edit:

If you want something more similar to Laravel with the default text feature you can add this helper:

yield: (name, default_value) => {

    if(typeof default_value == "object") default_value = "";
    return this._sections[name] || default_value;

}

And use in your layout:

{{{ yield "section_index" "default value" }}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM