In my Vue component I have this inside my script :
import Sortable, { MultiDrag, Swap } from "sortablejs";
export default {
name: "App",
data() {
return {
dragable: ["inde", "japan", "france"],
};
},
mounted() {
let drag = document.getElementById("dragable");
let sortable = new Sortable(drag, {
group: "dragable",
sort: true,
delay: 0,
delayOnTouchOnly: false,
touchStartThreshold: 0,
disabled: false,
store: null,
animation: 150,
preventOnFilter: true,
draggable: ".dragable",
onChoose: (/**Event*/ evt) => {
console.log(evt); // element index within parent
},
store: {
set: function (sortable, drag) {
var order = sortable.toArray();
},
},
});
},
};
I want to store my order result inside my data draggable but I cant access Vue component inside the store, I tried to bind this on Sortable instance new Sortable().bind(this) but can't bind it.
How can I access my Vue component inside my instance to save the order result ?
Related
I try to fetch stocks data from an API. This data should be used to create a chart.js graph.
how do I access in vue.js data to generate a chart.js line chart from the methods http(axios) call?
Is it possible to access the data directly in the mounted component or should I define a const in the section and create the variables there?
<template>
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<div>Selected: {{ selected }}</div>
<div>
<canvas id="myChart" height="200" width="650"></canvas>
</div>
<script>
export default {
mounted() {
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: "line",
data: {
labels: [prices[0].date],
datasets: [
{
label: 'Dataset msft',
data: prices[0].price
},
{
label: 'Dataset google',
data: prices[1].price
},
],
},
});
},
data() {
return {
selected: "",
prices: [],
options: [
{ text: "msft", value: "msft" },
{ text: "GOOGL", value: "GOOGL" },
],
};
},
watch: {
selected: function () {
this.getPrice();
},
},
methods: {
getPrice: function () {
var this_ = this;
axios
.get(
"https://site/...."
)
.then((response) => {
// JSON responses are automatically parsed.
this_.prices = response.data;
})
},
},
};
</script>
Yes, you can access variables in data() from mounted().
You need to prepend variables with this. when using the Options API
ex: this.prices[0].price
As you are putting watcher on selected but I did not see any changes in the selected variable in your code. As per my understanding you are making an API call to get the graph data based on the selected option.
If Yes, Instead of generating a chart in mounted you can generate it inside your getPrice() method itself based on the response. It should be :
methods: {
getPrice: function () {
var this_ = this;
axios
.get(
"https://site/...."
)
.then((response) => {
this.generateChart(response.data);
})
},
generateChart(prices) {
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: "line",
data: {
labels: [prices[0].date],
datasets: [
{
label: 'Dataset msft',
data: prices[0].price
},
{
label: 'Dataset google',
data: prices[1].price
}
]
}
});
}
}
Here, a very basic example:
<script>
export default {
async mounted() {
await this.$nextTick();
const ctx = document.getElementById("myChart");
this.chart = new Chart(ctx, {
type: "line",
data: {
labels: [],
datasets: [],
},
});
},
data() {
return {
selected: "",
chart: null,
options: [
{ text: "msft", value: "msft" },
{ text: "GOOGL", value: "GOOGL" },
],
};
},
watch: {
selected: function () {
this.getPrice();
},
},
methods: {
async getPrice() {
let { data } = await axios.get("https://site/....");
this.chart.data.datasets = [{ label: "dummy data" , data: [2, 3, 4]}];
this.chart.data.label = [1, 2, 3];
this.chart.update(); //very important, always update it
},
},
};
</script>
You create a property called chart and save your chart to it.
Then, after you fetch your data, you can access your chart with this.chart and then you set your datasets and labels. Whenever you make an change to the chart, use this.chart.update() to update it on the browser.
If you execute this code, you should see some dummy data in the chart
I'm passing an array of objects into a child component and I want to access this array into the created function of the child component.
When logging the entire this.$props object I'm getting all the data however when I'm logging the array I'm getting an empty proxy object.
Parent component
<script>
import SelectWithSearch from '#/components/formElements/SelectWithSearch.vue';
import AddressService from '#/services/AddressService';
export default {
data() {
return {
city: 312,
cityOptions: [],
};
},
components: { SelectWithSearch },
created() {
this.getCities();
},
methods: {
async getCities() {
const response = await AddressService.getCities();
this.cityOptions = response.data.cities.map((city) => {
return {
id: city.id,
display_name: `${city.sub_city} (${city.zip})`,
};
});
},
},
};
</script>
Child component (SelectWithSearch)
<script>
export default {
props: {
label: { type: String, required: false },
options: { type: Array, required: true },
},
created() {
console.log(this.$props);
console.log(this.$props.options);
console.log(this.options);
console.log(this.label);
},
Output
How can I access the options data in the created function?
I am using vue-chartjs to create charts for my application. I am passing the chartData as a prop. My chart doesn't render at first but does when I resize the window. Here is my code. First the chart component:
<script>
import { Doughnut, mixins } from "vue-chartjs";
const { reactiveProp } = mixins;
export default {
extends: Doughnut,
mixins: [reactiveProp],
mounted() {
this.render();
},
methods: {
render() {
console.log(this.chartData)
let options = {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
},
};
this.renderChart(this.chartData, options);
},
},
};
</script>
Now here is the code from the component where the chart is displayed:
template part
<v-container>
<ProjectDoughnutChart :chart-data="chartData" />
</v-container>
script part
components: {
ProjectDoughnutChart,
},
data() {
return {
chartData: {
labels: [],
datasets: [
{
backgroundColor: [],
hoverBackgroundColor: [],
data: [],
},
],
},
};
},
setChartsTimesheets() {
this.timesheets.forEach((timesheet) => {
let typeTotal = 0;
this.timesheets
.filter((timesheet1) => timesheet1.type==timesheet.type)
.forEach((timesheet1) => {
typeTotal+=timesheet1.billableAmount;
});
if (this.chartData.labels.indexOf(timesheet.type) === -1) {
let colors = this.getTaskColors(timesheet.type);
this.chartData.labels.push(timesheet.type);
this.chartData.datasets[0].data.push(typeTotal);
this.chartData.datasets[0].backgroundColor.push(colors.color);
this.chartData.datasets[0].hoverBackgroundColor.push(colors.hover);
}
});
},
Solved the problem using a similar solution as "Chart with API data" from the documentation.
TL;DR: Adding a v-if on the chart
For people, that have similar problem, but not using vue.js or the official solution doesnt cut it. I had to chart.update() the graph to show values, that were added after the graph was created.
See the example. If you comment the chart.update() line, the graph will not refresh until the window is resized.
let chart = new Chart(document.getElementById("chart"), {
type: "line",
data: {
labels: ["a", "b", "c", "d", "e", "f"],
datasets: [{
label: 'Dataset 1',
data: [1, 5, 12, 8, 2, 3],
borderColor: 'green',
}]
},
options: {
interaction: {
mode: 'index',
intersect: true,
},
stacked: false,
responsive: true,
}
});
// adding data to graph after it was created (like data from API or so...)
chart.data.labels.push("new data");
chart.data.datasets[0].data.push(9);
// with chart.update(), the changes are shown right away
// without chart.update(), you need to resize window first
chart.update();
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="chart"></canvas>
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.
I'm using the vue-table-2 component : https://github.com/matfish2/vue-tables-2 and I'm struggling to make it work as I want.
I have an API (using API Platform) which is already making all the pagination works. So when I fetch for the first time my list of companies it gives the first ten results + the total rows. I store all of this in my vuex store and I am able to display the list in my table (with useVuex false or true so I don't really understand how this parameter works). The issue is I cannot paginate because I only got ten results and can't get the total rows count to change so I do not get the pagination element at the bottom and can't bind something to it to fetch the other pages later.
Since I'm pretty new to VueJs I can't figure out how this should work with my API. Here is my code so far:
My DataTable element :
<v-client-table name="company" :columns="columns" :data="companies" :options="options" :theme="theme" id="dataTable">
<b-button slot="actions" slot-scope="props" variant="secondary" size="sm" class="btn-pill">Edit</b-button>
</v-client-table>
And my script :
<script>
import Vue from 'vue'
import { ClientTable, Event } from 'vue-tables-2'
import { mapGetters } from 'vuex'
Vue.use(ClientTable)
export default {
name: 'DataTable',
components: {
ClientTable,
Event,
},
data: function() {
return {
columns: ['name', 'actions'],
options: {
headings: {
name: 'Name',
actions: 'Actions',
},
sortable: ['name'],
filterable: ['name'],
sortIcon: {
base: 'fa',
up: 'fa-sort-asc',
down: 'fa-sort-desc',
is: 'fa-sort',
},
pagination: {
chunk: 5,
edge: false,
nav: 'scroll',
},
},
useVuex: true,
theme: 'bootstrap4',
template: 'default',
}
},
computed: {
...mapGetters({
companies: 'companyModule/companies',
totalCompanies: 'companyModule/totalCompanies',
}),
},
}
</script>
This is in my component loading the data where I specify how many items per page I want my api to send me and the page I want:
created() {
this.$store.dispatch('companyModule/FETCH_COMPANIES', {
page: 1,
nbItemPerPage: 10,
})
},
My store looks like this:
import ApiService from '#/services/APIService'
export const companyModule = {
strict: true,
namespaced: true,
state: {
companies: [],
totalCompanies: 0,
},
getters: {
companies: state => state.companies,
totalCompanies: state => state.totalCompanies,
},
mutations: {
SET_COMPANIES(state, data) {
state.companies = data.companies
state.totalCompanies = data.totalCompanies
},
},
actions: {
FETCH_COMPANIES(context, payload) {
payload.entity = 'companies'
return ApiService.get(payload).then(data => {
context.commit('SET_COMPANIES', data)
})
},
},
}
When I received my data, I stored everything in my companies state and for now I'm storing everything I'm getting from my API and this looks like this :
{
"#id": "/api/admin/companies/1",
"#type": "Company",
"id": 1,
"name": "Test Company",
}
Thanks in advance for your help !
watch: {
'companies': {
handler (newValue, oldValue) {
this.totalRows=this.companies.length;
},
deep: true
}
},
Vue “watch” is a powerful reactive option attribute to the vue framework that helps front-end developers listen to changes made on a value and then react to it.
So, once the totalRows is set, you can assign it to the table attributes and the table will change accordingly.
For my case, I used it for bootstrap table as follows:
<b-pagination
:total-rows="totalRows"
:per-page="perPage"
></b-pagination>