Use the same function to map different arrays in VueJs - vue.js

I'm trying to use the vuedraggable component and to "nest" it.
I'm fetching data from one table, that fetches data from the second and the second from the third (you get the point). And the second and third table is the ones that I'm currently interested in being able to change the order of.
I have a column named order (yeah, should have chosen sorted_order or something else). But for the moment I'm having problems to "reuse" the mapping function. I don't want to different functions, that doesn't seem to be the right way of doing it..
So for the first one, it looks like this:
<draggable v-if="stacksData.length" :element="'ul'" v-model="stacksData" :options="{animation: 150, handle:'.handle'}" #start="drag=true" #end="drag=false" #change="update">
<li v-for="(stack, index) in stacksData">
<i class="fas fa-arrows-alt handle"></i> <button v-on:click="fetchQuestions(stack)" class="btn btn-primary btn-sm">{{ stack.name }} ({{ stack.question_count }}) (order {{ stack.order }})</button>
</li>
</draggable>
And the second one:
<draggable v-if="questionsData.length" :element="'ul'" v-model="questionsData" :options="{animation: 150, handle:'.handle'}" #start="drag=true" #end="drag=false">
<li v-if="questionsData.length" v-for="(question, index) in questionsData">
<i class="fas fa-arrows-alt handle"></i> {{ question.description }} (order {{ question.order }})
</li>
</draggable>
My "update" function, as it is just now:
update(event){
console.log(event)
this.stacksData.map((stacksData, index) => {
stacksData.order = index + 1
})
}
Expected result:
Be able to call the update function on any array containing column order and update the order of it.

Related

Vue2 generated select triggers event for every other selects

I have a Vue2 project with Buefy extension. Then I have an array of objects which is rendered in the template with one select component for each item. Everything works, but if I trigger #input event on one of the select elements it triggers input event for all selects in the list. I dont understand what is wrong with that.
<div v-for="(inv, index) in pendingInvitations" :key="index" class="columns is-desktop">
<div class="column is-4">{{inv.email}}</div>
<div class="column is-4">
<b-field class="mb-5">
<b-select v-if="invitationRoles"
:input="changeInvitationRole(index)"
v-model="pendingInvitations[index].role"
:placeholder="role">
<option v-for="(value, key) in invitationRoles"
:key="key"
:value="value">
{{ value }}
</option>
</b-select>
</b-field>
</div>
</div>
...
changeInvitationRole(index){
console.log(index);
},
If I change the role and there are three items in the list the console.log() writes 0, 1, 2 as indexes for all items. Why it happens to me? I expect only current itmes index in the log.
Try replacing input with change

proper way to display and filter an object in VueJS

Right now I have data being returned from an API that is structured like the following
{_ids: "690506", _addresses: "987394", _bids: "709395", _sids: "384130"}
<ul>
{{Intl.NumberFormat("en-US").format(DataCounts._ids)}}
Location Records
</ul>
<ul>
<v-icon>{{ mdiArch }}</v-icon>
{{Intl.NumberFormat("en-US").format(DataCounts._addresses)}}
Location Records
</ul>
<ul>
<v-icon>{{ mdiArch }}</v-icon>
{{Intl.NumberFormat("en-US").format(DataCounts._bids)}}
Location Records
</ul>
etc.....
Is there a more compartmentalized way to structure this in the UI so when/if the API changes I do not have to go and check 30 lines of code to make sure it works.
you can use vue filters
https://v2.vuejs.org/v2/guide/filters.html
// create global filter
const mySpecialFormat = Intl.NumberFormat("en-US");
Vue.filter('numberFormatEn', function (value) {
if (!value) return ''
return mySpecialFormat.format(value.toString())
})
// then use it somewhere
{{ DataCounts._ids | numberFormatEn }}
or something along those lines
EDIT: Or did you mean how to simplify Object(k,v) -> html(ul)
in that case something like
https://v2.vuejs.org/v2/guide/list.html
<ul v-for="(value,key) in DataCounts" :key="some-key">
<v-icon v-if="...">{{ mdiArch }}</v-icon>
{{ value | numberFormatEn }}
Location Records
</ul>

Not getting different class names while iterating

I am having a v-for loop in my vuejs application. i want each span to have a different class name. For example .spa0, .spa1, .spa3..... How do I do it using index in v-for loop?
I tried something like this:
:class="`spa${index}`"
Some of my code is:
<div>
<span v-for="(t, index) in table_data" :class="`spa${index}`">{{t}}</span>
</div>
I expect each span to have a different class.
If table_data is like this as you stated in the comments:
{
type: 'LDAP',
des: 'LDAP for Demo - Do not edit or delete this App',
api: 'show token',
scim: 'cloud.kapstonellc.com:8082/scim/v2/10VN44ZN',
endis: true,
act: true
}
You should probably iterate over table_data keys instead:
<div>
<span v-for="(key, index) in Object.keys(table_data)" :class="`spa${index}`">
{{ table_data[key] }}
</span>
</div>

Vuejs: Re-Render List

I am trying to figure out how to re-render a list of name types. I want to ensure that only one name with type 0 (primary) exists at a time, so I want to enable/disable that option based on the number of names in my array with type 0.
<a v-for="type in names.types" v-bind:class="[canAddNameType(type) ? '' : 'disabled', 'dropdown-item']" href="#">
#{{ type.type }}
</a>
How can I make my list get re-rendered every time I add/remove a name?
Work directly with the nested data and bind to the key property for each item:
Template
<a v-for="type in types"
:key="type.type"
:class="[canAddNameType(type) ? '' : 'disabled', 'dropdown-item']" href="#">
#{{ type.type }}
</a>
Script
computed: {
types() {
return this.names.types
}
}

v-if and v-else inside of v-for for different text rendering

I can't find a way to choose different options for rendering text inside of v-for. Is it possible or do I need to structure the logic differently to do something like the code below?
<template>
<ul v-show="showNotifications">
<li v-for="notification in notifications">
// if notification.type = 'friend request'
New friend request from {{ notification.name }}
// else
New notification from {{ notification.name }}
</li>
</ul>
</template>
Notification is a array of objects with data like name and notification type.
Use another template element like following (not tested)
<template>
<ul v-show="showNotifications">
<li v-for="notification in notifications">
<template v-if="notification.type == 'friend request'">
New friend request from {{ notification.name }}
</template>
<template v-else>
New notification from {{ notification.name }}
</template>
</li>
</ul>
I did what Xymanek said and that isn't work for me completely, I also added a method like this since I realize the component is reactive to the variable in "v-for", in this case "notifications"
forceReload(){
this.files.push(fakeNotification);
this.files.pop();
}
as can see this just force the v-for to "re-render" by pushing a fake object to the array.
you can call this method just after the value of "notification.type" change.