Vue on click inside component - vue.js

I have component like this:
<template>
<!-- Content for section1 -->
<div id="section1" class="container-fluid home-div">
<h1 class="text-center">Create Your own Website!</h1>
<p>Welcome to website builder a place where magic comes true. This website will allow you to create your own website, host it on our webserver and change the content or add content as you go!
</p>
<button v-on:click="next" class="btn btn-primary"></button>
</div>
</template>
and my js:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Section1 from '../vue/components/homepage.vue';
import Section2 from '../vue/components/section2.vue';
const routes = [
{ path: '/', component: Section1 },
{ path: '/about', components: Section2, },
];
Vue.use(VueRouter);
const router = new VueRouter({
routes,
});
new Vue({
el: '#homepage',
router,
});
html:
<div id="homepage">
<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="{{ url('template') }}">Website Builder</a>
</div>
<div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav">
<li><router-link to="/">Create</router-link></li>
<li><router-link to="about">How</router-link></li>
</ul>
</div>
</div>
</nav>
<router-view></router-view>
</div>
So now when I click on the link nothing happens, it has a path of /#/ and /#/about respectively, and are being transformed to tags, what is wrong with my current code? Should the navigation be as a template maybe or within the template?

Your component has local scope, meaning it will try and call a next method on the component itself and not on your root instance where you have actually defined your method.
Depending on your situation and what you want you need to either move the method inside your homepage or section2 component.
Or you need to notify your root Vue instance whenever the click event has been called in a child component. There are many communication patterns possible with Vue.js for child-parent communication an easy one would be this:
https://v2.vuejs.org/v2/guide/components.html#Custom-Events
On click you would emit an event from your child component and use a v-on to listen to the event in your root instance.
But by the looks of it you want to implementing routing with one component per page:
https://v2.vuejs.org/v2/guide/routing.html

in your 'new App', when you set 'el' property it should refer to an ID of an html element (the root element).
your html should be like this instead:
<div id="homepage">
<homepage v-if="seen"></homepage>
<section2 v-else></section2>
</div>

Related

Global CSS doesn’t work when programmatically change route

My index page has a Header and Home components.
{
path: "/",
name: "Homepage",
components: {
header: () => import("../components/layout/HomepageHeader.vue"),
main: () => import("../views/Home.vue"),
},
},
Both don’t have any scoped CSS, they only use Tailwind CSS classes. And that Tailwind CSS file is global.
The problem occurs when I programmatically redirect to my index page (for example, after I logged in). The HomepageHeader component doesn’t have all the CSS. Same with the Home.vue component.
Here’s the simplified code of the Header
<template>
<div class="w-full bg-white sm:shadow-lg mb-6">
<div class="mx-6">
<nav
class="px-3 flex flex-col sm:flex-row sm:px-4 sm:justify-between sm:h-16 list-none"
>
<li
class="text-center h-16 font-semibold text-red-500 text-lg sm:text-xl sm:h-16 table"
>
<div class=" py-4 sm:h-16">
<router-link to="/">Home</router-link>
</div>
</li>
<li>
<login-badge
class="shadow-lg md:shadow-none px-4 py-3 flex sm:px-0 sm:h-14 text-white"
></login-badge>
</li>
</nav>
</div>
</div>
</template>
When I say
“component doesn’t have all the CSS”
I mean that all the classes in the HomepageHeader.vue component don’t work. But the classes inside the child component LoginBadge.vue work fine!
What else can I say? I use router.replace("/"); to redirect to the homepage.
How do I fix that?
P.S. Just found out that the same thing happends when I go back to a previous page and that previous page is the index page.
P.P.S. global CSS is imported inside the App.vue
<template>
<router-view name="header"></router-view>
<main class="container mx-auto">
<router-view name="main"></router-view>
</main>
</template>
<script>
export default {
setup() {
return {};
},
};
</script>
<style>
#import "./assets/tailwind.css";

Implementing a reusable tabbed component using Vuejs

I'm trying to implement a tabbed reusable component in vueJs but I'm getting an error that a particular component is not defined. Below are both components
//TabComponent
<template>
<div>
<div class="row">
<div class="col-lg-12 col-xl-12">
<div class="card-box">
<ul class="nav nav-tabs nav-bordered">
<li v-for="tab in tabs" :key="tab" class="nav-item">
{{tab}}
</li>
</ul>
<div class="tab-content">
<component :is="selectedComponent"></component>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TabComponent',
props: [ selectedComponent, tabs ] //The error is coming from this line
}
</script>
I have imported it to this component and currently it shows the error
Uncaught ReferenceError: selectedComponent is not defined
//Entitlements component
<template>
<div>
<tab-component :tabs="tabs" :selectedComponent="selectedComponent" />
</div>
</template>
<script>
import TabComponent from "../../../components/TabComponent";
import List from "./Entitlements/List";
import MyEntitlements from "./Entitlements/MyEntitlements";
export default {
name: 'Entitlements',
components: {List, MyEntitlements, TabComponent},
data(){
return{
tabs: ['List', 'MyEntitlements'],
selectedComponent: 'List',
}
}
}
</script>
HTML attribute names are case-insensitive, so browsers will interpret
any uppercase characters as lowercase. That means when you’re using
in-DOM templates, camelCased prop names need to use their kebab-cased
(hyphen-delimited) equivalents (source)
Try with:
<tab-component :tabs="tabs" :selected-component="selectedComponent" />
Edit:
If you define props as an array, change the list with strings (see "Prop types" here):
props: [ 'selectedComponent', 'tabs' ]

Vue, active router-link not updating after first change

I have a strange issue which I struggled with for a long time... I have a Sidebar with several router-links.
<template>
<div class="nav nav-pills main-nav" id="sidebar" role="tablist">
<router-link class="nav-link" to="/tasks">
Tasks
</router-link>
<router-link class="nav-link" to="/notes">
Notes
</router-link>
<router-link class="nav-link" to="/sounds">
Sounds
</router-link>
<div class="account">
<router-link class="nav-link" to="/profile">
Profile
</router-link>
<a class="nav-link" #click="logOut">
Log out
</a>
</div>
</div>
</template>
<script>
export default {
name: "sidebar",
methods: {
...
}
};
</script>
I have a strange issue with the behaviour of the latter menu. If I go to localhost:8080/notes, the notes button is active as expected. Then, if I click on any of the other link(let's say /tasks), it becomes active as expected. However, if I click on some link once again, /tasks remains active and the new page does not become active. That is, I will be able to navigate to other pages, but the /tasks router link will be active whatever I do. In other words, the "active" link is only updated once... I have no idea what the problem might be :/ Any suggestions are greatly appreciated!
In App.vue I import the sidebar
<div id="app">
<router-view name="header"></router-view>
<router-view name="sidebar"></router-view>
<main :class="{ 'remove-width': sidebarOpened }">
<fade-transition origin="center" mode="out-in" :duration="250">
<router-view />
</fade-transition>
</main>
</div>
My router.js start with
let router = new Router({
mode: "history",
linkExactActiveClass: "exact-active",
linkActiveClass: "active",
base: process.env.BASE_URL,
Pretty sure you shouldn't be having multiple router-views in your template. Can you remove those / replace them with the actual components and see if it fixes the issue? Something like this:
<div id="app">
<AppHeader />
<AppSidebar />
<main>
<fade-transition>
<router-view>
</fade-transition>
</main>
</div>
If it doesn't, you should post a bit more code of your components and router to help identify the issue.

Materialize CSS Modal not working with Vue

I am trying to use materialize modal in Vue..
I have imported it in main.js
import 'materialize-css'
import 'materialize-css/dist/css/materialize.css'
import 'materialize-css/dist/js/materialize.js'
File.vue
<a class="fa fa-trash modal-trigger" href="#delete" #click="consolel(index)"></a>
<div id="delete" class="modal" ref="deleteModal">
<div class="modal-content">
<h4>Modal Header</h4>
<p>A bunch of text</p>
</div>
<div class="modal-footer">
<a
href="#!"
class="modal-close waves-effect waves-green btn-flat"
#click="deleteItem(index)"
>Agree</a>
</div>
</div>
mounted(){
M.AutoInit();
}
I tried the way, docs asked to trigger modal
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems, options);
});
In mounted.
But this didn't work.
How to trigger modal in Vue?!
Another way to do it would be to simply pass an array of vue references and derive the underlying Node from the VNode.
M.Modal.init([this.$refs['deleteModal'][0]], null)

VueJS Modal component inside component

I have a component like this:
<test></test>
I declare this as follows:
Vue.component('test', {
data: {
showModal: true
},
methods: {
displayComponentModalDialog: function() {
this.showModal = true;
}
},
template: `<button #click='displayComponentModalDialog'>test</button>`
});
The <test></test> component is then placed somewhere inside the <div id="#app"> wrapper.
var app = new Vue({
router,
el: '#app',
// etc.
})
Now, I want to display another component inside the test component. So in this case I want a dialog to appear after I click the button in test component. I am not able to achieve this.
What I did is adding a new component:
Vue.component('dialog', {
template: '#dialog-template'
});
And then the following code, although I do not know for sure where to put it.
<!-- template for the modal component -->
<script type="text/x-template" id="dialog-template">
<transition name="dialog">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<button class="btn btn-primary" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<!-- use the modal component, pass in the prop -->
<dialog v-if="showModal" #close="showModal = false">
<h3 slot="header">header</h3>
<p slot="body">
test
</p>
</dialog>
I tried putting this code inside the <test></test> but doesn't work. If I put it inside the template attribute in the component structure, it complains about only one root element.
So it is clear I miss some basic conception how this actually works in VueJS. Someone can help me clarify? Thanks.
As far as I can see your component indeed doesn't have a root tag. Templates have to have a root tag.
This is NOT a valid Vue template:
<div>
<h1>Stuff</h1>
</div>
<h2>Other stuff</h2>
This IS a valid Vue template:
<div>
<div>
<h1>Stuff</h1>
</div>
<h2>Other stuff</h2>
</div>
Note that in the second version we have a single root element for the template, a <div>, whereas in the first one we do not.
You have both a <script></script> and a <dialog></dialog> in your component template.
if you want to add another component in your test component . you can use slot on it.
You can refer to this documentation: https://v2.vuejs.org/v2/guide/components-slots.html
Example:
//component 1
<template>
<div id="modal">
// do something for your modal here.
<slot></slot> // reserve area for your another html or component.
</div>
</template>
// component 2
<template>
<your-modal-component>
<another-component>
</your-modal-component>
</template>