Map array inside computed property - vue.js

So I wanted to see if I can get some guidance from the community if there is a better way to approach this:
So I have the following vue.js app:
new Vue({
name: 'o365-edit-modal-wrapper',
el: '#o365-modal-edit-wrapper',
data: function() {
const default_apps = [
{
'post_title': 'Excel',
}, {
'post_title': 'Word',
}, {
'post_title': 'SharePoint',
}];
return {
available_list: [],
selected_list: default_apps.map(function(name, index) {
return { name: name.post_title, order: index + 1, fixed: false };
}),
}
},
computed: {
dragOptions() {
// Pass in additional <draggable> options inside the return for both lists.
return {
tag: 'div',
group: 'o365apps',
disabled: !this.editable,
ghostClass: "ghost",
};
},
},
});
The selected_list returns the following items:
I was told that it's bad practice to do array mapping inside the data return, but to instead map inside the computed call - Could someone lead me in the right direction and just see if my code makes sense?
I tried defining an empty array as shown below:
return {
available_list: [],
selected_list:[],
}
& then inside the computed property, I tried accessing it using the following return but wasn't getting any data back:
selected_list() {
return this.default_apps.map(function(name, index) {
return { name: name.post_title, order: index + 1, fixed: false };
});
},
All help is appreciated - Thanks a bunch!

your are almost there except for a few details:
It's ok to map data inside data as long as you put them inside the return object literal data() { return { default_apps: [] } }.
Once default_apps is inside the return object of data, you can access the data inside of it from a computed property using the this keyword: this.default_apps.map()...
new Vue({
name: 'o365-edit-modal-wrapper',
el: '#o365-modal-edit-wrapper',
data: function() {
return {
default_apps: [
{ post_title: 'Excel' },
{ post_title: 'Word' },
{ post_title: 'SharePoint'}
],
available_list: [],
}
},
computed: {
selected_list() {
return this.default_apps.map(function(name, index) {
return { name: name.post_title, order: index + 1, fixed: false };
});
},
dragOptions() {
// Pass in additional <draggable> options inside the return for both lists.
return {
tag: 'div',
group: 'o365apps',
disabled: !this.editable,
ghostClass: "ghost",
};
},
},
});

Related

Data not being passed from Child Data to Parent Props

I have a Request Form Component, and within this request form Component I have a Dropdown Menu Component, which I will link both below. All values in my table are pushed into an object upon hitting the Submit Button. However my dropdown selection is only being picked up by my console.log and not being pushed into the Object.
I'm not so familiar with Vue, so I'm not sure what direction to go in for fixing this. I'll attach the relevant (?) pieces of code below.
Parent Component:
<SelectComponent :selected="this.selected" #change="updateSelectedValue" />
export default {
fullScreen: true,
name: 'CcRequestForm',
mixins: [BaseForm],
name: "App",
components: {
SelectComponent,
},
data() {
return {
selected: "A",
};
},
props: {
modelName: {
default: 'CcRequest',
},
parentId: {
type: Number,
default: null,
},
},
mounted() {
this.formFields.requester.value = this.currentRequesterSlug;
},
destroyed() {
if (!this.modelId) return;
let request = this.currentCcRequest;
request.params = request.params.filter(p => p.id)
},
computed: {
...mapGetters(['ccTypesForRequests', 'currentRequesterSlug', 'currentCcRequest']),
ccTypesCollection() {
return this.ccTypesForRequests.map((x)=>[x.slug, this.t(`cc_types.${x.slug}`)]);
}
},
methods: {
addParam() {
this.addFormFields(['params'], {
slug: '',
name: '',
isRequired: true,
description: '',
typeSlug: '',
selected: ''
});
},
deleteParam(idx){
this.removeFormFields(['params', idx]);
},
restoreParam(idx){
this.restoreFormFields(['params', idx])
},
$newObject() {
return {
slug: '',
name: '',
isAbstract: false,
requester: '',
description: '',
status: 'inactive',
params: [],
selected: ''
};
},
$extraPrams() {
return {
parentId: this.parentId,
};
},
updateSelectedValue: function (newValue) {
this.selected = newValue;
},
},
watch: {
selected: function (val) {
console.log("value changed", val);
},
},
};
Child Component:
<script>
export default {
name: "SelectComponent",
props: {
selected: String,
},
computed: {
mutableItem: {
get: function () {
return this.selected;
},
set: function (newValue) {
this.$emit("change", newValue);
},
},
},
};
You have to define the emit property in the parent component, or else it won't know what to expect. That would look like:
<SelectComponent :selected="this.selected" #update-selected-value="updateSelectedValue" />
Check out this tutorial for more information: https://www.telerik.com/blogs/how-to-emit-data-in-vue-beyond-the-vuejs-documentation
To update selected property inside the object, in this constellation, you need to update object property manually upon receiving an event, inside of updateSelectedValue method. Other way could be creating a computed property, since it's reactive, wrapping "selected" property.
computed: {
selectedValue () {
return this.selected
}
}
And inside of object, use selectedValue instead of selected:
return {
...
selected: selectedValue
}

Recursive method in VueJS

I'm creating a recursive method in Nuxt, can I do it?
Here is my component:
<script>
export default {
data() {
return {
items: [],
auxitems: [],
}
},
methods: {
orderRecursive(items, auxitems) {
items.data.forEach((element) => {
auxitems.push(element)
})
if (items.child.length > 0) {
this.orderRecursive(items.child, auxitems)
} else {
//
}
},
},
}
</script>
The struct items is like:
items= [
data: [{array}],
child: [{data, child}]
]
My intention is order all data in one array, then, I can show in view.
My method orderRecursive() is not working, can you tell me why?

Child element not updating props after change in data coming from apollo in nuxt/vue

UPDATE: the main issue seems to be that the props only get updated once. They should change when this.campaign.name becomes available.
I want to dynamically update the title and breadcrumb data fields and show them on the page. Currently page page shows undefined or null. How can I fix this?
I tried to create a computed value but it only seems to update once (after head and breadcrumb data is already showed). A method does not work since I don't have anything to trigger the method.
What is the correct way to fix this?
I am using nuxt generate to deploy the app.
export default {
components: { PageHeader },
middleware: 'authenticated',
data() {
return {
title: 'Campaigns' + this.campaignName,
breadcrumb: [
{
text: 'Campaigns',
href: '/'
},
{
text: this.campaignName,
href: '/'
}
],
campaign: ''
}
},
apollo: {
campaign: {
prefetch: true,
query: campaignQuery,
variables() {
return { id: this.$route.params.id }
}
}
},
computed: {
campaignName() {
return this.campaign && this.campaign.name
}
},
head() {
return {
title: this.title
}
}
}
</script>
Your computed property campaignName returns undefined cuz this.campaign.name is not defined
campaignName() {
if(this.campaign && this.campaign.name) return "Campaigns" + this.campaign.name;
return "default value";
}
Then you can use it directly in head
head() {
return {
title: this.campaignName
}
}
The solution was putting the data elements directly as a computer property. (so no recalculation)
export default {
components: { PageHeader },
middleware: 'authenticated',
data() {
return {}
},
apollo: {
campaign: {
prefetch: true,
query: campaignQuery,
variables() {
return { id: this.$route.params.id }
}
}
},
computed: {
title() {
return this.campaign && `Campaign: ${this.campaign.name}`
},
breadcrumb() {
return [
{
text: 'Campaign',
href: '/'
},
{
text: this.campaign && this.campaign.name,
href: '/'
}
]
}
},
head() {
return {
title: this.title
}
}
}
</script>

How can I fix my Vue component to properly show my Vue-Chart.js line chart?

I would like to create a line chart using the vue-chartjs library.
What I have created so far produces no error but it also renders nothing but a blank canvas. When I switch to the developer view, I notice that all my data prints out. I'm just not sure why it's not rendering.
Here's my HTML and a snippet of the Vue code:
<div class="app">
<h1>Line Chart</h1>
<line-chart></line-chart>
</div>
<script>
Vue.component('line-chart', {
extends: VueChartJs.Line,
mounted () {
this.renderChart({
labels: this.chartDate,
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: this.expectedFund
}
]
}, {responsive: true, maintainAspectRatio: false})
}
})
new Vue({
el: '.app',
data: {
message: 'Hello World',
dataSetData: [],
expectedFund: '',
chartDate: '',
crossOver: '',
billing: ''
},
methods: {
getDataSet: function(dataField) {
console.log("get data sets");
console.log(this.dataSetData);
this.expectedFund = this.dataSetData.map(function(chartData) {
//alert("expected");
console.log(chartData);
return chartData.ExpectedFund;
});
this.billing = this.dataSetData.map(function(chartData) {
return chartData.Billing;
});
this.billing = this.dataSetData.map(function(chartData) {
return chartData.Billing;
});
this.chartDate = this.dataSetData.map(function(chartData) {
return chartData.date;
});
this.crossOver = this.dataSetData.map(function(chartData) {
return chartData.crossOver;
});
},
getListData: async function() {
const { data } = await axios.get(
"https://my-json-server.typicode.com/isogunro/jsondb/chartData"
);
return data;
}
},
mounted: async function() {
this.dataSetData = await this.getListData();
console.log("ok", this.dataSetData);
this.getDataSet();
}
})
</script>
If the pasted code is not enough, here's the Pen
After much struggle and bouncing around a bunch of Vue discords, I was able to figure out how to create a multi-line and bar-chart using Vue-Chartjs. It was a struggle worth it because I finally understand the use of props and how they work, which is what I was missing with the vuejs charts. Here's a pen showing the solution.
I am posting the json below because my charts use that data found in "my fake json server/typicode". It might change in the future, so I'm pasting it here.
{"chartData":
[
{
"date":"4/4/2019",
"totalCount":381,
"ExpectedFund":191,
"Funded":290,
"Billing":125,
"crossOver":241,
"AcceptedTotal":515
},
{
"date":"4/11/2019",
"totalCount":233,
"ExpectedFund":12,
"Funded":220,
"Billing":125,
"crossOver":211,
"AcceptedTotal":315
},
{
"date":"4/18/2019",
"totalCount":542,
"ExpectedFund":34,
"Funded":240,
"Billing":125,
"crossOver":125,
"AcceptedTotal":415
},
{
"date":"4/25/2019",
"totalCount":154,
"ExpectedFund":49,
"Funded":210,
"Billing":243,
"crossOver":35,
"AcceptedTotal":115
},
{
"date":"5/2/2019",
"totalCount":300,
"ExpectedFund":55,
"Funded":200,
"Billing":125,
"crossOver":145,
"AcceptedTotal":105
},
{
"date":"5/9/2019",
"totalCount":231,
"ExpectedFund":55,
"Funded":250,
"Billing":125,
"crossOver":355,
"AcceptedTotal":215
},
{
"date":"5/16/2019",
"totalCount":331,
"ExpectedFund":77,
"Funded":270,
"Billing":312,
"crossOver":15,
"AcceptedTotal":615
},
{
"date":"5/23/2019",
"totalCount":498,
"ExpectedFund":232,
"Funded":270,
"Billing":312,
"crossOver":15,
"AcceptedTotal":615
},
{
"date":"5/30/2019",
"totalCount":102,
"ExpectedFund":33,
"Funded":150,
"Billing":25,
"crossOver":155,
"AcceptedTotal":315
},
{
"date":"6/6/2019",
"totalCount":293,
"ExpectedFund":235,
"Funded":170,
"Billing":112,
"crossOver":125,
"AcceptedTotal":315
},
{
"date":"6/13/2019",
"totalCount":198,
"ExpectedFund":432,
"Funded":470,
"Billing":112,
"crossOver":315,
"AcceptedTotal":215
}
]
}

Mdb datatable does not rendering data in Vue.js

I'm trying to implement a datatable with mdbootstrap in vue.js.
I would like to update table data on events and when initialized but it does not work.
Template;
<div class="col-md-12">
<mdb-datatable
:data="data"
striped
bordered
/>
</div>
Script;
import { mdbDatatable } from 'mdbvue';
export default {
name: 'userManagement',
components: {
mdbDatatable
},
data() {
return {
className:"",
classList: [],
data: {
columns: [
{
label: 'Name',
field: 'className',
sort: 'asc'
}, {
label: 'ID',
field: 'id',
sort: 'asc'
}
],
rows: [
{
className: 'Tiger Nixon',
id:1
},
{
className: 'Garrett Winters',
id:2
}
]
}
}
},
methods: {
getClassList(){
var _this = this;
this.$axios.get('my_url/admin/classes').then(function (response) {
if (response.status === 200) {
_this.data.rows = [];
response.data.forEach(function (obj) {
let item = {
className: obj.className,
id: obj.id
};
_this.data.rows.push(item);
});
}
}).catch(function (err) {
alert("" + err);
});
}
},
mounted(){
this.getClassList();
},
It always shows default values, I check the data rows from console the value seems to be updated but no change on the datatable.
Any help would be appreciated.
We've found the solution for Your issue.
The new code is available here: https://mdbootstrap.com/docs/vue/tables/datatables/#external-api
Also to make sure the data is reactive it's necessary to add the following code to the Datatable component in our package:
watch: {
data(newVal) {
this.columns = newVal.columns;
},
(...)
}
It will be fixed in the next MDB Vue release.
I installed mdbvue 5.5.0 which includes the change that mikolaj described. This caused the table columns to update when changed but in order to get the rows to update too I had to add to the watch method in Datatable.vue as follows:
watch: {
data(newVal) {
this.columns = newVal.columns;
this.rows = newVal.rows;
},