Modify sidebar component based on content section component in Vue - javascript

Here is my template section:
<template>
<!-- START Home.vue section -->
<div class="container-fluid" v-if="user.authenticated">
<!-- START Sidebar.vue section -->
<sidebar-component></sidebar-component>
<!-- END Sidebar.vue section -->
<div class="main-container">
<!-- START Nav.vue section -->
<nav-component></nav-component>
<!-- END Nav.vue section -->
<!-- START Content Section -->
<router-view></router-view>
<!-- END Content Section -->
</div>
</div>
<!-- END Home.vue section -->
</template>
Clearly it has 3 components: NavComponent,SidebarComponent, Main component area that will be replaced by the routed component.
I have another component ApplicationList component that when will replace the router-view section of above template, is supposed to cause the sidebar component to behave differently(say for example sidebar becomes hidden or its background becomes red).
So how do I do it?

Install https://github.com/vuejs/vuex-router-sync . It will give you your current route state in your Vuex.
In your <sidebar-component> just refer to this.$store.state.route.name (or path, or whatever you need) and use it in your v-if or some watch .
This is the easiest and most scalable solution to handle changes in components based on current route in application.
Hope it helps.

Related

Angular Material - Disable mat-sidenav transition animation but keep children animations?

I have an Angular app with a mat-sidenav that's structured like this:
<mat-sidenav-container>
<mat-sidenav [mode]="'side'">
<!-- Sidenav content -->
</mat-sidenav>
<mat-sidenav-content>
<!-- Main content -->
</mat-sidenav-content>
</mat-sidenav-container>
I'd like to disable the transition animation for the mat-sidenav but keep the sidenav content's animations (e.g. for a mat-vertical-stepper). However, I haven't been able to find a way to do this.
So far, I've found this similar GitHub issue, but the fixes described there seem to disable the sidenav content's animations too. For example, I've tried the following:
<mat-sidenav-container [#.disabled]="true">
<mat-sidenav [mode]="'side'">
<!-- Sidenav content -->
</mat-sidenav>
<mat-sidenav-content>
<!-- Main content -->
</mat-sidenav-content>
</mat-sidenav-container>
which disables the sidenav transition animation, but also disables all other animations. The following doesn't seem to work either:
<mat-sidenav-container [#.disabled]="true">
<mat-sidenav [mode]="'side'" [#.disabled]="false">
<!-- Sidenav content -->
</mat-sidenav>
<mat-sidenav-content [#.disabled]="false">
<!-- Main content -->
</mat-sidenav-content>
</mat-sidenav-container>
I've also found this article in Angular's documentation, but it seems very complicated and I can't figure out how to apply it to components without custom animations (like the mat-vertical-stepper).
Is there any easy way to disable a mat-sidenav's transition animation while still keeping its children's animations?
This is a workaround.
Temporarily disable it.
Demo
in HTML:
<mat-sidenav-container [#.disabled]="temporaryDisabled">
<mat-sidenav [mode]="'side'" #sidenav>
Sidenav content
</mat-sidenav>
<mat-sidenav-content>
<div class="header">
<button mat-stroke-button (click)="toggle()">toggle sidenav</button>
</div>
<div class="stepper">
<mat-vertical-stepper [linear]="isLinear" #stepper >
(... stepper codes ...)
</mat-vertical-stepper>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
in .ts file:
temporaryDisabled: boolean = false;
toggle(){
this.temporaryDisabled = true;
this.sidenav.toggle();
setTimeout(()=>{
this.temporaryDisabled = false;
},10);
}
using Angular module `NoopAnimationsModule`
1 Import
import {NoopAnimationsModule} from '#angular/platform-browser/animations';
2 ensure you add it to NgModule
#NgModule({
imports: [NoopAnimationsModule]...
})
export class YourMaterialModule { }
To remove animation/transition on some specific components you can also do it via CSS like this
.mat-sidenav{ transition: none; }
Check out this for disableRipple or this answer

Use a component to render each Vuetify expansion panel item

I'm trying to using Vuetify's v-expansion-panel component (AKA accordion) to render one panel for each task in a list. The parent component's template is:
<div v-if="tasks.length">
<v-expansion-panels>
<task
v-for="(task, index) in tasks"
:task="task"
:key="index"
/>
</v-expansion-panels>
</div>
Then the child task component renders the content of each panel like so:
<template>
<v-expansion-panel>
<v-expansion-panel-header>
<!-- render panel header content -->
</v-expansion-panel-header>
<v-expansion-panel-content>
<!-- render panel body content -->
</v-expansion-panel-content>
</v-expansion-panel>
</template>
It's convenient for me to render the header and body in a single component, because they largely depend on the same data. However, I don't like the way that the markup for the expansion panels is split over two different components. Because of this, if I unit test the child task component I get a warning:
[Vuetify] The v-expansion-panel component must be used inside a v-expansion-panels
Is there a way I can move all the expansion panel markup into the parent component, but generate the content for v-expansion-panel-header and v-expansion-panel-content in the child task component?
Why not just add all expansion panels together and in task.vue do the v-for?
<task :tasks="tasks" />
Task.vue
<template>
<v-expansion-panels
<v-expansion-panel
v-for="(task, index) in tasks"
:task="task"
:key="index">>
<v-expansion-panel-header>
<!-- render panel header content -->
</v-expansion-panel-header>
<v-expansion-panel-content>
<!-- render panel body content -->
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</template>
You can have multiple root elements in Vue 2 using render functions. It is more tricky to use but it would work. Take a look at this link.
Alternatively, you can use the vue-fragment component (link to npm page) that does it for you like so:
<template>
<fragment>
<v-expansion-panel-header>
<!-- render panel header content -->
</v-expansion-panel-header>
<v-expansion-panel-content>
<!-- render panel body content -->
</v-expansion-panel-content>
</fragment>
</template>

Angular lazy load modules from main component

I have the below setup in my app.routing.module.ts.
app.component.html
<router-outlet></router-outlet>
modules/core/components/home/home.component.html
<mat-sidenav-container autosize>
<mat-sidenav #sidenav role="navigation">
<!--this is a place for us to add side-nav code-->
<wn-sidenav-list (sidenavClose)="sidenav.close()"></wn-sidenav-list>
</mat-sidenav>
<mat-sidenav-content>
<!--in here all the content must reside. We will add a navigation header as well-->
<wn-header (sidenavToggle)="sidenav.toggle()"></wn-header>
<main>
<!-- I want the components child components of the home components to be loaded here -->
<router-outlet></router-outlet>
</main>
<wn-footer></wn-footer>
</mat-sidenav-content>
Problem
When I access localhost:4200/campaigns or localhost:4200/dashboard their respective components are displayed but they aren't using their parent's (home.component.html) view
My Goal
I want all sub-components of the home component to be displayed in the router-outlet of the home.component.html and other components will be displayed in the router-outlet of app.component.html
I've had a setup like this before but I wasn't using modules at the time and it was working perfectly. Is there something about lazy loading that I don't understand?
When I access localhost:4200/campaigns or localhost:4200/dashboard the
components of the campaign module are displayed but they aren't using
their parent's (home.component.html) view
In your route config you are using redirectTo:'/dashboard' so that's why you will see the view of campaign modue

Vue: Mysterious ghost props?

In my project, I came across the following code:
Parent component - <ParameterModal>:
<template>
<modal-wrapper props="...">
<!-- ... other templates similar to this... -->
<template v-else-if="modalTemplate === 'bitmask_set'">
<template slot="header">
<h4 class="center-text">{{title}}</h4>
</template>
<div v-if="errorMessage" class="error-message">
{{errorMessage}}
</div>
<ModalBitmaskSet
v-bind="modalMeta"
:setErrorMessage="setErrorMessage"
:clearErrorMessage="clearErrorMessage"
/>
</template>
<!-- ... -->
<div v-else>
Warning: unmapped modal template!
</div>
<!-- ... -->
</modal-wrapper>
</template>
Ok, cool, this is using a regular slot and named slot to display a component called <ModalBitmaskSet>. So I look inside modal-wrapper to find the outlets...
Child component - <modal-wrapper>
<template>
<!-- some container and wrapper elements and then... -->
<div class="modal-header">
<slot name="header" />
</div>
<div
:class="['modal-body', 'display-flex', 'flex-direction-column', modalTemplate]"
>
<div
id="escape_message"
style="text-align: center; display: none; padding-bottom: 10px;"
>
You have unsaved changes.<br />Please click Save or Cancel to proceed.
</div>
<md-content v-if="modalContent">{{modalContent}}</md-content>
<slot />
</div>
<!-- end containers and wrappers -->
</template>
Also cool, there is where the slots are coming out... but how are props being passed to <ModalBitmaskSet>? When I look in Vue DevTools, I can see that props are somehow being passed to this component that don't exist in the parent. On top of this, when I add new components to <ParameterModal>, they sometimes don't get passed props that other components seem to be getting! This is very weird!
As you can see from the photo, this component is somehow getting passed props that aren't listed in the code! Specifically, the props colIndex, fieldSet, indexOffset, methodIndex and rowIndex in this case, although other components on this <ParameterModal> component appear to get different props.
Am I missing something? Where could these ghostly props be coming from?
This line seems the likely cause, though without seeing the code for modalMeta it's difficult to be sure:
v-bind="modalMeta"
This is using the object v-bind syntax, so whatever properties exist in the modalMeta object will be passed as props to the component.
See:
https://v2.vuejs.org/v2/guide/components-props.html#Passing-the-Properties-of-an-Object
https://v2.vuejs.org/v2/api/#v-bind

Angular 2 how to render HTML in my header based on the current route

Basically, I have 3 routes and 3 different things I want to show based on which route I am currently on:
When route is /, I want to show in my header a link to FAQ.
When route is /browse I want to show in my header a Search input.
When route is /photo:id I want to show in my header a Add Favorite button.
So in my header code, which right now is just the below code, how can I handle those cases?
<div id="header">
<!-- if route is / then just <a routerLink="/faq">FAQ</a> -->
<!-- if route is /browse then just <input type="text"> -->
<!-- if route is /photo:id then just <button>Add</button> -->
</div>

Categories

Resources