#click not firing on header links for vue.js - vue.js

I want to change a masthead text to the current route name that I am on. It only works on component mount, and does not fire on click. How do I get the changeHeaderTitle to run from the button click created by the router?
<template>
<div>
<nav class="navigation--navbar">
<router-link
class="navigation--links"
v-for="routes in links"
v-bind:key="routes.id"
#click='changeHeaderTitle'
:to="`${routes.page}`"
>{{routes.text}}</router-link>
</nav>
<div class="header--headline">
<h2 class="header--headline-text">{{headerTitle}}</h2>
</div>
</div>
</template>
<script>
export default {
name: 'Navigation',
data () {
return {
headerTitle: 'Boop',
links: [
{
id: 0,
text: 'Home',
page: '/Home'
},
{
id: 1,
text: 'Tutoring',
page: '/Tutoring'
}
]
}
},
methods: {
changeHeaderTitle: function () {
if (this.$route.path === '/') {
this.headerTitle = 'Home Header Here'
} else {
let routeName = this.$route.path.split('/')
this.headerTitle = routeName[1]
}
}
},
mounted: function () {
this.changeHeaderTitle()
}
}
</script>

Looks like you need to add .native modifier. Do:
<router-link
class="navigation--links"
v-for="routes in links"
v-bind:key="routes.id"
#click.native='changeHeaderTitle'
:to="`${routes.page}`"
>
{{routes.text}}
</router-link>

Related

How to make a function from another brother component be called when pressed?

Good afternoon, tell me please, I wrote a calendar displaying the events that the user sets, and now I want to make a detailed display of the event when I click it. The problem is that the events are in my component and the whole display logic is in another, how can I use them together.I want to make it so that the getDetailInformation() function in the ModalWindowDetail component component is called by clicking on an event in another component Calendar.vue. I use the event bus, but nothing works for me, I don’t understand why. Please help me solve this problem.
Screenshot of Calendar and error in console
Code of Calendar on GitHub
App.vue:
<template>
<div class="all">
<app-calendar #sendTextEvent="text = $event"></app-calendar>
<app-detail v-if="modalWindowDetail"
:eventText="text"></app-detail>
</div>
</template>
<script>
import appCalendar from './components/Calendar.vue'
import appDetail from './components/ModalWindowDetail.vue'
export default {
data(){
return{
text: String
}
},
components: {
appCalendar,
appDetail
},
computed: {
modalWindowDetail() {
return this.$store.state.modalWindowDetail;
}
}
};
</script>
Calendar.vue component which display calendar:
<template>
<div class="overflow-div">
<transition :name="nameOfClass" >
<div :key="currentPage" class="fade_wrapper">
<div v-for="(week, i) in getCalendar" class="d_day">
<li v-for="day in week" class="li_day">
<div class="day">{{ day }}</div>
<div v-for="event in buildEvents(i, day)"
class="event"
v-bind:class="{ 'eventBrown': eventBrown(event),
'eventPurple': eventPurple(event),
'eventOrange': eventOrange(event),
'eventBlue': eventBlue(event) }"
v-on:click="openModalDetail(event)">{{ event }}
</div>
</li>
</div>
</div>
</transition>
</div>
</template>
<script>
import json from './Calendar_data.json'
import { mapState } from "vuex";
import { eventBus } from './../main.js'
export default {
mounted(){
eventBus.$on('getDetailInformation', this.openModalDetail())
},
computed: {
modalWindowDetail() {
return this.$store.state.modalWindowDetail;
},
},
methods: {
openModalDetail(text){
this.$emit('sendTextEvent', text);
}
};
</script>
The component in which the getDetailInformation() is located ModalWindowDetail.vue:
<template>
<div class="underModalWindow">
<div class="modalWindow">
<img src="src/assets/x.png" width="20px" height="20px">
<div class="nameofModal">Вся детальная информация о событии</div>
<div v-for="(key, name) in eventDetail" class="detailEvent">{{ name }}: {{ key }}</div>
<button>Окей</button>
</div>
</div>
</template>
<script>
import { eventBus } from './../main.js'
export default {
props: ['eventText'],
data(){
return{
options: [
{ text: 'Встреча', value: '8' },
{ text: 'День Рождения', value: '4' },
{ text: 'Праздник', value: '1' },
{ text: 'Другое', value: '16' }
],
eventDetail: Object,
}
},
computed: {
eventsData() {
return this.$store.state.eventData;
},
modalWindowDetail() {
return this.$store.state.modalWindowDetail;
},
},
created(){
eventBus.$emit('getDetailInformation', this.getDetailInformation())
},
methods: {
getDetailInformation(){
let arrOfEvents = this.eventsData.events;
for(let z = 0; z < arrOfEvents.length; z++){
let memo = arrOfEvents[z].memo;
console.log(this.memo)
if(memo === this.eventText){
let dataStartOfEvent = arrOfEvents[z].starts_at;
let getStartDataOfEvent = new Date(dataStartOfEvent);
let dataEndOfEvent = arrOfEvents[z].ends_at;
let getEndDataOfEvent = new Date(dataEndOfEvent);
if((getStartDataOfEvent.getHours() - 3) > 0){
this.$store.commit('changeModalWindowDetail', this.modalWindowDetail);
this.eventDetail = {
'Событие': this.eventText,
'Начало события': getStartDataOfEvent.toLocaleTimeString(),
'Конец события': getEndDataOfEvent.toLocaleTimeString(),
'Тип события': this.getType(arrOfEvents[z].type)
}
}else if(getStartDataOfEvent.getDate() != getEndDataOfEvent.getDate()){
this.$store.commit('changeModalWindowDetail', this.modalWindowDetail);
this.eventDetail = {
'Событие': this.eventText,
'Начало события': getStartDataOfEvent.toLocaleDateString(),
'Конец события': getEndDataOfEvent.toLocaleDateString(),
'Тип События': this.getType(arrOfEvents[z].type)
}
}
}
}
}
}
};
</script>
You should remove the () from the function name in eventBus.$on('getDetailInformation', this.openModalDetail()) - you want to reference the function, not to call it and use the result as a reference.
Also, your function getDetailInformation() does not return anything - but you seem to expect that it returns a text. You should correct this.
And finally, I think that #sendTextEvent="text = arguments[0]" would be more appropriate - and using a dedicated method/function will be the best.

Pass data to vue component

i'm learning Vue.js right now, but i have a little problem on understanding a quite easy task ( maybe my idea of programming is too old ).
i've created a little component with this code.
<template>
<div class="tabSelectorRoot">
<ul>
<li v-for="(element,index) in elements" v-on:click="changeSelected(index)">
<a :class="{ 'selected': activeIndex === index }" :data-value="element.value"> {{ element.text }}</a>
</li>
</ul>
<div class="indicator"></div>
</div>
</template>
<script>
export default {
name: "TabSelectorComponent",
data () {
return {
activeIndex : 0,
elements: [
{ 'text':'Images', 'value': 'immagini','selected':true},
{ 'text':'WallArts', 'value': 'wallart'}
]
}
},
created: function () {
},
methods: {
'changeSelected' : function( index,evt) {
if ( index == this.activeIndex) { return; }
this.activeIndex = index;
document.querySelector('.indicator').style.left= 90 * index +'px';
this.$emit('tabSelector:nameChanged',)
}
}
}
</script>
and this is the root
<template>
<div id="app">
<tab-selector-component></tab-selector-component>
</div>
</template>
<script>
import TabSelectorComponent from "./TabSelectorComponent";
export default {
name: 'app',
components: {TabSelectorComponent},
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
'mounted' : function() {
console.log(this)
//EventManager.eventify(this,window.eventManager);
/*this.register('tabSelector:changeValue',function(el){
console.log(el);
});*/
}
}
</script>
All of this renders in something like this
I'd like to reuse the component by varying the number of objects inside the list but i cannot understand how to accomplish this simple task
The basic way to communicate between components in Vue is using properties and events. In your case, what you would want to do is add an elements property to your TabSelectorComponent that is set by the parent.
TabSelectorComponent
export default {
name: "TabSelectorComponent",
props: ["elements"],
data () {
return {
activeIndex : 0
}
},
...
}
In your parent:
<tab-selector-component :elements="elementArray"></tab-selector-component>
This is covered in the documentation here.

how to hide sidebar in vue

guys, I m new to Vue and taken a coreui admin panel to develop some font vue but now I got stuck in this problem this is nav.js file
export default {
items: [
{
name: 'Product',
url: '/product',
icon: 'fa fa-cart-arrow-down',
children: [
{
name: 'Addproduct',
url: '/product/Addproduct',
},
{
name: 'Listproduct',
url: '/product/Listproduct',
}
]
},
]
}
main container
<template>
<div class="app">
<div class="app-body">
<Sidebar :navItems="nav"/>
<main class="main">
<div class="container-fluid">
<router-view></router-view>
</div>
</main>
<AppAside/>
</div>
</div>
</template>
<script>
import nav from '../_nav'
export default {
name: 'full',
components: {
Sidebar,
},
data () {
return {
nav: nav.items
}
},
computed: {
name () {
return this.$route.name
},
list () {
return this.$route.matched
}
}
}
</script>
here is my sidebar
<template v-for="(item, index) in navItems">
<template v-if="item.title">
<SidebarNavTitle :name="item.name" :classes="item.class" :wrapper="item.wrapper"/>
</template>
<template v-else>
<template v-if="item.children">
</template>
<template v-else>
<SidebarNavItem :classes="item.class">
<SidebarNavLink :name="item.name" :url="item.url" :icon="item.icon" :badge="item.badge" :variant="item.variant"/>
</SidebarNavItem>
</template>
</template>
</template>
i m stroing addproduct in my browser local storage now if when user login and go to dashboard then my i watch which url name is present in browser application or not if present show that else ignore now my problem is that how i can apply if condition like addproduct=addprodcut this this visible else hide
You could have a method in mounted hook, which can fetch data from localstorage and check if it's present in the url or not. Then assign it to a variable in main component which toggles the sidebar. Something like below should work:
<template>
<div class="app">
<div class="app-body">
<Sidebar :navItems="nav" v-if="showSidebar" />
<main class="main">
<div class="container-fluid">
<router-view></router-view>
</div>
</main>
<AppAside/>
</div>
</div>
</template>
<script>
import nav from '../_nav'
export default {
name: 'full',
components: {
Sidebar,
},
data () {
return {
nav: nav.items,
showSidebar: false
}
},
mounted () {
this.checkSidebarVisibility()
},
methods: {
checkSidebarVisibility: function() {
const inLocal = window.localStorage.getItems('your_item');
const inUrl = window.location.toString();
// check if inurl inside inLocal
if (inUrl is in inLocal) {
this.showSidebar = true;
} else {
this.showSidebar = false;
}
}
},
computed: {
name () {
return this.$route.name
},
list () {
return this.$route.matched
}
}
}
</script>

Fetch data in component on initiation using parameters from Vuex store

I am new to Vue and am trying to build a simple movie app, fetching data from an API and rendering the results. I want to have an incremental search feature. I have an input field in my navbar and when the user types, I want to redirect from the dashboard view to the search results view. I am unsure of how to pass the query params from the navbar to the search results view.
Here is my App.vue component
<template>
<div id="app">
<Navbar></Navbar>
<router-view/>
</div>
</template>
<script>
import Navbar from './components/Navbar.vue'
export default {
name: 'App',
components: {
Navbar
},
}
</script>
And here is my navbar component where I have the input field
<template>
<nav class="navbar">
<h1 class="logo" v-on:click="goToHome">Movie App</h1>
<input class="search-input" v-on:keyup="showResults" v-model="query" type="text" placeholder="Search..."/>
</nav>
</template>
<script>
import router from '../router/index'
export default {
data: function () {
return {
query: this.query
}
},
methods: {
goToHome () {
router.push({name: 'Dashboard'})
},
showResults () {
//here on each key press I want to narrow my results in the SearchedMovies component
}
}
}
</script>
If I use router.push to the SearchedMovies component then I am only able to pass the query as a parameter once. I thought about using Vuex to store the query and then access it from the SearchedMovies component, but surely there is a better way of doing it?
I also read about using $emit but since my parent contains all the routes, I'm not sure how to go about this.
You don't need to redirect user anywhere. I've made a small demo to show how one might do it. I used this navbar component as you described and emit an event from it:
const movies = {
data: [
{
id: 0,
title: 'Eraserhead',
},
{
id: 1,
title: 'Erazerhead',
},
{
id: 2,
title: 'Videodrome',
},
{
id: 3,
title: 'Videobrome',
},
{
id: 4,
title: 'Cube',
},
]
};
Vue.component('navbar', {
template: '<input v-model="filter" #input="onInput" placeholder="search">',
data() {
return {
filter: '',
};
},
methods: {
onInput() {
this.$emit('filter', this.filter);
}
}
});
// this is just a request imitation.
// just waiting for a second until we get a response
// from the datasample
function request(title) {
return new Promise((fulfill) => {
toReturn = movies.data.filter(movie => movie.title.toLowerCase().indexOf(title.toLowerCase()) !== -1)
setTimeout(() => fulfill(toReturn), 1000);
});
}
new Vue({
el: '#app',
data: {
movies: undefined,
loading: false,
filter: '',
lastValue: '',
},
methods: {
filterList(payload) {
// a timeout to prevent
// instant request on every input interaction
this.lastValue = payload;
setTimeout(() => this.makeRequest(), 1000);
},
makeRequest() {
if (this.loading) {
return;
}
this.loading = true;
request(this.lastValue).then((response) => {
this.movies = response;
this.loading = false;
});
}
},
mounted() {
this.makeRequest('');
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<navbar v-on:filter="filterList"></navbar>
<ul v-if="!loading">
<li v-for="movie in movies" :key="movie.id">{{ movie.title }}</li>
</ul>
<p v-else>Loading...</p>
</div>
Also jsfiddle: https://jsfiddle.net/oniondomes/rsyys3rp/
If you have any problem to understand the code above let me know.
EDIT: Fixed some bugs and added a couple of comments
EDIT2(after the comment below):
Here's what you can do. Every time user inputs something inside a navbar you call a function:
// template
<navbar v-on:input-inside-nav-bar="atInputInsideNavBar"></navbar>
// script
methods: {
atInputInsideNavBar(userInput) {
this.$router.push({
path: '/filtred-items',
params: {
value: userInput
}
})
}
}
Then inside you 'searched movies' page component you can access this value so:
this.$route.params.value // returns userInput from root component

Why is object not defined?

I want to try Vue.js 2 and started with a simple example. I've took this one from here https://jsfiddle.net/gmsa/gfg30Lgv/ and created a simple project with it. After I divided this code into files the project doesn't work. So I've made a data property a function:
data: function(){
return {
tabs: [{
name: "tab1",
id : 0,
isActive: true
}],
activeTab: {}
}
},
But there's an error in a console: Uncaught ReferenceError: newTab is not defined.
Project: https://github.com/rinatoptimus/vue-webpack-delete
File QueryBrowserContainer:
<template>
<div id="queryBrowserContainer">
<p>queryBrowserContainer text</p>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" v-for="tab in tabs" :class="{active:tab.isActive}">
{{ tab.name }}
</li>
<li>
<button type="button" class="btn btn-primary" #click="openNewTab">New tab</button>
</li>
</ul>
<div class="tab-content">
<div v-for="tab in tabs" role="tabpanel" class="tab-pane" :class="{active:tab.isActive}">
<app-querybrowsertab :tab="tab"></app-querybrowsertab>
</div>
</div>
<pre>{{ $data | json }}</pre>
</div>
</template>
<script>
import QueryBrowserTab from './QueryBrowserTab.vue';
export default {
data: function(){
return {
tabs: [{
name: "tab1",
id : 0,
isActive: true
}],
activeTab: {}
}
},
ready: function () {
this.setActive(this.tabs[0]);
},
methods: {
setActive: function (tab) {
var self = this;
tab.isActive = true;
this.activeTab = tab;
/*this.activeTab.isActive = true;
console.log("activeTab name=" + this.activeTab.name);*/
this.tabs.forEach(function (tab) {
if (tab.id !== self.activeTab.id) { tab.isActive = false;}
});
},
openNewTab: function () {
newTab = {
name: "tab" + (this.tabs.length + 1),
id: this.tabs.length,
isActive: true
};
this.tabs.push(newTab);
this.setActive(newTab);
/*this.activeTab = newTab;
console.log("### newtab name=" + newTab.name);*/
},
test: function() {
alert('676767');
},
closeTab: function () {
console.log("### CLOSE!");
}
}
}
File QueryBrowserTab:
<template>
<div>
<p>querybbbTab</p>
<h3>{{tab.name}}</h3>
<h3>{{tab.id}}</h3>
</div>
</template>
<script>
import QueryBrowserContainer from './QueryBrowserContainer.vue';
export default {
data: function () {
return {
databaseOptions: [],
};
},
props: ['tab'],
methods: {},
components: {
'app-querybrowsercontainer': QueryBrowserContainer
}
}
</script>
File App:
<template>
<div id="app">
<app-message></app-message>
<app-querybrowsertab></app-querybrowsertab>
<app-querybrowsercontainer></app-querybrowsercontainer>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {}
}
}
</script>
It seems in file: QueryBrowserTab, you have not passed tab props, but you are using it, make sure you pass tab as props from whatever places you are using it.
As stated in the docs here, you can pass props to a component like following:
<app-querybrowsertab :tab="tab"></app-querybrowsertab>
which you are already doing in app-querybrowsercontainer,but in file App, you are not passing the prop, which might be the source of error for you.