Vue <router-view/> loads header components twice - javascript

I am building a simple vue app and I encountered a strange issue where the components in my tag are rendered a second time inside the tag.
Originally, the and components were not in a header tag but they appeared below the component.
App.vue
<template>
<div id="app">
<header><app-logo/><nav-bar/></header>
<section class="container">
<router-view/>
</section>
</div>
</template>
<script>
import AppLogo from './components/AppLogo.vue'
import Home from './components/Home.vue'
export default {
name: 'App',
components: {
Home,
AppLogo
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
display: block;
font-weight: 300;
font-size: 100px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
</style>
nav-bar component:
<template>
<div>
<h1> TFJS/Vue Examples </h1>
<div v-for="page in pages" v-bind:key="page">
<div>
<div>
<router-link to='/basic-logistic-regression'> {{ page }} </router-link>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
pages: ['/BasicLogisticRegression']
}
}
}
</script>
I want to have nav-bar component appear above the router view at all times.

I solved this problem by using a mounted method called loadHome() which uses this.$router.push('/home') to programatically force the router-view to load the homepage component.
here is the code
App.vue
<template>
<div id="app">
<div class="routing">
<header><app-logo/><nav-bar/></header>
</div>
<section class="container">
<router-view/>
</section>
</div>
</template>
<script>
import AppLogo from './components/AppLogo.vue'
import NavBar from './components/NavBar.vue'
import Home from './components/Home.vue'
export default {
name: 'App',
components: {
Home,
AppLogo,
NavBar
},
methods: {
loadHome: function(){
this.$router.push('/home')
}
},
mounted: function(){
this.loadHome()
}
}
</script>

Related

How to use a component in only one router link

So I have a SPA with multiple routerlinks linking to multiple vue components. I am trying to link a component with props to only one of those "pages". How should I go about doing that?
Thanks in advance.
This is my main vue page where I connect all my routerlinks together.
<script>
import Footer from "./components/Footer.vue";
import Counter from "./components/Counter.vue";
export default {
components: {
Footer,
Counter,
},
};
</script>
<template>
<header class="Header">Welcome to my app</header>
<nav>
<RouterLink
style="text-decoration: none; color: inherit; padding-right: 20px"
to="/"
>
Home
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/about"
>
About
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/Dice"
>
Dice
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/FAQ"
>
FAQ
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/Calculator"
>
Calculator
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/Clock"
>
Clock
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/Counters"
>
Counters
</RouterLink>
</nav>
<main>
<RouterView></RouterView>
</main>
<Footer :copyrightYear="2022"></Footer>
</template>
<style scoped>
nav {
background-color: rgb(63, 63, 63);
}
.Header {
color: rgb(0, 0, 66);
text-align: center;
font-size: 50px;
}
nav {
text-align: center;
font-size: 30px;
}
</style>
And I would like to add a component to the 'Counters' page, something like this:
<Counter :startValue="0" :incValue="1"></Counter>
<Counter :startValue="45" :incValue="5"></Counter>
<Counter :startValue="33" :incValue="10"></Counter>
the component looks something like this:
<script>
export default {
props: {
startValue: Number,
incValue: Number,
},
methods: {
increment(a, b) {
a = a + b;
console.log(a);
return a;
},
},
};
</script>
<template>
<button #click="increment(startValue, incValue)">
{{ startValue }}
</button>
</template>
<style scoped>
button {
font-size: 20px;
}
</style>
I would like to add this component to my Counters.vue page:
<script>
export default {
components: {},
};
</script>
<template>
<div class="page">
<h1>Let's count!</h1>
<Counter :startValue="0" :incValue="1"></Counter>
<Counter :startValue="45" :incValue="5"></Counter>
<Counter :startValue="33" :incValue="10"></Counter>
</div>
</template>
<style scoped>
.page {
background-color: rgb(251, 255, 0);
text-align: center;
}
button {
font-size: 20px;
padding: 1px;
margin: 10px;
}
</style>
but adding the 'import' or 'components:' lines to the 'Counters.vue' page completely bombs the site. yet it does work fine on the main vue file. How do I link the component to Counters.vue successfully?
You have to import your component directly in the page you are using it and not in the App.vue
CounterView.vue
<script>
import Counter from "./components/Counter.vue";
export default {
components: {
Counter,
},
};
</script>
<template>
<div class="page">
<h1>Let's count!</h1>
<Counter :startValue="0" :incValue="1"></Counter>
<Counter :startValue="45" :incValue="5"></Counter>
<Counter :startValue="33" :incValue="10"></Counter>
</div>
</template>
<style scoped>
.page {
background-color: rgb(251, 255, 0);
text-align: center;
}
button {
font-size: 20px;
padding: 1px;
margin: 10px;
}
</style>
Also I suggest you to have a different name between your component and your page to avoid conflict
e.g:
Counter.vue for the component
CounterView.vue for the page

Vue.js Modal component shows up in component list, but the modal doesn't actually show

I'm trying to display an items details on click of a button, I have the data going to the modal properly, but I can't seem to get the modal to actually show up. I've tried different implementations of a modal in the template, and the closes I've gotten was having a grey screen show up on the button press. I'm at a loss of what to do at this point because every tutorial I try on modals doesn't seem to work for me. I'm using VUE CLI version 2
Home.vue
<template>
<div class="home">
<Navbar />
<Ordertiles #childToParent="onClickChild"/>
<div v-if="showModal">
<Modal #close="toggleModal" :header="item.header" :text="item.text" :image="item.img"/>
</div>
</div>
</template>
<script>
// # is an alias to /src
import Navbar from '#/components/Navbar.vue'
import Ordertiles from '#/components/Ordertiles.vue'
import Modal from '#/components/Modal.vue'
export default {
name: 'Home',
components: {
Navbar,
Ordertiles,
Modal
},
data() {
return {
item: '',
showModal: false
}
},
methods: {
toggleModal() {
this.showModal = !this.showModal
},
onClickChild(item) {
this.item = item
console.log(this.item)
this.toggleModal()
}
}
}
</script>
Modal.vue
<template>
<div class="modal">
<div class="container">
<div class="modal__title">Direction</div>
<p>{{header}}</p>
<img v-bind:src="image">
<p> {{text}} </p>
<button class="mt-3 border-b border-teal font-semibold">Close</button>
</div>
</div>
</template>
<script>
export default {
props: ['header', 'text', "image"],
methods: {
close () {
this.$emit('close')
}
}
}
</script>
<style lang="css" scoped>
.modal {
background-color: rgba(0, 0, 0, 0.7);
}
</style>
Before Clicking the button
After button click
Why do not use other npm modal packages like vue-modality .I strong vouch for this package.Its easy to use and understand. This will save you a great amount of time as you dont re-invent the wheel.Check out this link https://www.npmjs.com/package/vue-modality
I found a modal example that actually works for me
Modal.vue
<template>
<transition name="modal">
<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">
default footer
<button class="modal-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
props: ['header', 'text', "image"],
methods: {
close () {
this.$emit('close')
}
},
components: {
}
}
</script>
<style lang="css" scoped>
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: table;
transition: opacity 0.3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style>

How to shorten space between x-axis labels in vue-apex chart

I have a simple chart created using vue-apex charts that displays the amount of an asset over time, it works great, but the x-axis displays my data with a lot of distance like this:
https://imgur.com/a/IvfkbZS
How can I reduce the distance between the x-axis items like here:
https://imgur.com/a/X10St0D
here is my code:
<template>
<div class="balance-card-container">
<div class="s">
<md-card class="balance-card">
<md-card-header>
<div class="md-title title">{{ title }}</div>
</md-card-header>
<md-card-content>
<p class="number-p">2345</p>
</md-card-content>
</md-card>
<md-card class="second-card">
<!-- <h2 class="users">Assessments summary</h2> -->
<div class="chart-wrapper">
<apexchart width="900" height="200" type="line" :options="options" :series="series"></apexchart>
</div>
</md-card>
</div>
</div>
</template>
<style lang="scss" scoped>
#import "../variables.scss";
.balance-card {
border-radius: 14px !important;
box-shadow: 0px 6px 20px -6px rgba(221, 243, 255, 0.6) !important;
}
.title {
text-align: center;
font-family: Open Sans;
font-style: normal;
font-weight: bold !important;
font-size: 14px;
color: $casal;
}
.number-p {
text-align: center;
font-family: Open Sans;
font-style: normal;
font-weight: bold;
font-size: 28px;
letter-spacing: 0.25px;
color: $casal;
}
.s {
display: flex;
}
.second-card {
width: 900px !important;
}
.chart-wrapper {
width: 100%;
height: 200px;
}
</style>
<script>
export default {
name: "BalanceCard",
props: ["title"],
data() {
return {
options: {
chart: {
id: 'vuechart-example'
},
xaxis: {
categories: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
}
},
series: [{
name: 'series-1',
data: [10000, 5000, 1000]
}]
}
}
}
</script>

How do I set unique background images for react router components?

I'd like set to different background images for my 'Home' and 'About' components within the react project I'm building. I gave the 'Home' and 'About' components their own stylesheets (styles.css and about.css, respectively), then added a background-image: url() for each, but they both ended up with the 'Home' background.
Any suggestions on how to have different backgrounds for your components, when using react router?
Code as follows:
Home.jsx
import React from 'react'
import './styles.css'
import hashi_logo_2 from './Photos/hashi_logo_2.png'
import {Link} from 'react-router-dom'
function Home() {
return (
<div className = 'home'>
<nav className = 'nav'>
<ul>
<Link to = '/about' style={{ textDecoration: 'none' }} >
<li className='list'>About</li>
</Link>
<li className='list'>Food</li>
<li className='list'>Events</li>
<li className='list'>News</li>
<Link to ='/shop' style={{ textDecoration: 'none' }} >
<li className='list'>Shop</li>
</Link>
<li className='list'>Contact</li>
<li className='list'>Blog</li>
</ul>
</nav>
<main>
<div class='main__image'>
<img src= {hashi_logo_2}/>
</div>
</main>
</div>
)
}
export default Home
styles.css (styling for 'Home')
html * {
box-sizing: border-box;
font-family: 'Permanent Marker', cursive;
}
body {
margin: 0;
padding:0;
background-image: url('./Photos/hashi_pic_blurred_2.jpg');
background-repeat: no-repeat;
background-size: cover;
backdrop-filter: brightness(100%);
}
/* Navigation */
.nav {
background-color:#8b0000;
margin:0;
padding: 15px 0;
opacity: 0.75;
position: fixed;
width:100%;
}
ul {
display:flex;
list-style: none;
flex-direction: row;
justify-content: space-around;
font-size: 20px;
}
.list {
list-style: none;
text-decoration: none;
color: white;
font-size: 25px;
}
.list:hover{
background-color: black;
}
/* Logo */
main {
text-align: center;
padding-top: 130px;
padding-top:180px;
}
img {
max-width: 40%;
height: auto;
}
About.jsx
import React from 'react'
import './about.css'
function About() {
return(
<div className = 'about'>
<p>
Hashigo Zake takes the provision of fine beer to new levels.
<br/>
<br/>
Seven days a week, 362 days a year, we serve the best that New Zealand's booming craft brewing industry has to offer.
We are also building the best range of imported beer that New Zealand has seen.
<br/>
We deal directly with breweries in Australia, Japan and the US and import many of the best beers in the Pacific rim.
<br/>
We also have access to some of the best beers coming from Europe.
<br/>
<br/>
We open at midday every day.
<br/>
Our location is 25 Taranaki St, Te Aro, Wellington, New Zealand.
</p>
<h2>"And he dreamed, and behold a ladder set up on the earth, and the top of it reached to heaven."</h2>
</div>
)
}
export default About
about.css
.about {
height:100%;
background-image: url('./Photos/hashi_taps.jpg');
}
p {
margin-top: 50px;
color: white;
text-align: center;
font-size: 30px;
/* background-color: rgb(139,0,0, 0.75); */
font-family: 'Open Sans', sans-serif;
padding-left: 50px;
padding-right: 20px;
transform: translateY(20%);
font-weight: bold;
}
h2 {
color: white;
text-align: center;
font-size: 40px;
padding-left: 20px;
padding-right: 20px;
margin-top: 400px;
transform: translateY(-450%);
}
import React from 'react';
import Home from './Home'
import About from './About'
import Shop from './Shop'
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
function App() {
return (
<Router>
<div>
<Switch>
<Route path ='/' exact component = {Home}/>
<Route path = '/about' component = {About}/>
<Route path = '/shop' component = {Shop}/>
</Switch>
</div>
</Router>
)
}
export default App;

How to use v-for (Vue.js) to loop a JSON object and split the rendered DOMs into two div containers?

I have an Axios callback that returns a JSON formatted array that contains 170 key:value pairs. Now I use v-for to render one div container per key:value pair into another div wrapper (so the results are shown as a column).
My estimated output is to have two columns as DOM output, each with 85 key:value pairs.
How can someone make v-for to jump to the second div wrapper once it iterated the first 85 (50%) of the JSON array to endup with two columns created next to each other (assuming html/css structure is fine obv.)?
Thank you very much for your ideas in advance!
Vue.config.devtools = true;
var app = new Vue({
delimiters: ['[[', ']]'],
el: '.eurQuotesWrapper',
data() {
return {
rates: []
}},
created() {
axios
.get("http://data.fixer.io/api/latest?access_key=XXX&base=EUR")
.then(response => {
this.rates = response.data.rates;
});
}
});
.column {
margin-top: 8px;
margin-left: 6px;
height: 100%;
width: 16%;
float: left;
border: 1px solid;
border-radius: 10px;
}
.headings {
text-align: center;
font-family: 'Varela Round', sans-serif;
font-weight: bold;
font-size: 16px;
color: #2E1A6D;
margin-top: 5px;
margin-bottom: 5px;
}
.keyColumn {
float: left;
width: 15%;
height: 100%;
}
.valueColumn {
float: left;
width: 35%;
height: 100%;
}
.key {
font-family: 'Varela Round', sans-serif;
font-weight: bold;
font-size: 16px;
}
.value {
font-family: 'Varela Round', sans-serif;
font-weight: bold;
font-size: 16px;
padding-left: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<html>
<body>
<div class="column">
<div class="headings">EUR/XXX</div>
<div class="eurQuotesWrapper">
<div class="keyColumn">
<div v-for="(value, key) in rates" class="key">[[ key ]]</div>
</div>
<div class="valueColumn">
<div v-for="(value, key) in rates" class="value">[[ value ]]</div>
</div>
<div class="keyColumn">
<div v-for="(value, key) in rates" class="key"></div>
</div>
<div class="valueColumn">
<div v-for="(value, key) in rates" class="value"></div>
</div>
</div>
</div>
</body>
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</html>
The point is creating a set of computed values that only return the first (or second) half of the object you get from the API. By using computed values, the original response will stay "intact" for future processing.
It's not a DRY solution (but can be modified to be), and I would create a component for the columns - but in this snippet I just used a simpler form of display (<div v-for=""></div>)
Vue.config.devtools = true;
var app = new Vue({
delimiters: ['[[', ']]'],
el: '.eurQuotesWrapper',
data() {
return {
rates: [],
}
},
computed: {
rates1() {
const ratesArr = Object.entries(this.rates)
const ret = ratesArr.reduce((a, c, i, d) => {
if (i <= d.length / 2) a[c[0]] = c[1]
return a
}, {})
console.log('rates1', ret)
return ret
},
rates2() {
const rateArr = Object.entries(this.rates)
const ret = rateArr.reduce((a, c, i, d) => {
if (i > d.length / 2) a[c[0]] = c[1]
return a
}, {})
console.log('rates2', ret)
return ret
}
},
created() {
axios
.get("http://data.fixer.io/api/latest?access_key=XXX&base=EUR")
.then(response => {
this.rates = response.data.rates;
});
}
});
/*.column {
margin-top: 8px;
margin-left: 6px;
height: 100%;
width: 16%;
float: left;
border: 1px solid;
border-radius: 10px;
}
.headings {
text-align: center;
font-family: 'Varela Round', sans-serif;
font-weight: bold;
font-size: 16px;
color: #2E1A6D;
margin-top: 5px;
margin-bottom: 5px;
}
.keyColumn {
float: left;
width: 15%;
height: 100%;
}
.valueColumn {
float: left;
width: 35%;
height: 100%;
}
.key {
font-family: 'Varela Round', sans-serif;
font-weight: bold;
font-size: 16px;
}
.value {
font-family: 'Varela Round', sans-serif;
font-weight: bold;
font-size: 16px;
padding-left: 20px;
}*/
.keyColumn {
float: left;
}
.valueColumn {
float: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<html>
<body>
<div class="column">
<div class="headings">EUR/XXX</div>
<div class="eurQuotesWrapper">
<strong>COL1</strong>
<div v-for="(value, key) in rates1">[[key]]: [[value]]</div>
<hr />
<strong>COL2</strong>
<div v-for="(value, key) in rates2">[[key]]: [[value]]</div>
</div>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</html>

Categories

Resources