Is it possible to substitute Vue.extend with new Vue? - vuejs2

I am working on a Quasar project and I am having a problem. I need to access from external javascript to the properties and methods of the Vue component.
const vue = Vue.extend({
name: 'PageIndex',
data() {
return {
accessToken:
'myToken',
mapStyle: 'mapbox://styles/mapbox/streets-v11',
coordinates: { lng: -82.42642875898966, lat: 23.11975881338755 },
barbershopsSource: {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
title: 'Foo'
},
geometry: {
type: 'Point',
coordinates: [-82.42644475189455, 23.119620627441506]
}
},
{
type: 'Feature',
properties: {
title: 'Bar'
},
geometry: {
type: 'Point',
coordinates: [-82.42193696725194, 23.124402891576594]
}
},
{
type: 'Feature',
properties: {
title: 'Baz'
},
geometry: {
type: 'Point',
coordinates: [-82.43414198682088, 23.115900071933567]
}
}
]
}
};
},
components: {},
methods: {
createMap() {
mapboxgl.accessToken = this.accessToken;
const map = new mapboxgl.Map({
container: 'map',
style: this.mapStyle, // stylesheet location
center: this.coordinates, // starting position [lng, lat]
zoom: 15 // starting zoom
});
const source = this.barbershopsSource;
map.on('load', function() {
console.log('Map loaded');
//I want to have access to the component properties here
});
map.on('click', 'barbershops', function(e) {
console.log('Barbershop clicked:', e.lngLat);
});
}
},
mounted() {
this.createMap();
}
});
export default vue;
I know that access to properties is pretty simple, but the thing is that by default and I don't know why, Quasar uses Vue.extend to create the components. If I substitute
const vue = Vue.extend
by
const vue = new Vue
I can access to properties, but the component view isn't loaded.
Any help would be greatly appreciated

The way it works is, quasar takes App.vue as the entry point and loads the generated compiled javascript. The app is created there.
There is only one app running.
You add functionality to your vue app by extend the app.
You create app once in App.vue and add functionality to it by extending.

Related

Nuxt: Module should export a function: #turf/helpers [ERROR]

Does anyone know why am I getting Module should export a function: #turf/helpers when I add #turf/helpers to my buildModules in nuxt.config.js?
nuxt.config.js
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
],
// Auto import components: https://go.nuxtjs.dev/config-components
components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [
// https://go.nuxtjs.dev/tailwindcss
'#nuxtjs/tailwindcss',
'#turf/helpers'
],
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
],
Am I adding the module to the wrong array?
FYI: the module is present within my package.json / dependencies. Thus, the installation went through.
// Component where import { point } from '#turf/helpers' returns undefined
<script>
import { defineComponent } from '#vue/composition-api';
import mapboxgl from 'mapbox-gl';
import { point } from '#turf/helpers'
export default defineComponent({
data () {
return {
geojson: {
'type': 'FeatureCollection',
'features': []
},
map: null,
}
},
mounted() {
this.initMapBox();
},
methods: {
// Initialize MapBox map
initMapBox: function() {
mapboxgl.accessToken = 'pk.eyJ1IjoiYWxleGFuZHJ1YW5hIiwiYSI6ImNrZTl3NzJ3bzIxNG4yc2w2aG03dHNkMDUifQ.xaSxrVMLZtfGAlWoGvB1PQ';
this.map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/alexandruana/cksxeq0637zjy17tcvd4h919d',
center: [22.253, 45.419],
zoom: 4
});
this.map.on('load', () => {
console.log('Map loaded.')
let point = point([22.253, 45.419]);
console.log(point)
this.map.addSource('points', {
type: 'geojson',
data: this.geojson
});
this.map.addLayer({
id: 'points',
type: 'circle',
source: 'points',
paint: {
'circle-radius': 8,
'circle-color': '#00a9e2'
},
filter: ['in', '$type', 'Point']
});
});
},
}
})
Importing it as a regular NPM package and using it without colliding with the same variable name fixed the issue!
Indeed, this was not a Nuxt module.

Vue PayPal implementation with vue-head, paypal not defined

I'm trying to add the paypal sdk via vue-head(https://www.npmjs.com/package/vue-head) in my component but I keep getting this error:
Error in mounted hook: "ReferenceError: paypal is not defined"
What am I doing wrong here? Is the SDK simply not loading before mounted?
Is there a better way to accomplish this? Does anyone have an example of their paypal implementation in vue? Any help would be greatly appreciated.
edit: Also if I include the script tag server side (rails) then try to access paypal in vue I see this error:
Could not find driver for framework: [object Object]
<template>
<div id="paypal-button" />
</template>
<script>
import { mapState as mapConfigState } from '../scripts/store/appConfig';
export default {
props: {
totalPrice: {
type: String,
required: true,
},
currency: {
type: String,
required: true,
'default': 'USD',
},
buttonStyle: {
type: Object,
required: false,
},
},
computed: {
...mapConfigState({
customer: state => state.customer,
}),
paypalEnvironment() {
return (this.customer.paypalTestingMode) ? 'sandbox' : 'production';
},
client() {
return {
sandbox: this.customer.paypalClientIdSandbox,
production: this.customer.paypalClientIdLIVE,
};
},
},
head: {
script() {
return [
{
type: 'text/javascript',
src: `https://www.paypal.com/sdk/js?client-id=${this.client[this.paypalEnvironment]}`,
},
];
},
},
mounted() {
const total = this.totalPrice;
const currency = this.currency;
paypal.Buttons.driver(
{
env: this.paypalEnvironment,
client: this.client,
style: this.buttonStyle,
createOrder(data, actions) {
return actions.order.create({
purchase_units: [
{
amount: {
value: total,
currency,
},
},
],
});
},
onApprove(data, actions) {
return actions.order.capture();
},
}, '#paypal-button'
);
},
};
</script>
edit2: I tried adding the script in my mounted hook like this:
let el = document.querySelector(`script[src="https://www.paypal.com/sdk/js?client-id=${this.client[this.paypalEnvironment]}"]`);
if (!el) {
const src = `https://www.paypal.com/sdk/js?client-id=${this.client[this.paypalEnvironment]}`;
el = document.createElement('script');
el.type = 'text/javascript';
el.async = true;
el.src = src;
document.head.appendChild(el);
}
I can see the script in the head tag in the dev console but paypal still is not defined.
For anyone else who is trying to implement PayPal in a Vue component:
<template>
<div id="paypal-button" />
</template>
<script>
export default {
mounted() {
function loadScript(url, callback) {
const el = document.querySelector(`script[src="${url}"]`);
if (!el) {
const s = document.createElement('script');
s.setAttribute('src', url); s.onload = callback;
document.head.insertBefore(s, document.head.firstElementChild);
}
}
loadScript('https://www.paypal.com/sdk/js?client-id=sb&currency=USD', () => {
paypal.Buttons({
// Set up the transaction
createOrder(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '0.01',
},
}],
});
},
// Finalize the transaction
onApprove(data, actions) {
return actions.order.capture().then(details => {
// Show a success message to the buyer
alert(`Transaction completed by ${details.payer.name.given_name}`);
});
},
}).render('#paypal-button');
});
},
};
</script>
Alternatively you can use this: https://github.com/paypal/paypal-js

Adding a chart-js plugin to vue-chart-js

I'm trying to add a chartjs plugin called chartjs-plugin-annotation (https://github.com/chartjs/chartjs-plugin-annotation) to my vue-chart js project. In my BarChart.vue file, I first imported the chartjs annotation plugin
<script>
import { Bar, mixins } from "vue-chartjs";
import chartjsPluginAnnotation from "chartjs-plugin-annotation";
const { reactiveProp } = mixins;
export default {
extends: Bar,
mixins: [reactiveProp],
plugins: {
annotation: {
drawTime: "afterDatasetsDraw",
events: ["click"],
dblClickSpeed: 350,
annotations: [
{
drawTime: "afterDraw",
id: "a-line-1",
type: "line",
mode: "horizontal",
scaleID: "y-axis-0",
value: "25",
borderColor: "red",
borderWidth: 2,
onClick: function (e) {
// `this` is bound to the annotation element
},
},
],
},
},
props: {
options: {
type: Object,
required: true,
},
},
mounted() {
// add plugin
this.addPlugin([chartjsPluginAnnotation]);
this.renderChart(this.chartData, this.options);
},
watch: {
options() {
this.renderChart(this.chartData, this.options);
},
},
};
</script>
I added the plugin under mounted() this.addPlugin([chartjsPluginAnnotation]);, before rendering the chart.
Am I adding the config options to my chart correctly as at the plugins : ?
I've installed the plugin successfully, using npm install chartjs-plugin-annotation --save. I refreshed my app on my local but there's no annotation plugin added to the chart. What am I supposed to fill up in the onClick: function (e)? What am I still missing?
I apologise in advance because I'm really new to this framework.
Here's how your options object should look like:
{
...
annotation: {
annotations: [
{<your annotation object code here>}
],
},
...
}
Next, you've correctly identified that you should use the addPluing() method, just make sure to use it like so
// in imports
import SomePlugin from "..."
// in mounted
this.addPlugin(SomePlugin);
https://stackoverflow.com/a/65486537/7165219
import chartjsPluginAnnotation from "chartjs-plugin-annotation";
And:
mounted() {
Chart.plugins.register(chartjsPluginAnnotation);
this.addPlugin(chartjsPluginAnnotation);
this.renderChart(this.chartData, this.options);
}

Trying to set xAxis extremes using highcharts-vue wrapper

I use the highcharts-vue wrapper (https://github.com/highcharts/highcharts-vue) to display a chart in my project. Now I'm dynamically adding new data to the already existing data.
(Originally I believe the addPoint function is used, but I already switched to pushing it to the series array.)
Now when I add one more element to data the selected/displayed range stays the same, but I wish to set it anchored to the right, so the new pushed data point appears (without having to shift the selected range manually).
In this highcharts example it's very much what I need, except for it not updating automatically at an interval, but on clicking a button.
https://www.highcharts.com/stock/demo/dynamic-update
I thought, I could work around it by using setExtremes on xAxis, but I get an error, that xAxis doesn't exist. Something like in this example.
http://jsfiddle.net/wkBwW/16/
So I think it's because I have to change the values differently or call an update differently because of the wrapped version.
<template>
<div class="chartcard">
<highcharts :constructor-type="'stockChart'" :options="chartOptions" ></highcharts>
<button v-on:click="addPoint" key="nextbutton"> add data </button>
</div>
</template>
<script>
import chartdatajson from "../assets/chart_data.json"
import {Chart} from 'highcharts-vue'
import Highcharts from 'highcharts'
import stockInit from 'highcharts/modules/stock'
stockInit(Highcharts);
let groupingUnits = [['week', [1]], ['month', [1]]];
function getOhlcAndVolume(data) {
...
}
let dataOhlcVolume = getOhlcAndVolume(chartdatajson);
export default {
name: 'ChartCard',
props: {
},
components: {
highcharts: Chart
},
methods: {
rescale: function(){
this.chartOptions.rangeSelector.selected = 0;
},
addPoint: function() {
let somedata = this.test_add_data.shift();
let ohls = somedata.slice(0,5);
let volume = [somedata[0], somedata[5]];
this.chartOptions.series[0].data.push(ohls);
this.chartOptions.series[1].data.push(volume);
// this.chartOptions.xAxis.max = somedata[0]
this.chartOptions.xAxis[0].setExtremes(1554048000000 , somedata[0])
},
},
data () {
return {
test_add_data: [[1556812800000,262,265,260.5,265,30200],[1557072000000,260,260,258,259,33688],[1557158400000,259.5,263,259,262.5,25686]],
chartOptions: {
rangeSelector: {
selected: 0
},
title: { text: 'Some Title' },
yAxis: [{...
}],
xAxis: {
},
series:
[{
type: 'candlestick',
name: 'AAPL',
data: dataOhlcVolume.ohlc,
dataGrouping: {
units: groupingUnits
}
}, {
type: 'column',
name: 'Volume',
data: dataOhlcVolume.volume,
yAxis: 1,
dataGrouping: {
units: groupingUnits
}
}]
}
}
}
}
</script>
Check this example with setting extremes in vue app: https://codesandbox.io/s/vue-template-nutgx. As you can see setExtremes() method has to be invoked on chart.xAxis instance.
You can get chart reference following this approach:
data() {
return {
chartOptions: {
chart: {
events: {
load: (function(self) {
return function() {
self.chart = this; // saving chart reference in the component
};
})(this)
}
},
...
}
};
}
This way you can reference xAxis.setExtremes() like that:
methods: {
setNewExtremes: function() {
this.chart.xAxis[0].setExtremes(1525872600000, 1528291800000);
}
}

Vue Js Components does not get destroyed?

I'm currently working on an very versatile dashboard to display various data.
For the frontend I'm using the latest nuxt and vue version.
My dashboard has many kinds of variations to display data (for example pie charts, line charts,...) these are described in components which are called dynamically.
The Problem is that when I browse from the Page "/" to another (for example "/foo") the interval gets fired again and crashes the app.
That happenes after the lifecycle hook destroyed. I tried to define the interval as an variable and stop it in the beforeDestroy hook but it did not help.
let interval= setInterval(this.fetchData.bind(null, configuration, connector), configuration.refreshTime)
/* later */
clearInterval(interval);
Do you see an error?
Thank you.
Thats the relevant code:
Template
<no-ssr>
<v-container grid-list-md>
<v-layout row wrap v-masonry transition-duration="0.5s" item-selector=".flex" column-width="#grid-sizer">
<v-flex xs1 sm1 md1 lg1 x1 id="grid-sizer"></v-flex>
<component :key="dashboardItem.id" v-for="(dashboardItem,index) in dashboardItems" :is="dashboardItem.type" :connector="dashboardItem.connector"
:type="dashboardItem.type" :configuration="dashboardItem.configuration" :id="dashboardItem.id" :index="index"></component>
</v-layout>
</v-container>
</no-ssr>
Script
import OnlyValue from '#/components/dashboardItems/OnlyValue.vue'
import TrafficLight from '#/components/dashboardItems/TrafficLight.vue'
import ChartAllHover from '#/components/dashboardItems/ChartAllHover.vue'
import PieChart from '#/components/dashboardItems/PieChart.vue'
import Section from '#/components/dashboardItems/Section.vue'
import Gauge from '#/components/dashboardItems/Gauge.vue'...
export default {
name: 'HomePage',
head () {
return {
title: "Dashboard"
}
},
computed: {
...mapGetters({
isAuthenticated: "users/isAuthentificated",
profileName: "profiles/name",
dashboardItems: "profiles/dashboardItems"
})
},
mounted() {
if (typeof this.$redrawVueMasonry === 'function') {
this.$redrawVueMasonry()
}
},
components: {
OnlyValue,
TrafficLight,
ChartAllHover,
PieChart,
Section,
Gauge
}
}
When calling a components it looks the following:
import dashboardItem from '~/mixins/dashboardItem'
export default {
name: "gauge",
mixins: [dashboardItem],
props: {
connector: {
type: String,
required: true
},
type: {
type: String,
required: true
},
configuration: {
type: Object,
required: true
},
id: {
type: Number,
required: true
},
index: {
type: Number,
required: true
}
},
data: () => ({
initOptions: {
renderer: 'svg'
},
options: {
tooltip: {
formatter: "{c}%"
},
series: [{
name: null,
type: 'gauge',
detail: {
formatter: '{value}%'
},
data: null
}]
},
isLoading: true
}),
methods: {
getData(configuration, connector) {
this.fetchData(configuration, connector)
setInterval(this.fetchData.bind(null, configuration, connector), configuration.refreshTime)
},
fetchData(configuration, connector) {
this.getSingleValue(configuration, connector)
.then(data => {
this.isLoading = false
let percent = (data.value / configuration.max) * 100
percent = Math.round(percent * 10) / 10
this.$nextTick(function () {
this.$refs.gauge.mergeOptions({
series: [{
name: data.title,
data: [{
value: percent,
name: data.title
}]
}]
})
})
this.$redrawVueMasonry()
})
.catch(e => console.log(e))
}
},
mounted () {
this.getData(this.configuration, this.connector)
}
}