I tried to create a chart with vue 3 and and google charts. Chart is created with vue-google-charts package. But i couldn't able to create control wrapper for it. I want to include RangeSliderFilter to my charts. Here is my code.
<script setup>
import AppLayout from '#/Layouts/AppLayout.vue';
import { Head, Link } from '#inertiajs/inertia-vue3';
import { ref, onMounted, nextTick } from "vue";
import { GChart } from 'vue-google-charts'
const props = defineProps({
data: Object
})
const chartData = ref([])
const rangeSlider = ref();
onMounted(() => {
chartData.value[0] = props.data.header_array;
props.data.msg_array.map((val, index) => {
val[0] = new Date(val[0])
chartData.value.push(val)
})
});
const chartOptions = ref({
title: "Temperature History",
curveType: 'function',
height: 700,
})
</script>
<template>
<Head title="Temperature History" />
<AppLayout>
<div class="py-12">
<div class="mx-auto sm:px-6 lg:px-8">
<div class="shadow-md sm:rounded-lg bg-white">
<div class="p-4">
<GChart v-if="chartData.length > 0" type="LineChart" :data="chartData"
:options="chartOptions" />
<div id="filter_div"></div>
</div>
</div>
</div>
</div>
</AppLayout>
</template>
How I can do this? Is there any good chart package for this?
Related
I am still a beginner at vue and quasar and I would like to animate this Article Container.
<template>
<div class="row align-center q-gutter-md">
<ArticleCard v-for="(article, index) in currentSlice" :article="article" :key="index"/>
</div>
<q-btn rounded label="next" #click="changeSlice" class="self-center"></q-btn>
</template>
<script setup>
import { ref } from 'vue';
import ArticleCard from './ArticleCard.vue';
const props = defineProps({
articles: Array,
articlesShowed: Number
});
const currentEnd = ref(props.articlesShowed);
const currentSlice = ref(props.articles.slice(0, currentEnd.value));
const changeSlice = () => {
currentSlice.value = props.articles.slice(currentEnd.value, currentEnd.value + props.articlesShowed);
currentEnd.value += props.articlesShowed;
}
</script>
and this is my card
<template>
<transition
:duration="1000"
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
>
<q-card class="q-pa-md">
<q-card-section>
<div class="text-h6">{{ props.article.title }}</div>
<q-separator inset></q-separator>
</q-card-section>
<q-card-section>{{ article.description }}</q-card-section>
</q-card>
</transition>
</template>
<script setup>
import { ref } from "vue";
const props = defineProps({
article: Object
});
</script>
For some reason this transition does not work. Technically, I believe that this happens because the card is not toggled, I am merely changing the content inside of it. Could someone pin down the problems, and give me some hints or advices?
I created a page to show all events that I created, the problem is that when entering the page, no event is shown, only the add events button. And as soon as I hit enter in the IDE and add an empty line anywhere in the code, the list magically appears. Can anyone explain to me the reason for this?
I'm using Quasar and Firebase, I'll let my HTML and Javascript code here if anyone has any idea why this is happening
HTML
<template>
<q-page class="flex flex-center bg-primary column">
<q-btn
to="/adicionar-evento"
color="grey-9"
padding="16px 50px"
class="q-mt-lg"
>
<q-icon left size="2.5em" name="add_circle" />
Adicionar um novo evento
</q-btn>
<div v-for="evento in eventos" :key="evento.id" class="partidaDiv row">
<div class="column colunaPartida">
<h1 class="dataHorario">{{ evento.data.slice(0, 5) }}</h1>
<h1 class="dataHorario">{{ evento.horaInicio }}</h1>
</div>
<div class="column colunaPartida2">
<h1 class="dataHorario">{{ evento.quadra.label }}</h1>
<h1 class="textoLocal">{{ evento.quadra.value }}</h1>
<h1 class="textoLocal">Cachoeirinha, Rio Grande do Sul</h1>
</div>
<div class="column colunaPartida3">
<q-icon name="person" color="white" size="2rem" />
<h1 class="dataHorario">
{{ evento.numeroVagasPreenchidas }}/{{ evento.numeroVagasJogadores }}
</h1>
</div>
</div>
<q-item>
<h1></h1>
</q-item>
</q-page>
</template>
Javascript
<script>
import db from "src/boot/firebase";
import {
collection,
getDocs,
orderBy,
query,
addDoc,
onSnapshot,
deleteDoc,
doc,
getDoc,
updateDoc,
} from "firebase/firestore";
export default {
setup() {
return {
name: "IndexPage",
eventos: [],
};
},
async mounted() {
const ordersRef = collection(db, "eventos");
const q = query(ordersRef, orderBy("data"));
const unsubscribe = onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach((change) => {
let eventoChange = change.doc.data();
eventoChange.id = change.doc.id;
if (change.type === "added") {
this.eventos.unshift(eventoChange);
}
});
});
},
};
</script>
Figured out, I was using setup() instead of data().
I'm working on this app and the idea is to show details of the cars in a sidebar on click. There are several issues like the sidebar is showing four times and I resolve it somehow but I don't know why is it showing four times. now I don't getting any response on emit call help me out please, I try $parent.$emit, $root.$emit but not seems working!!!
<template>
<div class="home">
<!-- warehouse details -->
<div
v-for="(detail, detailindex) in details"
:key="detailindex"
class="container mt-5 mb-5"
>
<h1>
{{ detail.name }}
<span class="location">{{ detail.cars.location }}</span>
</h1>
<!-- vehicle details -->
<SingleGarage :detail="detail"> </SingleGarage>
</div>
<b-sidebar
id="my-sidebar"
title="Sidebar with backdrop"
backdrop-variant="dark"
ref="mySidebar"
backdrop
shadow
#emitData="testingEmit()"
>
<div class="px-3 py-2">
<h1>{{currentCar}}</h1>
</div>
</b-sidebar>
</div>
</template>
<script>
// # is an alias to /src
import axios from "axios";
import SingleGarage from "../components/SingleGarage";
export default {
components: { SingleGarage },
name: "Home",
data: () => ({
details: String,
currentCar: 'String',
}),
methods:{
testingEmit(data){
this.currentCar = data
console.log('data from emit',data)
}
},
mounted() {
axios
.get("https://api.jsonbin.io/b/5ebe673947a2266b1478d892")
.then((response) => {
var results;
response.data.forEach((element) => {
element.cars.vehicles.sort((a, b) => {
a = new Date(a.date_added);
b = new Date(b.date_added);
results = a > b ? -1 : a < b ? 1 : 0;
return results * -1;
});
});
this.details = response.data;
});
},
};
</script>
<template>
<div class="vGrid mt-4">
<div
class="gridItem border vehicle singleCar"
v-for="(vehicle, vehicleIndex) in detail.cars.vehicles"
:class="'griditem' + vehicleIndex"
:key="vehicle._id"
>
<SingleCar
:vehicle="vehicle"
#click.native="testingTef(vehicleIndex)"
></SingleCar>
</div>
</div>
</template>
<script>
import SingleCar from "#/components/SingleCar";
export default {
name: "SingleGarage",
components: { SingleCar },
props: ["detail"],
data: () => ({
dummyImg: require("#/assets/img/dummycar.png"),
currentCar : 1
}),
methods: {
testingTef(vehicleIndex) {
this.$parent.$emit('emitData',this.detail.cars.vehicles[vehicleIndex].make)
this.$root.$emit('bv::toggle::collapse', 'my-sidebar')
console.log(this.detail.cars.vehicles[vehicleIndex].make)
console.log(this.detail.cars.vehicles[vehicleIndex].date_added)
this.currentCar = this.detail.cars.vehicles[vehicleIndex].make;
},
},
};
</script>
<template>
<div class="singleCar">
<!-- conditionally show image -->
<img
class="carImg"
:src="vehicle.img"
v-if="vehicle.img"
alt="No Preview"
/>
<img class="carImg" :src="dummyImg" v-else alt="No Preview" />
<div class="p-3">
<h3 class="make">{{ vehicle.make }}</h3>
<div class="modelDetails">
<div class="model d-flex ">
<p class="bold">Model:</p>
<p class="price ml-auto ">{{ vehicle.model }}</p>
</div>
<div class="price d-flex ">
<p class="bold">Price:</p>
<p class="price ml-auto ">€{{ vehicle.price }}</p>
</div>
</div>
<p class="dateAdded ml-auto ">{{ vehicle.date_added }}</p>
</div>
</div>
</template>
<script>
export default {
name: "SingleCar",
props: ["vehicle"],
data: () => ({
dummyImg: require("#/assets/img/dummycar.png"),
}),
methods:{
working(){
console.log('working');
console.log(this.vehicle.make)
}
}
};
</script>
Thanks for your help.
So a few things you can try to fix this
in your Home.vue you can change
#emitData="testingEmit()"
to
#emitData="testingEmit"
// or
#emitData="testingEmit($event)"
You are telling to the function testingEmit that is not params to parse. So you need to take out the () and Vue will parse everything that comes from the $event or you cant say put the $event as a param in your testingEmit (second option).
For your SingleGarage.vue you can take the $parent.$emit and replace it with
this.$emit('emitData',this.detail.cars.vehicles[vehicleIndex].make)
I currently have two active themes using Tailwind light-theme and dark-theme but I can't make it work within an external button component, just with the code and function inside the view.
This is just an example where the function inside the view is acceptable but I have a "real world" case where I need it working from the component, changing the class between dark/light mode.
Here is my "Home.vue" file importing ButtonA and ButtomB:
<template>
<div :class="theme" class="bg-background-primary">
<h1 class="text-4xl text-typo-primary">Test title</h1>
<!-- Inside Home.vue - WORKING -->
<button class="border border-gray-400 bg-blue-500 hover:bg-blue-700 text-white p-2 rounded" #click="toggleThemeOne()">Toggle Dark/Light</button>
<!-- Component with function outside - WORKING -->
<ButtonA msg="From component" #click.native="toggleThemeTwo()" />
<ButtonB msg="Full from component" />
</div>
</template>
<script>
// # is an alias to /src
import ButtonA from '#/components/ButtonA.vue'
import ButtonB from '#/components/ButtonB.vue'
export default {
name: 'Home',
components: {
ButtonA,
ButtonB
},
data() {
return {
theme: 'theme-light',
}
},
methods: {
toggleThemeOne() {
this.theme = this.theme === 'theme-light' ? 'theme-dark' : 'theme-light'
localStorage.setItem('theme', this.theme)
console.log('toggleThemeOne working');
console.log(this.theme)
},
toggleThemeTwo() {
this.theme = this.theme === 'theme-light' ? 'theme-dark' : 'theme-light'
localStorage.setItem('theme', this.theme)
console.log('toggleThemeTwo working');
console.log(this.theme)
},
}
}
</script>
Home.vue has a working button that's changing the theme
ButtonA
It has the HTML only and the function applied on the component
<template>
<div>
<button class="border border-gray-400 bg-blue-500 hover:bg-blue-700 text-white p-2 rounded"> {{ msg }} </button>
</div>
</template>
<script>
export default {
name: "ButtonComp",
props: [
'msg'
]
}
</script>
ButtonB
<template>
<div>
<button
class="border border-gray-400 bg-blue-500 hover:bg-blue-700 text-white p-2 rounded"
#click="toggleThemeTree()"
> {{ msg }} </button>
</div>
</template>
<script>
export default {
name: "ButtonComp",
props: [
'msg'
],
methods: {
toggleThemeTree() {
this.theme = this.theme === 'theme-light' ? 'theme-dark' : 'theme-light'
localStorage.setItem('theme', this.theme)
console.log('toggleThemeTree working');
console.log(this.theme)
},
},
}
</script>
This is the one that's not working. the function should change the :class on Home.vue but I only get the values on the console and the :class isn't working.
I did try with $emit and computed property before but It didn't work.
You should pass theme to ButtonB component in Home.vue:
<ButtonB msg="Full from component" :theme.sync="theme" />
Then in ButtonB component, emit the value back to parent on click:
<script>
export default {
name: "ButtonComp",
props: [
'msg',
'theme'
],
methods: {
toggleThemeTree() {
let theme = this.theme === 'theme-light' ? 'theme-dark' : 'theme-light' // Do not change this.theme directly
localStorage.setItem('theme', theme)
this.$emit('update:theme', theme)
},
},
}
</script>
I need some help displaying a selected an item on the page you are on. I have three component Home, Product, and Index. The Index component is Global component which have a list of items with a route-link attached to them to got to the Product Page (Component) and display the item that was click. I am passing the item in the route-link as params to be able to access the item on the Product page. I am using the Index Component on the Home component to display all item. And when I click an item from the Index component from the Home page, it go to the Product page and display that item. That part is working fine, but when I am on the Product page and I click an item from the Index component, it is not displaying the clicked item in the Product page. I really need some help how to solve this problem.
Main.js code
import Vue from 'vue'
import App from './App'
import router from './router/routes'
import Index from './components/Index'
Vue.component('list-items', Index)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {App},
template: '<App/>'
})
Route.js File
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../pages/Home'
import Product from '../pages/Product'
Vue.use(Router)
export default new Router({
routes: [
{
path: '' || '/',
name: 'Home',
component: Home
},
{
path: '/product',
name: 'Product',
component: Product,
props: true
}
],
mode: 'history'
})
Home.vue component
<template>
<div class="container-fluid p-0">
<list-items />
</div>
</template>
<script>
export default {
name: 'Home',
data: () => ({
})
}
Product.vue component
<template>
<div class="container-fluid p-0">
<div class="container-fluid py-5">
<div class="row">
<div class="col-md-7">
<div class="col-md-12">
<img v-bind:src="item.url" alt="" class="img-fluid">
</div>
</div>
<div class="col-md-4 margin-padding-right">
<div class="col-md-12">
<h3>{{$route.params.product.name}}</h3>
<h5 class="price">${{item.price}}</h5>
</div>
</div>
</div>
<br>
<div class="container-fluid">
<div class="col-md-12 related-item">
<h5>Related Items</h5>
</div>
<list-items />
</div>
</div>
</div>
<script>
export default {
name: 'Product',
props: ['product'],
data: () => ({
quantity: 1,
item: {
name: '',
url: ''
}
}),
mounted () {
if (this.product) {
this.item.name = this.product.name
this.item.url = this.product.image
}
},
watch: {
change: function (newValue, oldValue) {
this.item.name = newValue.product.name
}
}
}
</script>
<style lang="scss" scoped>
</style>
This is an image of what I am trying to achieve.