2

I'm on the path of learning Vue and i have a question that you might find trivial but i struggle to find an answer. First of all, i'm using Vue with Vue Router, in order to build a test blog.

Let's say the h1 of my page is inside the header component, itself included inside the layout.

But then, how can i set the content of this h1 tag for each page, since it belongs to the header, which is only included in the layout? One solution i found was to set meta.h1 on each route declaration, something like that:

{
    path: 'articles',
    meta: {
        h1: 'All the articles'
    }
}

Then, inside the header, i can use a method to get the value of this.$route.meta.h1. Something like that:

methods: {
    h1() {
        return this.$route.meta.h1
    }
}

It works, but it seems kind of wrong, since i don't think that's the job of the route file to handle this. To make it simple, what is the best way, the preferred way, to handle this situation? ty :)

[EDIT]

Here is a simple example page from the bootstrap documentation that could well illustrate my question: https://getbootstrap.com/docs/4.0/examples/blog/

Title of a longer featured blog post

is the h1 and would probably be dynamic, changing from page to page. But it's part of the header component, not part of the articles, of the forum, of the comments or any other component... so if i can reformulate my question, that would be "how can i set this h1 title elegantly" ? Don't think of something complicated, this is a very basic question from a beginner looking toward some answers :p

Anthony Aslangul
  • 3,589
  • 2
  • 20
  • 30
  • When the article is loaded, couldn't you emit an event up to the Header, in order to set its content? – Matt Oestreich Apr 21 '19 at 17:03
  • I can also do this yes, but is it how it should be done ? Since i have near zero experience with Vue, i'm having a hard time figuring out what's considered best practices versus crappy code. Doing something that works is important, but doing the right way is even better :p – Anthony Aslangul Apr 21 '19 at 17:49

2 Answers2

0

You can pass props via routes like this, but I'm not sure how you would supply that variable.

I'm not sure of the structure of your app, and if the header component is the header for the entire app, or if it's just a header for each article.. If it's a header just for the article, there is no need to emit events.. (see example below).


[CodePen mirror]


const appHeader = {
  template: "#app-header",
  computed: {
    dynamicHeader() {
      let r = this.$route.name;
      // caps first letter
      let f = r.charAt(0).toUpperCase() + r.slice(1);
      switch(f){
        case "Home": return f + " Page!";
        case "Contacts": return "Contact Us!";
        case "About": return f + " Us!!"
      }
    }
  }
};

const contactsPage = {
  template: "#contacts-page"
};

const aboutPage = {
  template: "#about-page"
};

const homePage = {
  template: "#home-page"
};

const routes = [
  {
    path: "/",
    name: "home",
    components: {
      header: appHeader,
      content: homePage
    }
  },
  {
    path: "/contact",
    name: "contacts",
    components: {
      header: appHeader,
      content: contactsPage
    }
  },
  {
    path: "/about",
    name: "about",
    components: {
      header: appHeader,
      content: aboutPage
    }
  }
];

const router = new VueRouter({ routes });

new Vue({
  router
}).$mount("#app");
nav.mainNav > * {
  padding: 0 0.75rem;
  text-decoration: none;
}
 nav.mainNav > *:nth-last-child(n+2) {
  border-right: 1px solid #aaa;
}
 #headerContainer {
  background-color: yellow;
  margin-bottom: -20px;
}
 #page {
  border: 1px solid black;
  margin: 20px 20px 20px 20px;
}
 #page > * {
  margin: 10px 10px 10px 10px;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.4/vue-router.min.js"></script>
<div id="app">
  <div>
    <router-view name="header"></router-view>
    <router-view id="page" name="content"></router-view>
  </div>
</div>

<!-- -------------------- -->
<!-- APP HEADER COMPONENT -->
<!-- -------------------- -->
<script type="text/x-template" id="app-header">
  <div>
    <div id="headerContainer">
      <h1>{{ dynamicHeader }}</h1>
    </div>
    <nav class="mainNav">
      <router-link 
        :to="{ name: 'home' }"
      >Home</router-link>
      <router-link 
        :to="{ name: 'about' }"
      >About</router-link>
      <router-link 
        :to="{ name: 'contacts' }"
      >Contacts</router-link>
    </nav>
  </div>
</script>
<!-- -------------------- -->

<!-- ----------------------- -->
<!-- CONTACTS PAGE COMPONENT -->
<!-- ----------------------- -->
<script type="text/x-template" id="contacts-page">
  <div style="background-color:blue;">
    <h2>this is the contacts page</h2>
  </div>
</script>
<!-- ----------------------- -->

<!-- -------------------- -->
<!-- ABOUT PAGE COMPONENT -->
<!-- -------------------- -->
<script type="text/x-template" id="about-page">
  <div style="background-color:green;">
    <h2>this is the about page</h2>
  </div>
</script>
<!-- -------------------- -->

<!-- ------------------- -->
<!-- HOME PAGE COMPONENT -->
<!-- ------------------- -->
<script type="text/x-template" id="home-page">
  <div style="background-color:red;">
    <h2>this is the home page</h2>
  </div>
</script>
Matt Oestreich
  • 8,219
  • 3
  • 16
  • 41
  • Thank you for your answer, however i was just talking about the global app header. Can you take a look at my question, i edited it with an example ? ty mate – Anthony Aslangul Apr 21 '19 at 20:00
  • That still isn't the global app header... The part that says "Large" and has the links under it (World, US, Technology, Design, Culture..etc...) would all be considered the global app header (including the links).. What you are referencing appears to be the header for an "article preview" type of component. – Matt Oestreich Apr 21 '19 at 21:50
  • Ok i see your point, indeed it's an article preview in this case, you are right... hum... ok we'll make it simple: if i have an about page, a news page, a contact us page, you know, the very basic stuff. How can i change the h1 of each of these pages, if this tag (the h1) is included inside another component (in my case, the header component) ? For instance, in the Contact us page, the h1 ("Contact us") is not in the template of the contact us component. Do you understand what i mean? – Anthony Aslangul Apr 21 '19 at 23:01
  • To be honest i'm not really convinced that setting the h1 in a switch statement is a good solution, because it is not very scalable. It works because there is 3 pages in this example, but with 30 pages it will become ugly. Not to mention the cases where the page name changes. But you are right, it works, as my first solution of setting the h1 in the meta object worked too. However, it must exists a better solution to solve this problem right ? – Anthony Aslangul Apr 22 '19 at 09:14
  • 1
    Correct. The way you're trying to structure this, and the logic behind it, is flawed. You need to use layouts for each page (where you would set the h1) and components to fill the layouts with content. None the less, my answer did meet the objectives you were wanting. – Matt Oestreich Apr 22 '19 at 12:19
  • I figured out a way to handling this situation as i wanted to. Thank you anyway for taking the time to answer! – Anthony Aslangul Apr 22 '19 at 13:01
  • 1
    That is still rather flawed logic. If you are wanting to go this route, I recommend using [Vuex](https://vuex.vuejs.org/) - it sounds like you are going to need it eventually anyway. While an eventbus will certainly work for you, most people do not recommend using them (eventbus are prone to race conditions).. Here are some examples.. Cheers! [One](https://stackoverflow.com/questions/50695234/vue-js-which-better-to-use-event-bus-or-storage) [Two](https://forum.vuejs.org/t/bus-vs-vuex/6679) [Three](https://forum.vuejs.org/t/eventbus-vs-vuex-vs-root-emit-best-practices/59340/4) – Matt Oestreich Apr 22 '19 at 13:51
  • I think you're right, and more experience will probably give me more clarity about all this, what to use and when :) – Anthony Aslangul Apr 22 '19 at 16:00
0

I found a solution that seems to better fit what i requested, which is using an event bus as described in this video:

https://www.youtube.com/watch?v=jzh4zQcfB0o

To sum up what the guy says, the idea is to use another instance of Vue as an event bus in order to emit and listen to events between components not related to each other. This way, i can set the h1 title of my page from any components.

Anthony Aslangul
  • 3,589
  • 2
  • 20
  • 30