Vuejs template inheritance - javascript

How can I use template inheritance (Like what jade has, extends file.jade and then the blocks with the same name would be overwritten)?
I know that I can do everything with composition, but for components like footer and header which appear on every single page except one or two (e.g.login page) I must write them on every single component. In my app I have a two level navigation and it seems painful to repeat them on every one of those child components :(
I know that I can use jade and then inherit a jade file within my components, but it seems wrong because I would have some jade and some Vue files, is there any other way to do this?
// Component.vue
<template lang="jade">
extends ./StandardLayout
block content
router-view
</template>
// StandardLayout.Vue
<template lang="jade">
div
navbar
div.container
div.spacer
div.row
block content
<template>
What I've settled for, is a layouts folder filled with jade layouts and I use them to extend my components. I used vue-cli with webpack template.

In the most general case if you have to repeat the same HTML over and over, one option you could use is <partial>s.
<partial name="header"></partial>
<div>My content content</div>
<partial name="footer"></partial>
Where you declare partials as
Vue.partial('header', '<h3>This is the title: {{title}}</h3>')
Vue.partial('footer', '<footer>Mini footer</footer>')
However if you are building a Single Page Application the strategy you could follow is to simply have a header and a footer around your <router-view>, here is a jsfiddle that demonstrates how to do.
https://jsfiddle.net/gurghet/vdqutw2y/
<header><h1>
My title: {{title}}
</h1></header>
<p>
<a v-link="{ path: '/foo' }">Go to Foo</a>
<a v-link="{ path: '/bar' }">Go to Bar</a>
</p>
<router-view></router-view>
<footer>Such footer, many links, wow!</footer>

If you know Chinses, please look it
// Base Component
<template>
<div class="base-thing special-class">
<Button />
</div>
</template>
<script>
import Button from './ButtonClick'
export default {
components: { Button }
}
</script>
// Inheriting Component
<script>
import BaseComponent from './BaseComponent'
import Button from './OtherButton'
export default {
extends: BaseComponent
components: {
Button
}
}
</script>
The Button of Child Component will be replaced OtherButton. We can do something in the OtherButton

Related

(Nuxt) Vue component doesn't show up until page refresh

I'm storing nav items in my Vuex store and iterating over them for conditional output, in the form of a Vue/Bulma component, as follows:
<b-navbar-item
v-for='(obj, token) in $store.state.nav'
v-if='privatePage'
class=nav-link
tag=NuxtLink
:to=token
:key=token
>
{{obj.text}}
</b-navbar-item>
As shown, it should be output only if the component's privatePage data item resolves to true, which it does:
export default {
data: ctx => ({
privatePage: ctx.$store.state.privateRoutes.includes(ctx.$route.name)
})
}
The problem I have is when I run the dev server (with ssr: false) the component doesn't show up initially when I navigate to the page via a NuxtLink tag. If I navigate to the page manually, or refresh it, the component shows.
I've seen this before in Nuxt and am not sure what causes it. Does anyone know?
recommendation :
use mapState and other vuex mapping helper to have more readable code :).
dont use v-for and v-if at the same element
use "nuxt-link" for your tag
use / for to (if your addresses dont have trailing slash)
<template v-if='privatePage'>
<b-navbar-item
v-for='(obj, token) in nav'
class=nav-link
tag="nuxt-link"
:to="token" Or "`/${token}`"
:key="token"
>
{{obj.text}}
</b-navbar-item>
</template>
and in your script :
<script>
import {mapState} from 'vuex'
export default{
data(){
return {
privatePage: false
}
},
computed:{
...mapState(['privateRoutes','nav'])
},
mounted(){
// it's better to use name as a query or params to the $route
this.privatePage = this.privateRoutes.includes(this.$route.name)
}
}
</script>
and finally if it couldn't have help you , I suggest to inspect your page via dev tools and see what is the rendered component in html. it should be an <a> tag with href property. In addition, I think you can add the link address (that work with refresh and not by nuxt link) to your question, because maybe the created href is not true in navbar-item.
NOTE: token is index of nav array . so your url with be for example yourSite.com/1.so it's what you want?
This question has been answered here: https://stackoverflow.com/a/72500720/12747502
In addition, the solution to my problem was a commented part of my HTML that was outside the wrapper div.
Example:
<template>
<!-- <div>THIS CREATES THE PROBLEM</div> -->
<div id='wrapper'> main content here </div>
</template>
Correct way:
<template>
<div id='wrapper'>
<!-- <div>THIS CREATES THE PROBLEM</div> -->
main content here
</div>
</template>

Angular: 7.2.14 - Yet Another Router Link Not Working Topic

Sorry to revive a question. Im using Angular 7 and Im trying to use Router Link.
This is my app-routing-module
const routes: Routes = [
{ path: 'locations' , component : LocationManagerComponent },
{ path: 'locations/create' , component : CreateEditLocationComponent },
{ path: 'locations/create/:id', component : CreateEditLocationComponent },
{ path: '404' , component : PageNotFoundComponent},
{ path: '**' , redirectTo: '/404'}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
This is router link:
<a [routerLink] = "['/locations']" routerLinkActive="active"> test link </a>
When I click on link, nothing happens. The URL on browser changed but component is not loaded.
If I press F5, component is loaded and from that point on, routers link works.
I've tryed a lot of stackoverflow solution like writing link in any sort of variant like
<a routerLink="/locations" ...
<a [routerLink]= ['/locations'] ...
<a [routerLink]= "['/locations']" ...
With or without LinkAttive attribute. Putting
<base href="/">
in index.html etc....
Following this topic: TOPIC I've tried to include Router in my Layout component:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-layout',
templateUrl: './layout.component.html',
styleUrls: ['./layout.component.css']
})
export class LayoutComponent implements OnInit {
constructor(
private route : ActivatedRoute
) { }
[...]
but nothing changes.
The strange part is that after an F5, all routes works, even route to component not yet loaded.
In this topic TOPIC 2 the user resolved removing css class. I've tried to put my link in a completely cleaned component HTML and it not working (but still works after a refresh).
<p>
dashboard works!
<a routerLink = '/locations' routerLinkActive="active"> test link </a>
</p>
UPDATE: This is layout.component where route tag is.
I can't figure out how to have a Sidenav without having route-outlet inside it.
<mat-sidenav-container fullscreen>
<mat-sidenav #sidenav mode="over">
<div class="profile_container">
<span> User Name </span>
</div>
<mat-nav-list>
<mat-list-item><a [routerLink]="['/locations']" routerLinkActive="active"> Locations
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<app-header (toggleSidenav)="sidenav.toggle()"></app-header>
<div style="padding: 20px 10px 10px 20px;">
<router-outlet></router-outlet>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
Note: this answer is based on the previous version of your question, before you added the code of layout.component.html. So, instead of layout component, I am using the simplified dashboard component.
The below is working for me in Angular 8.1.
app.component.html
<app-dashboard></app-dashboard>
means that the DashboardComponent is contained within (is the child of) the AppComponent.
No change to the default app.component.ts
dashboard.component.html
<p>
dashboard works!
<a routerLink = '/locations' routerLinkActive="active">
Locations test link </a>
</p>
<p><a routerLink = '/locations/create' routerLinkActive="active">
Locations/create </a></p>
<p><a routerLink = '/locations/create/:id' routerLinkActive="active">
Locations/create/:id </a></p>
<p>router-outlet is below:</p>
<router-outlet></router-outlet>
All the links are working with click and with manually entering the url (eg: http://localhost:4200/locations/create/:id) in the browser and with reload (F5).
New Components
Generated using the ng generate component command:
Dashboard
LocationManager
CreateEditLocation
PageNotFound
app-routing-module.ts
The same as your file, but also added import statements for the newly generated components.
I figured what cause the problem but I can't unserstand why and I was not able to reproduce in StackBlitz.
This was my app.component.html, the root of all app:
<main>
<!-- Showing All Site Pages -->
<span *ngIf='isLogged()'>
<app-layout style="height:100%"></app-layout>
</span>
<!-- Showing Login Page -->
<div *ngIf='!isLogged()'>
<router-outlet></router-outlet>
</div>
</main>
The App-Layout code is above.
THIS NOT WORKS!
I changed it with a simply:
<main>
<app-layout style="height:100%"></app-layout>
</main>
As you see from my question, Layout has its own router-outlet.
I think the problem is the two router-outlet tag. Maybe Angular is not able to understand thats they are mutually exclusive. Maybe when I was clicking on menu, for some reason, Angular was updating the "first" router-outlet encountered and only after a refresh (F5), when the isLogged was already triggered and the app-layout was loaded directly, Angular knows which router-outlet to use.
In the new Way all pages, even Login, has to be child of AppLayout so every Layout component that's exists only if logged, has to be manually hide with *ngIf='!isLogged()'
A little price to pay to have routes works.

Vuejs: shared components used on multiple pages disappeared

right now, I'm writing a single-page-application in vue.js using vue-router. Pages like the homepage, sign-in page etc. all share a navigation and footer component. On a few pages however, I need the entire screen so that the navigation and footer shall not be displayed.
Hence, I decided to nest components and include the navigation and footer component when necessary. My problems now is, that the navigation and footer template disappeared on all pages.
Edit: A more complete demo can be found in this Github repository.
Here's a simplified version of the files I'm using:
index.html:
<div id="app">
<router-view></routerview>
</div>
router.js:
import Homepage from './homepage.vue';
import SignIn from './signin.vue';
const router = new VueRouter({
routes: [
{path: '/', component: Homepage},
{path: '/signin', component: SignIn},
]
})
homepage.vue and signin.vue components:
<template>
<navigation></navigation>
// some page-specific content
<footer-vue></footer-vue>
</template>
<script>
import Navigation from './navigation.vue';
import Footer from './footer.vue';
export default {
components: {
'navigation': Navigation,
'footer-vue': Footer,
},
}
</script>
A component without navigation and footer:
<template>
// some page-specific content
</template>
Is it even possible to nest components this way? I hope someone is able to point me into the right direction.
Both homepage.vue and signin.vue have invalid templates. e.g.
<template>
<navigation></navigation>
<h1>The homepage</h1>
<footer-vue></footer-vue>
</template>
This is not allowed as it has 3 root nodes. See https://v2.vuejs.org/v2/guide/components.html#A-Single-Root-Element
You need to wrap it to get it to work:
<template>
<div>
<navigation></navigation>
<h1>The homepage</h1>
<footer-vue></footer-vue>
</div>
</template>
Note that this limitation does not apply to functional components and is also expected to be lifted for all components in Vue 3.
Much more worrying is that you're not seeing any errors messages for this. You really need to look into that as it suggests there's something very much amiss with your development setup.
An example of the error message you should be seeing:
new Vue({
el: '#app',
template: '<div></div><div></div>'
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
</div>

Using a component containing other components within a router-view in Vue.js

I am trying to build a layout using single-file components in Vue.js, with dynamic population and URLs using Vue-router. (I'm using the webpack template via vue-cli as well.)
It works as expected for my app.vue file-- containing the nav, sidebar, page head, and <router-view>-- and the <router-view> content appeared as expected when the correct <router-link> is clicked... until I tried to add subcomponents to the add-load component being called to the <router-view>. Now, nothing appears at all, despite not throwing any errors.
Admittedly, I am not basing my structure on any examples, as I couldn't really find any doing it the way I was hoping to. I wanted to use nested components by calling them like custom elements-- I think this makes the code much easier to read and maintain. I'm not entirely sure how to structure it otherwise, to be honest. Using multiple <router-view>s as siblings to each other seems counterintuitive to me.
I've tried a variety of combinations of how and where to import and call the components, and nothing has worked. The only way I can get any content to load is if I only call a single component for path: '/add-load'. Is it just impossible to use multiple components outside of your base app.vue? I find that hard to believe. Here's what I started with.
From my index.js:
import AddLoad from '#/components/AddLoad'
import AddLoad from '#/components/ProgressSteps'
import Stops from '#/components/Stops'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
components: {
Sidebar,
TopNav,
MobNav,
PageHead
}
},
{
path: '/add-load',
components: {
AddLoad,
ProgressSteps}
}
]
})
From my App.vue file (the multiple component behavior that I'd like to mimic is shown here):
<template>
<div id="app">
<div class="wrapper">
<Sidebar/>
<div class="container-fluid">
<TopNav/>
<MobNav/>
<div class="container-fluid">
<PageHead/>
<router-view></router-view>
</div>
</div>
</div>
</div>
</template>
<script>
import Sidebar from '#/components/Sidebar'
import TopNav from '#/components/TopNav'
import MobNav from '#/components/MobNav'
import PageHead from '#/components/PageHead'
export default {
name: 'App',
components: {
Sidebar,
TopNav,
MobNav,
PageHead
}
}
</script>
From my AddLoad.vue file:
<template>
<div class="add-load">
<div class="content-container container-slim">
<progress-steps/>
<router-link to="#stops">Stops</router-link>
<router-view></router-view>
</div>
</div>
</template>
<script>
import ProgressSteps from '#/components/ProgressSteps'
export default {
name: 'AddLoad',
component: ProgressSteps
}
</script>
Here is a link to a codesandbox, so you can see the full functionality. https://codesandbox.io/s/7k520xk0yq

Two different layouts in aurelia app

I'd like to use two separate layouts for my aurelia app. Difference between them is that one doesn't have a sidebar. Currently I'm using one layout file defined as below:
<template>
<div class="container">
<router-view></router-view>
</div>
</template>
If an active route needs this sidebar to appear I'm just putting it into its view.
What I'd like to achieve is to add another layout that would have this sidebar by default:
<template>
<require from="../common/elements/sidemenu/sidemenu"></require>
<div class="container">
<sidemenu></sidemenu>
<router-view></router-view>
</div>
</template>
So the question is - how to do this? Is it even possible with an aurelia app to have multiple layouts (or master pages, however you call those)?
Use aurelia.setRoot()
You can manually set up your application by specifying a script with configure instructions in your index.html. Typically, this is set to main.
index.html
<body aurelia-app="main">
In this script you can specify a root view model using aurelia.setRoot('root'). If no argument is provided, the convention is to use 'app'.
main.js
aurelia.start().then(() => aurelia.setRoot());
However, you can inject the aurelia object anywhere in your application, and call the setRoot function at any time to load a different root view model.
home.js
#inject(aurelia)
export class HomeViewModel {
constructor(aurelia) {
this.aurelia = aurelia;
}
doStuff() {
this.aurelia.setRoot('withSidebar');
}
}
One common use case for this is having a login page, and I've created a complete template for this use case that you can review, clone, or fork here: http://davismj.me/portfolio/sentry/

Categories

Resources