Show Hide Vuejs Element - vue.js

hello, I have a dilemma, trying to show and hide content from a list
I have an object in data
{
types : {
key_1 : { code: 'code_1', text: 'hello 1', show: false },
key_2 : { code: 'code_2', text: 'hello 2', show: false },
key_3 : { code: 'code_3', text: 'hello 3', show: false },
key_4 : { code: 'code_4', text: 'hello 4', show: false },
key_5 : { code: 'code_5', text: 'hello 5', show: false },
}
}
and another in localStorage
[
{ key_6 : { code: 'code_6', text: 'hello 6', show: false } },
{ key_7 : { code: 'code_7', text: 'hello 7', show: false } },
{ key_8 : { code: 'code_8', text: 'hello 8', show: false } },
{ key_9 : { code: 'code_9', text: 'hello 9', show: false } },
]
in created
created: function(){
let datas = JSON.parse(window.localStorage.getItem('types'));
datas.forEach( o => {
this.types[o.code] = {
text : o.text,
show : false,
};
});
},
it works fine this.types, there are both lists
now there's an HTML
<ul>
<li v-for="(v,k) in types" :key="k">
<a #click="opClo(k)">
<span>{{v.text}}</span>
</a>
<ol v-show="v.show">
<li>hello</li>
</ol>
</li>
</ul>
in methods
opClo : function( key ){
this.types[key].show = !this.types[key].show;
},
opClo would have to show or hide the ol, but it fails, it only opens the data, the challenge doesn't open them, how can this problem be solved?

for the record if someone else has the same problem,
the datas.forEach loop when assigning data directly to the object, it is to use $set
this.$set(this.types, key, item)
This was the problem.
Anyway, I think the problem is that because you are adding the items from localStorage after the this.type property is created, the newly added items are not reactive.
see https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

Related

Cannot read properties of undefined on formatter, but data is showing fine

I have a bootstrap table that shows a list of appliances. I am importing my data with Axios and for this specific table I am outputting data from two database tables, so I have one object which is called applianceReferences which stores another object called activeAppliances.
Not sure if it is relevant for this question, but just so you know.
Before talking about the problem, let me just post the whole code and below I will talk about the section that is giving me issues.
<template>
<b-container class="my-2">
<b-card v-if="showTable" class="ml-4 mr-4">
<b-table
search-placeholder="search"
:filter-included-fields="fields.map(f => f.key)"
include-filter
:items="applianceReferences"
:fields="fields"
/>
</b-card>
</b-container>
</template>
<script>
import {applianceService} from "#/services/appliance";
import CommonCollapsible from "#/components/common/CommonCollapsible";
import moment from 'moment';
export default {
components: { CommonCollapsible, CommonTable },
props: {
ownerId: String,
ownerType: String,
showDocuments: Boolean,
goToAppliances: "",
importAppliances: ""
},
data() {
return {
applianceReferences: [],
showTable: true
}
},
computed: {
fields() {
return [
{
key: 'referenceName',
label: this.$t('referenceName'),
sortable: true
},
{
key: 'activeAppliance.type',
label: this.$t('type'),
sortable: true,
},
{
key: 'activeAppliance.brandName',
label: this.$t('brand'),
sortable: true
},
{
key: 'activeAppliance.purchaseDate',
label: this.$t('purchaseDate'),
sortable: true,
template: {type: 'date', format: 'L'}
},
{
key: 'activeAppliance.warrantyDuration',
label: this.$t('warrantyDuration'),
sortable: true,
formatter: (warrantyDuration, applianceId, appliance) =>
this.$n(warrantyDuration) + ' ' +
this.$t(appliance.activeAppliance.warrantyDurationType ?
`model.appliance.warrantyDurationTypes.${appliance.activeAppliance.warrantyDurationType}` :
''
).toLocaleLowerCase(this.$i18n.locale),
sortByFormatted: (warrantyDuration, applianceId, appliance) =>
appliance.activeAppliance.warrantyDurationType === 'YEARS' ? warrantyDuration * 12 : warrantyDuration
},
{
key: 'activeAppliance.purchaseAmount',
label: this.$t('amount'),
sortable: true,
template: {
type: 'number', format: {minimumFractionDigits: '2', maximumFractionDigits: '2'},
foot: sum
}
},
{
key: 'actions',
template: {
type: 'actions',
head: [
{
text: 'overviewOfAppliances',
icon: 'fas fa-fw fa-arrow-right',
action: this.createAppliance
},
{
icon: 'fas fa-fw fa-file-excel',
action: this.importAppliance,
tooltip: this.$t('importAppliances'),
}
],
cell: [
{
icon: 'fa-trash',
variant: 'outline-danger',
action: this.remove
},
]
}
}
]
},
},
methods: {
load() {
Object.assign(this.$data, this.$options.data.apply(this));
this.applianceReferences = null;
applianceService.listApplianceReferences(this.ownerId).then(({data: applianceReferences}) => {
this.applianceReferences = applianceReferences;
this.applianceReferences.forEach( reference => {
applianceService.listAppliances(reference.id).then(result => {
this.$set(reference, 'appliances', result.data);
this.$set(reference, 'activeAppliance', result.data.find(appliance => appliance.active))
this.loaded = true
})
})
}).catch(error => {
console.error(error);
})
},
createAppliance(){
this.goToAppliances()
},
importAppliance(){
this.importAppliances()
},
},
watch: {
ownerId: {
immediate: true,
handler: 'load'
}
},
}
</script>
Okay, so the error occurs in this specific property:
{
key: 'activeAppliance.warrantyDuration',
label: this.$t('warrantyDuration'),
sortable: true,
formatter: (warrantyDuration, applianceId, appliance) =>
this.$n(warrantyDuration) + ' ' +
this.$t(appliance.activeAppliance.warrantyDurationType ?
`model.appliance.warrantyDurationTypes.${appliance.activeAppliance.warrantyDurationType}` :
''
).toLocaleLowerCase(this.$i18n.locale),
sortByFormatted: (warrantyDuration, applianceId, appliance) =>
appliance.activeAppliance.warrantyDurationType === 'YEARS' ? warrantyDuration * 12 : warrantyDuration
},
What I am basically doing here is combining two values from the object: warrantyDuration and warrantyDurationType and putting them in one single row in my bootstrap table.
The problem is that this is giving me an error: Cannot read properties of undefined (reading 'warrantyDurationType'
Yet the data actually outputs normally.
So what exactly does it want me to do?
I tried wrapping a v-if around the table to make sure that the application checks if the data exist before outputting it, but this does not solve the issue.
<div v-if="applianceReferences && applianceReferences.activeAppliance">
<b-card v-if="showTable" class="ml-4 mr-4">
<common-table
search-placeholder="search"
:filter-included-fields="fields.map(f => f.key)"
include-filter
:items="applianceReferences"
:fields="fields"
/>
</b-card>
</div>
Last, just to give you a full overview, my array looks like this:
Any ideas?

Show only enabled item in v-treeview

I'm using v-treeview and i have items like that:
[
{
id: 1,
name: 'name 1',
disabled: false,
children: [
{
id: 2,
name: 'name 2',
disabled: false,
children: [
{
id: 3,
name: 'name 3',
disabled: false
}
]
},
{
id: 4,
name: 'name 4',
disabled: false,
children: [
{
id: 5,
name: 'name 5',
disabled: true
}
]
},
{
id: 6,
name: 'name 6',
disabled: true,
children: [
{
id: 7,
name: 'name 7',
disabled: true
}
]
}
]
}
]
that i want is, only showing the items with disabled false; without passing by filter data to send to v-treeview;
I already tried on slot on not showing any data when disabled is true but the the item set blank space:
<template v-slot:label="{item}" >
<v-container v-if="!item.disabled">
{{ item.name }}
</v-container>
</template>
Some items is provided with v-select, it allow to switch the disabled value of children items, so can't use filter computed cause i have no access of the children with disabled true;
You can use computed in order to create a dynamic variable:
computed: {
visibleElements: function() {
// filter here only entries you are interested to show
let visibleElements = elements.map(el => {
:
:
});
return visibleElements;
}
}

Display Selected values in v-select multiple

I am new in vue js. Using vue2, I have a v-select implemented on my site now, I want to select multiple values and save and show them while editing. But I can't show multiple values properly using :reduce
Here is my code:
<v-select name="allowed_extensions"
:reduce="allowed_extensions => allowed_extensions.value"
multiple
:closeOnSelect="false"
v-model="form.allowed_extensions"
:options="file_options"
v-validate="'required'" > </v-select>
In js:
data () {
return {
isDisabled: false, //Submit Button
form: {
maximum_file_size: '',
allowed_extensions: ''
},
be_errors: {},
// Options
file_options: [
{ label: 'doc', value: 'doc' },
{ label: 'docx', value: 'docx' },
{ label: 'pdf', value: 'pdf' },
{ label: 'txt', value: 'txt' },
{ label: 'gif', value: 'gif' },
{ label: 'png', value: 'png' },
{ label: 'jpg', value: 'jpg' },
{ label: 'jpeg', value: 'jpeg' }
]
}
}
IN Mysql DB, sample data saved as : ["doc","txt"]
But when I want to display them in edit, it showing wrongly in a single tag.
How can I solve this

Expand and collapse treeview using button | Vuetify

I got some problem with Vuetify treeview component. My goal is:
When I select some treeview's element and press expand /collapse button I want to see all children for this element, and then when I press the button once again I want to collapse all selected element.
Here's my code:
<template>
<v-container fluid>
<v-btn justify-center #click="expandCollapse"> Expand or collapse </v-btn>
<v-treeview
class="ml-4"
v-model="tree"
:open="items"
:items="items"
activatable
item-key="name"
>
<template slot="prepend" slot-scope="{ item }">
<v-list-tile-avatar
size="30"
style="min-width: 40px;"
tile
>
<img :src="imageType(item.type)" alt=""/>
</v-list-tile-avatar>
</template>
</v-treeview>
</v-container>
</template>
<script>
export default {
data: () => ({
items: [
{
name: 'Factory A',
type: 'board',
children: [
{
name: 'Line 1',
children: [{
name: 'Machine ABC',
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 2',
children: [{
name: 'Machine ABC 02',
children: [{
name: 'Part A',
type: 'part'
},
{
name: 'Part B',
type: 'part'
},
{
name: 'Part C',
type: 'part'
},
{
name: 'Part D',
type: 'part'
}
],
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 3',
children: [{
name: 'Machine ABC 03',
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 4',
children: [{
name: 'Machine ABC 04',
type: 'machine'
}],
type: 'board'
}
]
}
]
}),
methods: {
imageType (type) {
switch (type) {
case 'board':
return require('#/assets/images/board.svg')
case 'machine':
return require('#/assets/images/machine.svg')
case 'part':
return require('#/assets/images/part.svg')
}
},
// ADDED
bfs: function (tree, key, collection) {
if (!tree[key] || tree[key].length === 0) return
for (var i = 0; i < tree[key].length; i++) {
var child = tree[key][i]
collection.push(child)
this.bfs(child, key, collection)
}
},
expandCollapse (item) {
const childs = []
const selectedIDs = []
childs.push(item)
this.bfs(item, 'children', childs)
}
}
}
</script>
Ok, I got the solution. I just added two if-statements to function.
if (this.open.indexOf(selectedIDs[0]) === -1) {
this.open = this.open.concat(childs.map(node => node.id))
} else {
this.open = this.open.filter((item) => !selectedIDs.includes(item))
}
Use the open and active event listeners to update the open/closed items.
To get the active items use the update:active event.
To get the open items use the update:open event.
on expandCollapse use the active items and the open items to determine whether to open or close, and then update the open to reflect the change. This part is just iterating through the items and running a comparing to active and open

Vue Good Table Component, insert html in filter select options

I am a web-designer, i am working in laravel 5.8 with vue js 2, this is a work for my company.
I have a vue good table component and i want in the flags(languages) column a filter with a drop-down options.
The options(list of languages(example: pt,fr and gb)) are coming from database by a axios request.
Don't want the languages to appear in the filter options with name of the languages but with "span" for a flags icon
(Example: "<span :class="'flag-icon flag-icon-gb
flag-icon-squared'"></span>" ).
This examples works just fine with a row scope and get the flags but in the filter I can get it to translate to html just gives the line as plain text.
I have already tried with "html: true," and "htmlContent: <span></span>"
The scop for the row flag works just fine
vue component scop
<template slot="table-row" slot-scope="row">
<span class="text-center" v-if="row.column.field == 'language.name'">
<span :class="'flag-icon flag-icon-' + row.formattedRow[row.column.field] + ' flag-icon-squared'"></span>
</span>
<span v-else>
{{ row.formattedRow[row.column.field] }}
</span>
</template>
The table data
data() {
return {
columns: [
{
label: 'Name',
field: 'user.name',
filterOptions: {
enabled: true
}
},
{
label: 'Country',
field: 'language.name',
html: true,
filterOptions: {
enabled: true,
filterDropdownItems: []
}
},
{
label: 'Status',
field: 'status.name',
filterOptions: {
enabled: true,
filterDropdownItems: []
}
},
{
label: 'Property',
field: 'property.title',
filterOptions: {
enabled: true,
filterDropdownItems: []
}
},
{
label: 'Last Reply',
field: 'updated_at',
type: 'date',
dateInputFormat: 'YYYY-MM-DD hh:mm:ss',
dateOutputFormat: 'Do MMM YYYY',
filterOptions: {
enabled: true
}
},
{
label: 'Create Date',
field: 'created_at',
type: 'date',
dateInputFormat: 'YYYY-MM-DD hh:mm:ss',
dateOutputFormat: 'Do MMM YYYY',
filterOptions: {
enabled: true
}
},
],
rows: [],
totalRecords: 0,
serverParams: {
columnFilters: {},
sort: {
field: '',
type: '',
},
page: 1,
perPage: 10
}
}
},
The axios request where i get the language list and try to put the span in the filter options
vue
getLanguages() {
let url = '/manage/data/request-language';
axios.get(url)
.then(({status, data}) => {
if (status === 200) {
data.records.forEach(item => {
let newData = {value: item.id, html: true, text: "<span :class='flag-icon flag-icon-" + item.name + " flag-icon-squared'></span>"};
this.columns[1].filterOptions.filterDropdownItems.push(newData);
});
}
}).catch(error => Alert.handleRequestError(error));
},
I expect to appear a flag list and not a span list of the flags.
Is it possible to override that specific filter or to force it html instead of plain text?