I have navigation component like this:
<template>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="">Website Builder</a>
</div>
<div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav">
<li>
Create
</li>
<li>
How
</li>
<li>
About
</li>
<li>
Videos
</li>
</ul>
</div>
</div>
</nav>
</template>
and my js:
Vue.component('navigation', Navigation)
Vue.component('create', Create)
Vue.component('how', How)
Vue.component('about', About)
Vue.component('youtube', Youtube)
new Vue({
el: '#app',
data: {
currentView: 'create'
}
and html:
<div id="app">
<navigation></navigation>
<keep-alive>
<transition name="slide-fade" mode="out-in">
<component :is="currentView"></component>
</transition>
</keep-alive>
</div>
However when I click on navigation, it doesn't change therefore I am assuming it's not working properly. if I put navigation away from component and stick it in div id=app it works fine, why is this happening?
The .native modifier is not necessary on native elements - it can only be used on component elements. Remove it.
It seems you want to change data in the root component. Your current code changes data in the navigation component.
Two ways to do this:
1) The clean way:
In the navigation component, we emit an event with the new value to the parent:
<a href="#" #click="$emit('current-view', 'youtube')">
in the parent (here, the root) component, we receive the event and set the value:
<navigation #current-view="currentView = $event"></navigation>
2) The hacky way:
<a href="#" #click="$root.currentView='youtube'">
Related
I created a recipe website, you can find it here https://hungry-vegetarian.com/.
The tab on the index page is a vue instance. I'm trying to create a search bar that is also a vue instance.
The problem occurs when I try to display searched recipes on the index page. It just shows the search result on top of the search bar.
Ideally, only searched recipes should appear on the tab just like they are now but without any indications on top of the tab like Breakfast, Salad, Bakery, etc.
I don't know how to make two objects work together. For now, they work separately without communicating with each other.
SEARCH
<div id="search">
<div class="main-search">
<h1 class="search-question">What are you in the mood for?</h1>
<div class="search-box">
<input type="text" v-model="searchQuery" class="input-search" placeholder="Bread">
<button class="btn-search"><i class="fa fa-search"></i></button>
</div>
</div>
<div class="container">
<div class="recipe" v-for="post in filteredList">
<div v-if="searchQuery">
<a v-bind:href="post.url" class="recipe-card__card-link" target="_blank">
<img v-bind:src="post.image" alt="" class="recipe-card__image"/>
<div class="recipe-card__text-wrapper">
<h2 class="recipe-card__title">{{post.name}}</h2>
<div class="recipe-card__details-wrapper">
<p class="recipe-card__excerpt">{{post.body}}</p>
<a v-bind:href="post.url" class="recipe-card__read-more">Read more <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
tab
<main id="tab">
<header>
<nav>
<ul>
<div id="arrow">
<span></span>
<span></span>
<span></span>
</div>
<li v-for="(tab, tabName) in tabs" :key="tabName">
<button class="tab" #click="setTabActive(tabName)" :class="{'active': tabName === activeTab}">
<span class="tab-copy">{{ tabName }}</span>
<span class="tab-background">
</span>
</button>
</li>
</ul>
</nav>
</header>
<article>
<div class="container">
<transition name="fade" mode="out-in" appear :duration="500">
<tab-content v-for="(tabContent, t) in tabs" :data="tabContent" :key="'content'+t" v-if="t === activeTab" inline-template>
<div class="content-wrapper">
<div class="recipes" v-for="(recipe, i) in data.recipes" :key="i">
<a v-bind:href="recipe.url" class="recipe-card__card-link"></a>
<img :src="recipe.image" alt="" class="recipe-card__image">
<div class="recipe-card__text-wrapper">
<h2 class="recipe-card__title">{{recipe.name}}</h2>
<div class="recipe-card__details-wrapper">
<p class="recipe-card__excerpt">{{recipe.body}}</p>
<a v-bind:href="recipe.url" class="recipe-card__read-more">Read more <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
</div>
</tab-content>
</transition>
</div>
</article>
</main>
I tried to combine instances search and tab into just one instance tab, but it always gives me a Vue warning:
[Vue warn]: Property or method "searchQuery" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
Also, I feel like I can have just the wrong approach to this problem I am trying to solve. Please, any suggestions are welcome. I am stuck.
I have a HomeNavbar.vue component that has my Navbar links (I'm using Vue-Router).
HomeNavbar.vue:
<template>
<div>
<b-container fluid>
<b-row>
<b-col>
<nav class="navbar navbar-expand-lg">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarTogglerDemo01">
<a class="navbar-brand logo" href="/"></a>
<ul class="navbar-nav ml-auto mt-2 mt-lg-0">
<li class="nav-item">
<router-link to="/" class="nav-link">Home</router-link>
</li>
<li class="nav-item">
<router-link to="/about" class="nav-link">About</router-link>
</li>
<li class="nav-item">
<ScrollToLink
href="#features"
class="nav-link"
>Features
</ScrollToLink>
</li>
<!-- <li class="nav-item">-->
<!-- <router-link to="/pricing" class="nav-link">Pricing</router-link>-->
<!-- </li>-->
<li class="nav-item">
<router-link to="/faqs" class="nav-link">FAQ's</router-link>
</li>
<li class="nav-item">
<router-link to="/contact" class="nav-link">Contact</router-link>
</li>
</ul>
</div>
<!-- <a class="nav-link" id="searchBox"><i class="fa fa-search"></i></a>-->
</nav>
</b-col>
</b-row>
</b-container>
</div>
</template>
<script>
import ScrollToLink from '../components/ScrollToLink';
export default {
name: "HomeNavbar",
components: {
ScrollToLink
}
}
</script>
As you can see I created a simple component for smooth scrolling called ScrollToLink.vue,
that is being used in the code above.
ScrollToLink.vue:
<template>
<a :href="href" #click.prevent="scroll">
<slot></slot>
</a>
</template>
<script>
export default {
name: "ScrollToLink",
props: ['href'],
methods: {
scroll() {
document.querySelector(this.href)
.scrollIntoView({ behavior: 'smooth' });
}
}
}
</script>
<style scoped>
</style>
The code works well when I'm on the Home page, which contains the features section with the id="#features" where it will scroll down to.
But if I click on About page, and then click on Features button it points to http://highrjobsadminlte.test/about#features, instead of this http://highrjobsadminlte.test/#features.
How can I get it to link back to /#features via the Home page?
When I click nav link on navbar it does not collapse.
Vue version 2.6.10.
<template>
<div class="nav-wrapper">
<nav>
<ul>
<li v-for="(route, index) in routings" :key="index">
<router-link :to="route.url">{{route.name}}</router-link>
</li>
<li>
Blog
</li>
<li class="visible-xs">
<Button v-if="!isLoggedIn" :label="loginButtonLabel" :isFilled="true" :action="goToLogin"/>
<UserWidget v-else :email="setFirstName" :title="'administrator'" :isUserMenu="true" :action="gotoDashboard"/>
</li>
</ul>
</nav>
</div>
</template>
This is the navbar what i talk about
This is the header part of the code. When click on the hamburger icon class 'mobile-menu-wrapper visible-xs' this will change to 'mobile-menu-wrapper visible-xs expanded'. There for I think it will be change to previous class its solve the matter. Please advise me to find the issue.
<template>
<div class="header-wrapper">
<div class="header-container container">
<Logo/>
<Nav class="hidden-xs" :routings="routings"/>
<Button v-if="!isLoggedIn" class="hidden-xs" :label="isLoggedIn ? 'Console' : 'Login / Sign-up'" :isFilled="true" :action="goToLogin"/>
<UserWidget class="hidden-xs" v-if="isLoggedIn" :email="setFirstName" :title="'administrator'" :isUserMenu="true" :action="gotoDashboard"/>
<div class="mobile-menu-icon-wrapper visible-xs" #click="getMobileMenu">
<i v-if="isMenuExpanded" class="mobile-menu-icon close-icon"></i>
<i v-if="!isMenuExpanded" class="mobile-menu-icon expand-icons"></i>
</div>
<div class="mobile-menu-wrapper visible-xs" :class="{'expanded': isMenuExpanded}">
<div class="menu-overlay" #click="getMobileMenu"></div>
<Nav :routings="routings" :eventBus="eventBus" :adminDetails="adminDetails" :isLoggedIn="isLoggedIn"/>
<div class="mobile-menu-icon-wrapper" #click="getMobileMenu">
<i v-if="isMenuExpanded" class="mobile-menu-icon close-icon"></i>
</div>
</div>
</div>
</div>
</template>
Try to add an onclick event in your router link to close the navigation bar, I don't see the code that you're using to open/close the nav, but you can emit an event like this:
Let's listen for the event closeNav in the parent component, by adding #closeNav in the Nav component:
<template>
<div class="header-wrapper">
<div class="header-container container">
<Logo/>
<Nav class="hidden-xs" :routings="routings"/>
<Button v-if="!isLoggedIn" class="hidden-xs" :label="isLoggedIn ? 'Console' : 'Login / Sign-up'" :isFilled="true" :action="goToLogin"/>
<UserWidget class="hidden-xs" v-if="isLoggedIn" :email="setFirstName" :title="'administrator'" :isUserMenu="true" :action="gotoDashboard"/>
<div class="mobile-menu-icon-wrapper visible-xs" #click="getMobileMenu">
<i v-if="isMenuExpanded" class="mobile-menu-icon close-icon"></i>
<i v-if="!isMenuExpanded" class="mobile-menu-icon expand-icons"></i>
</div>
<div class="mobile-menu-wrapper visible-xs" :class="{'expanded': isMenuExpanded}">
<div class="menu-overlay" #click="getMobileMenu"></div>
<!-- here is part of the magic -->
<!-- alternative one, update isMenuExpanded directly -->
<Nav :routings="routings" :eventBus="eventBus" :adminDetails="adminDetails" :isLoggedIn="isLoggedIn" #closeNav="isMenuExpanded = false"/>
<!-- alternative two, update isMenuExpanded using the closeNavBar method -->
<!--<Nav :routings="routings" :eventBus="eventBus" :adminDetails="adminDetails" :isLoggedIn="isLoggedIn" #closeNav="closeNavBar"/> -->
<div class="mobile-menu-icon-wrapper" #click="getMobileMenu">
<i v-if="isMenuExpanded" class="mobile-menu-icon close-icon"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
...
methods: {
// alternative using method
closeNavBar() {
this.isMenuExpanded = false;
}
}
...
}
</script>
The navbar component will emit the event once the user clicks on any router-link (you can add the event in any other link or button)
<template>
<div class="nav-wrapper">
<nav>
<ul>
<li v-for="(route, index) in routings" :key="index">
<!-- emit the event to close the navBar -->
<!-- emit directly in the tag -->
<router-link :to="route.url" #click="$emit('closeNav')">{{route.name}}</router-link>
<!-- emit by using a method -->
<!--<router-link :to="route.url" #click="closeNavBarFromChild">{{route.name}}</router-link>-->
</li>
<li>
Blog
</li>
<li class="visible-xs">
<Button v-if="!isLoggedIn" :label="loginButtonLabel" :isFilled="true" :action="goToLogin"/>
<UserWidget v-else :email="setFirstName" :title="'administrator'" :isUserMenu="true" :action="gotoDashboard"/>
</li>
</ul>
</nav>
</div>
</template>
<script>
...
methods: {
closeNavBarFromChild() {
this.$emit('closeNav') // Emit the event that the parent is listening
}
}
...
</script>
I wrote two ways to use events, but they have the same effect.
I have this Vue instance as
document.addEventListener('DOMContentLoaded', () => {
if(document.getElementById("app")){
const node = document.getElementById('app');
const props = JSON.parse(node.getAttribute('current_user'));
const app = new Vue({
el: '#app',
router,
template: '<App />',
components: { App }
}).$mount('#app');
}
});
The data is in const props which contains user details such as email and password, it's in JSON form.
I have another component registered as
import CurrentUser from "../components/shared/CurrentUser";
Vue.component("v-current-user", CurrentUser);
And its been called in header. such as
<template>
<header class="app-header navbar">
<button class="navbar-toggler sidebar-toggler d-lg-none mr-auto" type="button" data-toggle="sidebar-show">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="#">
<img class="navbar-brand-full" src="/images/evercam-logo-2.png" alt="Evercam Logo">
<img class="navbar-brand-minimized" src="/images/Favicon-300.png" width="30" height="30" alt="Evercam Logo">
</a>
<button class="navbar-toggler sidebar-toggler d-md-down-none" type="button" data-toggle="sidebar-lg-show">
<span class="navbar-toggler-icon"></span>
</button>
<v-current-user />
</header>
</template>
All I want to do is to pass this props in such a way that any child component will receive it as well as I can send it to <v-current-user /> and can get the values in that component where I am using this current user
<template>
<ul class="nav navbar-nav ml-auto">
<li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
<v-gravatar email="junaid#evercam.io" class="img-avatar" :size="40" />
</a>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" href="/users/sign_out">
<i class="fa fa-lock"></i> Logout
</a>
</div>
</li>
</ul>
</template>
in <v-gravatar> for email.
Sorry fo ambiguous questions I am a total newbie to Vuejs right now
I followed the examples for setting up a nav-bar.html and a nav-bar.js in the Aurelia tutorial. Later, I wanted to add some functionality to the nav-bar.js VM but found that non of it's properties or methods are ever called.
I'm trying to use Aurelia Auth filtering on my top navigation, but even when omitting the auth functionality, nothing in top-nav-bar.js is ever called.
Code below:
top-nav-bar.js
import {bindable} from 'aurelia-framework';
import {inject} from 'aurelia-framework';
import {AuthService} from 'aurelia-auth';
//import {AuthFilterValueConverter} from './authFilter';
//import {Router} from 'aurelia-router';
#inject(AuthService )
export class TopNavBar {
_isAuthenticated=false;
#bindable router = null;
constructor(auth){
console.log('called nav bar constructor'); //NEVER CALLED
this.auth = auth;
}
//#computedFrom(this.auth)
get isAuthenticated(){
return this.auth.isAuthenticated(); //NEVER CALLED
}
}
top-nav-bar.html
<template>
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<!-- <require from="paulvanbladel/aurelia-auth"></require> -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">
<i class="fa fa-home"></i>
<span>${router.title}</span>
</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li repeat.for="row of router.navigation | authFilter: isAuthenticated" class="${row.isActive ? 'active' : ''}">
<a data-toggle="collapse" data-target="#bs-example-navbar-collapse-1.in" href.bind="row.href">${row.title}</a>
</li>
</ul>
<ul if.bind="!isAuthenticated" class="nav navbar-nav navbar-right">
<li>Login</li>
</ul>
<ul if.bind="isAuthenticated" class="nav navbar-nav navbar-right">
<li>Profile</li>
<li>Logout</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="loader" if.bind="router.isNavigating">
<i class="fa fa-spinner fa-spin fa-2x"></i>
</li>
</ul>
</div>
</nav>
</template>
app.html
<template>
<require from="./top-nav-bar.html"></require>
<require from="bootstrap/css/bootstrap.css"></require>
<top-nav-bar router.bind="router"></top-nav-bar>
<div class="page-host">
<router-view></router-view>
</div>
</template>
If you have aurelia VM with js and html you need to import it to the view like (without *.html):
<require from="./top-nav-bar"></require>
Sometimes you do not have VM for the view, in that case you import just the html, like you do:
<require from="./top-nav-bar.html"></require>