So I have many components which have a sidebar and navbar code written in all of them except one component. So I did the reasonable thing and made both of them(sidebar and navbar) separate components.
Now if I import them in App.vue, it shows in all the components including the one I don't need them in.
How do I go about it? Btw, the App.vue is my central point and where I'm loading router-view from
As answered by #Badgy
Make a v-if="$route.path !== 'yourpathwhereyoudontwantthenavbar
Example:
// this will not display the sidebar on the register page
<Sidebar v-if="$route.path !== '/register'" />
Another Alternative by myself:
Define where you want these components to appear in the meta options of your route objects https://router.vuejs.org/guide/advanced/meta.html. It's more or less just a way to attach arbitrary information which you can fetch from the current route to determine e.g. your layouting
const router = new Router({
routes: [
{
path: '/users',
name: 'users',
component: Users,
meta: { sidebar: true, navbar: true },
},
},
})
// This will make the sidebar appear in the user page
<sidebar v-if="$route.meta.sidebar">
You can do <sidebar v-if="!$route.meta.sidebar"> if you don't want it just in 1 component
Related
I have the following problem, I haven't been able to find a solution to this:
I have a list of videos(they are played on the listing page) when I load a listing page
<ion-col class="category-item travel-category" size="12" *ngFor="let item of videos"
[routerLink]="['/app/video-admin/details', item.IdVideo]">
<app-video-player [videoId]="item.IdVideo">
</app-video-player >
</ion-col>
So what I need is to continue playing the video that is selected when it goes to the video detail page, Since the video is already playing I don't want to connect to the webrtc source again, it would take about 10 seconds to re-connect, how could I reuse the (app-video-player) component in the detail page "/app/video-admin/details" and keeping its state?
The easiest would be to reconnect and search where it was when clicked, but that means reconnection and searching where it was on the previous page(route) but that is exactly what I want to avoid, I think that's not a good solution.
The detail layout would have more controls, and basically only the selected video running
Any idea guys? thanks
You would need to design the layout such that the video player component is not destroyed when navigating to the new route.
That means your route should not be navigating to a new component, but rather it should be navigating within a component that contains both a video player and a details component. Any component can have a router outlet in it, and you can use child routes to navigate.
It's not clear what you want the layout to be, but here's the simplest example, with the details component underneath the list of videos:
Component HTML
<ion-col class="category-item travel-category" size="12" *ngFor="let item of videos"
[routerLink]="['details', item.IdVideo]">
<app-video-player [videoId]="item.IdVideo">
</app-video-player >
</ion-col>
<router-outlet></router-outlet>
Routing Module
const routes: Routes = [
{
path: 'app/video-admin',
component: VideoAdminComponent,
children: [
{
path: 'details/:id',
component: VideoDetailsComponent,
},
],
},
];
Obviously this isn't the layout you want, but this should give you the general knowledge to follow through with what you actually want.
Docs: https://angular.io/guide/router#nesting-routes
I am stuck trying pass data from Child A ($emit) component to Parent and from Parent to Child B (props).
Using nuxt.js I have:
layouts/default.vue
This default template will load a lot of components.
Those components will be used or not based on variable from child, the variable will set the v-if directive.
The children are the pages like:
pages/blog/index.vue
pages/about/index.vue
...
The goal is the Child set on Parent what components would be used, the flag can change anytime, the user can choose what will be rendered on admin area.
I have tried use local computed methods on child component, and vuex, no luck with both.
The idea on layouts/default.vue.
<template>
<div>
<TopBar v-if=showTopBar></TopBar>
<Nav v-if=showNav></Nav>
etc...
<nuxt />
</div>
</template>
<script>
import TopBar from "../components/TopBar";
import Nav from "../components/Nav";
etc...
export default {
data() {
return {
showTopBar: false,
showNav: false
etc...
};
},
}
</script>
On child already have use the $emit but no luck.
Child on this situation are pages, and the layout of those pages will be defined by variable from a fetch on the API, user can change the layout anytime.
The goal is have someting like double way between Child Components, example:
Calling route /blog will call pages/blog/index.vue
This would send to layout/default.vue using $emit what components would be rendered (choosed from user in admin area and fetched from API) and the component ID. (example: {topBar: true, topBarID: 2})
On layouts/default.vue after get the $emit from pages/blog/index.vue I would have for example TopBar false, and then not render it, or have received true with an ID, this Id will be send to TopBar as prop for render the customized TopBar made by user on Admin area.
Would be possible someone show an example how to get the pass those data for this specific cenario please?
(Does not matter if using local variables from the Child component or vuex, just looking for an example how to get the contents of variable from Child instead an plain object or undefinied object).
PS.: If there an better approach to deal with dynamic layouts, I am accepting suggestions too.
PS2.: I know I would use specific template per page, like layout/blog and layout/contact, etc... but since the idea is make an CMS, this would not fit on this scenario, I mean, from the admin area user should be able to create pages enabling or disabling components through an page Wizard (the idea is getting something like Wix, every component customization from user will be stored in the database using an Id, and on layouts user choose the previous components mounting the page, in the end all call will be made using the ids of those), and not need to add specific layouts programing, because this the Idea of set all possible components and layouts in layout/default.vue sounds at this moment an better approach, but if is not, I would love see other ways to get same goal.
The correct way to do it would be:
<child-component-1 :showNav.sync="showNav">
And within the child component you would update that by doing:
this.$emit('update:showNav', value)
The parent would define this property:
data() {
return {
showNav: default_value
}
}
You would have to pass that variable to every child component. Every child component would have to define it as a property.
Perhaps a better way to do it would be to instead create a simple store within nuxt and use that to house the settings.
I have a project, first it's just a normal SPA, but then I have to merge another Vue project to it, it leads to css conflicts...
Now I have a router like this:
{
path: '/admin',
name: 'Home',
component: MainContainer,
redirect: '/admin/posts/list',
children: .....
},
{
path: '/',
component: Container,
children: .....
}
It means I have 2 systems in 1 Vue app, but using different CSS. My attemp is use scoped css for the main component - here is MainContainer and Container. But using scoped style make the style not affect to these child component. Is there anyway for children of MainContainer only use style1.css and Container only use style2.css? If I delete scoped, the style of style1.css also affect Container and so on
I can check the vue router and reload the page to clean the old css when page change from MainContainer => Container or reverse, but it seems not to be the right way to do.
I created a new Angular 7 app using the Angular CLI. I left the configuration/setup the default and started adding my code on-top of it. The AppComponent makes a service call to fetch some blog posts and pass them to a child component that renders them.
app.component.html
<div class="container">
<header class="header-site">
<p class="site-title">Sully<p>
<p class="site-tagline">Code-monkey</p>
<p class="site-description">A sotware development blog with a touch of tech and a dash of life.</p>
</header>
<div *ngFor='let post of posts'>
<app-blog-post [post]="post"></app-blog-post>
</div>
</div>
<router-outlet></router-outlet>
app.component.ts
#Component({selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css']})
export class AppComponent {
posts: Post[];
constructor(private blogService: BlogService) {}
async ngOnInit() {
await this.loadPosts();
}
async loadPosts() {
this.posts = await this.blogService.getPosts();
}
}
This loads the first 10 posts and renders them with my app-blog-post child component.
blog-post-component.html
<article>
<header>
<h1 class="post-title"><a [routerLink]="['/blog', post.path]">{{post.title}}</a></h1>
<h4 class="post-details">{{post.details}}</h4>
</header>
<div>
<markdown ngPreserveWhitespaces [data]="post.content">
</markdown>
</div>
</article>
blog-post-component.ts
#Component({
selector: 'app-blog-post',
templateUrl: './blog-post.component.html',
styleUrls: ['./blog-post.component.css']
})
export class BlogPostComponent implements OnInit {
#Input() post: Post;
}
What happens is that it renders the first 10 blog posts as expected. Now, in the app-routing.module.ts class, I've added /blog/:id as a route, which my child component routes to when you click the post title.
const routes: Routes = [
{
path: 'blog/:id',
component: BlogPostComponent
}
];
I don't understand the routing mechanics here. When I navigate to the post, via the router, nothing happens. I see the URL path change in the browsers URL bar, but the content doesn't change.
What I'm trying to do is replace the 10 posts in the current view with the single post that's already been fetched as the only post on the page, when I hit that specific route. I've read through the docs but can't tell how to replace the content already in the view, with a subset of that content using the component already created. I'm not sure if I have to move the rendering of 10 posts off to a unique route, and just keep the router-outlet as the only element in the app.component.html, and for the '/' route, route to the component containing the top 10 posts. I'm worried that makes sharing the post data I've already fetched, between sibling components, more difficult as the parent now has to push/pull between the two children. Is that a backwards way of handling it?
Further still, each blog post has a unique route. I'm porting my blog from an existing hosted service where the path to a post is /blog/year/month/day/title. Can my Routes object be as simple as /blog/:year/:month/:day/:title? Since I can't get the routing working, I'm unable to test the routing itself and see if that's doable. I want to keep the same routing so existing bookmarks and search engine result links aren't broken.
When you utilise the routing mechanism, the specified component gets rendered in the appropriate router-outlet. I suspect that what you see when you navigate to a route, is the selected post rendered at the very bottom of the page.
As you allude to, if you would like to render the list of default blog posts, you will need to create a separate route/component for it, letting the router-outlet render it for you.
The way the routing works, is by going through each entry in your routes list and checking the current path for a match. This means the order is important. If you want to track both /blog/:year/:month/:day/:title and blog/:id, you will want to order them most specific first. And if you want an empty URL to point to a landing page, as you have above you could put something like { path: '', pathMatch: 'full', [component/redirectTo] } at the bottom of your route list.
I'm pretty new to React and Redux so I may be doing this completely the wrong way, in fact judging from a few other answers to similar questions on here I suspect I'm doing quite a lot wrong.
I've got a button in my 'Layout' component which adds a class to a div, this class comes from a state. The button is a toggle and will turn the state & class on and off (this will result in making a menu appear and dimming the rest of the page).
However I also want any interaction with the 'Nav' component (which lives inside a 'Header' component which in turn lives in 'Layout') to also toggle the state & class (so clicking a link collapses the menu). In jQuery/VanillaJS this was incredibly easy but I can't seem to work out the React/Redux way of doing this.
Layout Component: https://pastebin.com/WzpbeSw7
Header Component: https://pastebin.com/c34NFtUx (probably not relevant but here for reference)
Nav Component: https://pastebin.com/EsJDuLQc
By using redux :
You can have a state like toggleBlaBla : "show" . If you connected your react component to state of redux by using react-redux , whenever you dispatch an action for changing toggleBlaBla to "hide", your connected component will rerender.
By using only react :
If you want two components to change some ui state by some events, it is a good idea to put them in a container component, so that whenever your state changes these two components rerender with your changed state passing to both components.
One way to achieve this is to do the following:
In Layout component:
On line 26 change <Header / > to: <Header handleNavClick={this.toggleNav.bind(this)} / >
In Header component:
On line 10 change <Navigation position="header" /> to: <Navigation closeNav={this.props.handleNavClick.bind(this)} position="header" />
In Navigation component:
On line 16 change return <li key={item._id}><Link to={item.slug}>{item.name}</Link></li> to: return <li key={item._id}><Link to={item.slug} onClick={this.props.closeNav.bind(this)}>{item.name}</Link></li>
Passing the props in this way will allow you to reference reference the toggleNav function inside of Layout and then will update the state accordingly.
*** Note, you may get a binding error such as React component methods may only be bound to the component instance..
If this happens, you will need to define a function on the Navigation component instead of using this.props.closeNav directly. You would need to create a function in Navigation like this: closeNav() { this.props.closeNav.bind(this) }. Don't forget to update the function on the <Link /> component to this.closeNav.bind(this)