How can I use Edge.JS to have a different title per page


#1

From Gitter: https://gitter.im/adonisjs/adonis-framework?at=59ddf1cb01110b7231a0fcfc

As it is documented nowhere, here’s my question. Can I do something like this with edge ?
The following do not work, but how am I supposed to do something similar that allows me to have different title/metas per page?

<title>@!section('page:title')</title>
<meta charset="@!section('page:charset')">

#2

Hey :wave:

To be able to do that you’ll need to use Edge Components.

So let defines your master template with something like this:

<!DOCTYPE html>
<html>
<head>
  {{-- Meta Information --}}
  <meta charset="UTF-8">
  <meta name=viewport content="width=device-width, initial-scale=1">

  {{-- Title --}}
  <title>{{ title }}</title>
</head>
<body class="{{ bodyClass }}">
  @!yield($slot.main)
</body>
</html>

Then on your view you’ll need to do:

@component('layout.master', { bodyClass: 'forum', title: 'Forum' })

  @each(thread in threads)
    <article>
      <h4>
        <a href="/threads/{{ thread.id }}">{{ thread.title }}</a>
      </h4>
      <div class="body">{{ thread.body }}</div>
    </article>
  @endeach

@endcomponent

#3

Yeah but using this I loose the ability to have multiple @section on my layout :confused:


#4

Now you don’t.

You can still have multiple slot. Here the main slot is used since I have only one content.
But you can do something like this

@component('layout.master', { bodyClass, title })
  @slot('page')
    @include('layout._navbar')

    <div class="m-grid__item m-grid__item--fluid m-grid m-grid--ver-desktop m-grid--desktop m-body">
      {{-- Aside --}}
      @include('layout._aside')

      {{-- Content --}}
      <div class="m-grid__item m-grid__item--fluid m-wrapper">

        <main class="m-content">
          @!yield($slot.content)
        </main>
      </div>
    </div>
  @endslot

  @slot('script')
    <script>
      alert('Yay!')
    </script>
  @endslot
@endcomponent

With a master page that looks like

</head>
<body class="m-page--fluid m--skin- m-content--skin-light2 m-header--fixed m-header--fixed-mobile m-aside-left--enabled m-aside-left--skin-dark m-aside-left--offcanvas m-footer--push m-aside--offcanvas-default {{ bodyClass }}">

  <div class="m-grid m-grid--hor m-grid--root m-page">
    @!yield($slot.page)
  </div>

  @!yield($slot.script)
</body>
</html>

#5

Edge Components brakes my Vue component.

I only get it to work with @section. Is that a known problem or am i doing something wrong?


#6

Can you share your code?


#7

Thank you @wxs77577.

This is how it looks like right now using @section.

master.edge:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="msapplication-tap-highlight" content="no">
    <meta name="description"
          content="Materialize is a Material Design Admin Template,It's modern, responsive and based on Material Design by Google. ">
    <meta name="keywords"
          content="materialize, admin template, dashboard template, flat admin template, responsive admin template,">
    @!section('title')
    <!-- Favicons-->
    <link rel="icon" href="{{ '/images/backend/favicon/favicon-32x32.png' }}" sizes="32x32">
    <!-- Favicons-->
    <link rel="apple-touch-icon-precomposed" href="{{ '/images/backend/favicon/apple-touch-icon-152x152.png' }}">
    <!-- For iPhone -->
    <meta name="msapplication-TileColor" content="#00bcd4">
    <meta name="msapplication-TileImage" content="{{ '/images/backend/favicon/mstile-144x144.png' }}">
    <!-- For Windows Phone -->
    <!-- CORE CSS-->
    <link href="{{ mix('/css/backend/materialize.css') }}" type="text/css" rel="stylesheet" media="screen,projection">
    <link href="{{ mix('/css/backend/style.css') }}" type="text/css" rel="stylesheet" media="screen,projection">
     <!-- Custome CSS-->
    <link href="{{ mix('/css/backend/custom/custom.css') }}" type="text/css" rel="stylesheet" media="screen,projection">
    <!-- INCLUDED PLUGIN CSS ON THIS PAGE -->
    <link href="{{ '/js/backend/plugins/perfect-scrollbar/perfect-scrollbar.css' }}" type="text/css" rel="stylesheet"
          media="screen,projection">
    <!-- Include csrfToken -->
    <meta name="csrf_token" content="{{ csrfToken }}">
    @!section('css')
</head>
<body>
{{{ vueView != '' ? '<div id="' + vueView + '">' : '' }}}
@include('backend.includes.header')
<!-- START MAIN -->
<div id="main">
    <!-- START WRAPPER -->
    <div class="wrapper">
        <!-- START LEFT SIDEBAR NAV-->
        @include('backend.includes.left-sidebar')
        <!-- END LEFT SIDEBAR NAV-->
        <!-- START CONTENT -->
        @!section('content')
        <!-- END CONTENT -->
        <!-- START RIGHT SIDEBAR NAV-->
        @include('backend.includes.right-sidebar')
        <!-- LEFT RIGHT SIDEBAR NAV-->
    </div>
    <!-- END WRAPPER -->
</div>
{{{ vueView != '' ?  '</div>' : '' }}}
<!-- END MAIN -->
<!-- START FOOTER -->
@include('backend.includes.footer')
<!-- END FOOTER -->
@if(vueView)
<!-- Vue js -->
<script src="{{ mix('/js/backend/' + vueView + '.js') }}"></script>
@endif
<!-- jQuery Library -->
<script type="text/javascript" src="{{ '/js/backend/plugins/jquery-1.11.2.min.js' }}"></script>
<!--materialize js-->
<script type="text/javascript" src="{{ '/js/backend/materialize.js' }}"></script>
<!--scrollbar-->
<script type="text/javascript" src="{{ '/js/backend/plugins/perfect-scrollbar/perfect-scrollbar.min.js' }}"></script>
<!--plugins.js - Some Specific JS codes for Plugin Settings-->
<script type="text/javascript" src="{{ '/js/backend/plugins.js' }}"></script>
</body>
</html>

customers/index.edge (edge file that is calling Vue component with vueView: ‘customers’ sent from customerController):

@layout('backend.layouts.master')

@section('title')
<title>Kunder</title>
@endsection

@section('css')
<link href="{{ '/css/backend/vue.css' }}" type="text/css" rel="stylesheet" media="screen,projection">
@endsection

@section('content')

<!--start container-->
<div class="container">
    <div class="row">
        <div class="col s12 m12 l12">

            <div id="roboto">

                <di-customers showgrid="0"></di-customers>

            </div>
        </div>
    </div>
</div>
<!--end container-->

@endsection

as you can see i load vue app dynamically and only if it is an vue component on the page.
i don’t get an error using slots and edge components but the vue component is not showing.

Later i will show the code when i try to use slots and edge components.


#8

You can do something similar to this:

base.edge

<!DOCTYPE html>
<html lang="en">
<head>
    <title>
        @!section('title')
    </title>
    @!section('css')
</head>

<body>

<div class="container">
    @!section('content')
</div>

@!section('js')
</body>

</html>

page.edge

@layout('base')

@section('title')
Title goes here
@endsection

@section('css')
    <link rel="stylesheet" href="public/css/app.css">
@endsection

@section('content')
    <h1>Some content goes here</h1>
@endsection

@section('js')
<script src="public/js/app.js"></script>
@endsection

#9

In fact, it’s way simpler by using @set since it’s available.


#10

@romain.lanz, I agree with you, it is more cleaner:

base.edge

<!DOCTYPE html>
<html lang="en">
<head>
    <title>{{ title }}</title>
    @!section('css')
</head>

<body>
@!section('vars')

<div id="app" class="container">
    @!section('content')
</div>

@!section('js')
</body>

</html>

page.edge

@layout('base')

@section('css')
    <link rel="stylesheet" href="public/css/app.css">
@endsection

@section('vars')
    @set( 'title', 'Title goes here' )
@endsection

@section('content')
    <h1>Some content goes here</h1>
@endsection

@section('js')
<script src="public/js/app.js"></script>
@endsection