link685 link686 link687 link688 link689 link690 link691 link692 link693 link694 link695 link696 link697 link698 link699 link700 link701 link702 link703 link704 link705 link706 link707 link708 link709 link710 link711 link712 link713 link714 link715 link716 link717 link718 link719 link720 link721 link722 link723 link724 link725 link726 link727 link728 link729 link730 link731 link732 link733 link734 link735 link736 link737 link738 link739 link740 link741 link742 link743 link744 link745 link746 link747 link748 link749 link750 link751 link752 link753 link754 link755 link756 link757 link758 link759 link760 link761 link762 link763 link764 link765 link766 link767 link768 link769 link770 link771 link772 link773 link774 link775 link776 link777 link778 link779 link780 link781 link782 link783 link784 link785 link786 link787 link788 link789 link790 link791 link792 link793 link794 link795 link796 link797 link798 link799 link800 link801 link802 link803 link804 link805 link806 link807 link808 link809 link810 link811 link812 link813 link814 link815 link816 link817 link818 link819 link820 link821

[Vue.js] Problem importing getters into Router - Vuex

Problem importing getters into Rotate - Vuex.

when trying to import a value that is within the vuex state.

An error is reported, stating that it is undefined.

there is no idea what I might have done wrong. Please, if anyone can help, I will be very grateful.

Thanks for listening

Error
TypeError: “_store__WEBPACK_IMPORTED_MODULE_4__.default.getters is undefined”

Store

import vue.js from ‘vue’
import Vuex from ‘vuex’
import auth from ‘./module-auth’

Vue.use(Vuex)
export default function () {
const Store = new Vuex.Store({
modules: {
auth
},
strict: process.env.DEV
})
return Store
}

module-auth
Getters

import decode from ‘jwt-decode’

function isTokenExpired (state) {
try {
const decoded = decode(state.token)
if (decoded.exp < Date.now() / 1000) {
return true
} else return false
} catch (err) {
return false
}
}
export {
isTokenExpired,
}

Router

import vue.js from ‘vue’
import VueRouter from ‘vue-router’
import routes from ‘./routes’
import store from ‘../store’

Vue.use(VueRouter)

export default function () {
const Router = new VueRouter({
scrollBehavior: () => ({ x: 0, y: 0 }),
routes,
mode: process.env.VUE_ROUTER_MODE,
base: process.env.VUE_ROUTER_BASE
})

Router.beforeEach((to, from, next) => {
const publicPages = [‘/‘]
const authRequired = !publicPages.includes(to.path)

const loggedIn = store.getters[‘auth/isTokenExpired’]
console.log(loggedIn)

if (authRequired && !loggedIn) {
return next(‘/‘)
}
next()
})
return Router
}

Solution :

the mistake is that you try to use a function as Vuex module.
Module should be an object.
Docs say:

export const moduleA = {
state: { count: 0 },
mutations: {
increment(state) {
state.count++;
}
},

getters: {
doubleCount(state) {
return state.count * 2;
}
}
};

And the function isTokenExpired looks like it should be placed in “getters” section.

Solution 2:

Notice that getters is undefined. Does it help to define the getters in the auth module?

export {
getters: {
isTokenExpired
}
}

Without it, you’ve exported a store module that has no definitions the store can work with.

Solution 3:

Exporting a function that create a store and use it as a function will create many stores and is not desired.

Since you need to use one instance of store anywhere, you need to export the store instance, not a function that create a store.

[Vue.js] How do I use v-model on none form-related elements?

Before anything else, I’m using Vuetify’s VSwitch component inside my-component. to return the value of my-component to the parent.

something like <my-component v-model=”returnedData”></my-component>

Then the inside <my-component></my-component>

<template>
<div>
<v-switch v-model=”toggledData” value=”John”></v-switch>
<v-switch v-model=”toggledData” value=”Andrew”></v-switch>
<v-switch v-model=”toggledData” value=”Melissa”></v-switch>
<v-switch v-model=”toggledData” value=”Elizabeth”></v-switch>
</div>
</template>

<script>
export default {
props: [‘value’],
data () {
return {
toggledData: []
}
}
}
</script>

to return the value of toggledData to the parent that’s using it if possible. I’ve been browsing the net for a while and I’ve been seeing only with inputs. But it was possible to some of Vuetify’s components like the VTreeviewso I was thinking maybe it’s possible.

Solution :

Using v-model like in the example:

<my-component v-model=”returnedData”></my-component>

is (by default) equivalent to this:

<my-component :value=”returnedData” @input=”returnedData = $event”></my-component>

Any component can support v-model just by having a value prop and emitting an input event. The names of the prop and event can be changed using the model option, see https://vuejs.org/v2/guide/components-custom-events.html#Customizing-Component-v-model

All of this assumes that you want two-way data binding. In the question you seem to imply that you just want to pass data up to the parent, which is only one way. For that you only need to emit an event and listen for that event using an @ listener.

Genuinely creating a two-way data binding would be tricky in this case. The easiest way is to drop the v-model on the v-switch and use the prop and event separately. There are alternatives, such as using v-model with a computed property that has a getter and setter, but I’m not convinced that would make things any clearer.

Solution 2:

You can do something like this:
<v-switch @change=”$emit(‘swithValue’, value)” value=”John”></v-switch>
Then in the parent component just listen for swithcValue like @switchValue=”myFunction” the function implicitly gets the emitted value and you can do with it as you wish.

Solution 3:

The parent component listens to the child’s changes with the childToParent and if there is any change I call the childChanged () method

// Parent Component

<template>
<div id=”parent”>
<p>{parentToggledData}</p>
<Child v-on:childToParent=”childChanged”/>
</div>
</template>

<script>
import Child from “./Child”;
export default {
name: “parent”,
components: {
Child
},
data() {
return {
parentToggledData: []
};
},
methods: {
childChanged(value) {
this.parentToggledData = value;
}
}
};
</script>

I listen to the changes on each v-switch, and if there is one, I call the emitToParent () method in this method, I send the changes to the parent with $emit which takes as parameter the event listened by the parent childToParent and “the value to send this.toggledData

// Child Component

<template>
<div id=”child”>
<v-switch v-model=”toggledData” value=”John” @change=”emitToParent”></v-switch>
<v-switch v-model=”toggledData” value=”Andrew” @change=”emitToParent”></v-switch>
<v-switch v-model=”toggledData” value=”Melissa” @change=”emitToParent”></v-switch>
<v-switch v-model=”toggledData” value=”Elizabeth” @change=”emitToParent”></v-switch>
</div>
</template>

<script>
export default {
name: “child”,
data() {
return {
toggledData: []
};
},
methods: {
emitToParent(event) {
console.log(event)
console.log(this.toggledData)
this.$emit(“childToParent”, this.toggledData);
}
}
};
</script>

[Vue.js] How do I sort a table column on page load in Vue.js?

there is a table that to sort by a certain column (ascending) on page load in Vue.js. How do I go about implementing this?

Here is my html..

<table class=”dash-table”>
<thead class=”dash-table-head”>
<tr class=”dash-table-mainHead”>
<th
v-for=”(column, key) in columns”
:key=”key”
@click=”sortTable(column)”
\>{ column.label }
<br>
<i
v-if=”sortOptions.currentSortColumn === column.field”
:class=”sortOptions.sortAscending ? icons.up : icons.down”
class=”sort-icon” />
</th>

<tbody>
<tr
v-for=”(row, key) in tableData”
:key=”key”
class>
<td>
<span>{ row.conversationSource }</span>
</td>
<td>{ row.accounts }</td>
<td>{ row.conversationCount }</td>
<td>{ row.interactive }</td>
<td>{ row.leads }</td>
<td>{ row.leadsPercent }%</td>
<td> </td>
</tr>
</tbody>

This is my column data.

columns: [
{ label: this.$t(‘reporting.source’), field: ‘conversationSource’ },
{ label: this.$t(‘reporting.accountsWithActivity’), field: ‘accounts’, align: ‘center’, type: ‘icon’ },
{ label: this.$t(‘reporting.answerableConversations’), field: ‘conversationCount’, type: ‘boolean’, align: ‘center’ },
{ label: this.$t(‘reporting.interactiveConversations’), field: ‘interactive’, type: ‘boolean’, align: ‘center’ },
{ label: this.$t(‘reporting.leads’), field: ‘leads’, align: ‘center’ },
{ label: this.$t(‘reporting.interactiveLeadConversations’), field: ‘leadsPercent’, type: ‘date’ },
{ field: ‘blank’ },
]

And here is my sorting method which fires when a certain column is clicked.

methods: {
sortTable(column) {
let sortedData = [];
sortedData = this.tableData.sort((a, b) => {
if (a[column.field] < b[column.field]) {
return -1;
}
if (a[column.field] > b[column.field]) {
return 1;
}
return 0;
});

if (
!this.sortOptions.currentSortColumn ||
this.sortOptions.currentSortColumn !== column.field
) {
this.tableData = sortedData;
this.sortOptions.sortAscending = true;
this.sortOptions.currentSortColumn = column.field;
return;
}

this.sortOptions.sortAscending
? (this.tableData = sortedData.reverse())
: (this.tableData = sortedData);

this.sortOptions.sortAscending = !this.sortOptions.sortAscending;
this.sortOptions.currentSortColumn = column.field;
}
}
};

to sort by the leads field in ascending order on page load.

Here is the computed property where the data is summed and calculated.

tableData: {
get() {
let convertedData = this.dataOverview
console.log(convertedData);
let sumResult =
_(convertedData)
.groupBy(‘conversationSource’)
.map((objs, key) => ({
‘conversationSource’: key,
‘conversationCount’: _.sumBy(objs, ‘conversationCount’),
‘interactive’: _.sumBy(objs, ‘interactive’),
‘leads’: _.sumBy(objs, ‘leadsSent’),
‘accounts’: _.size(objs, ‘merchantName’),
‘leadsPercent’: _.round((_.sumBy(objs, ‘leadsSent’) / _.sumBy(objs, ‘interactive’) || 0) * 100)
}))
.value();
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
return (this.convertedData = sumResult);
},
set() {}
}

Solution :

You can use one of the lifecycle hooks to run some code at various times in the lifecycle of the component. In this case either created or mounted:

methods: {

},
created() {
this.sortTable(‘leads’);
}

Solution 2:

fire the sorting method on the created lifecycle hook Docs

data: {
return: {
// the component data goes here
}
},

methods: {
//the component methods
},

created(){
this.sortTable(‘<Column Name>’);
}

[Vue.js] How to toggle class when input lenght is not 0

how to add class when input [type=”email”] has lenght > 0 and remove class if input lenght = 0?

Im not so good in javascript. The solution can be in vue.js or pure javascript.

I tried a few examples from the Internet, but without success.

<div class=”form-group”>
<input type=”email” name=”email” required>
<label for=”email”>Email</label>
</div>

add class if input lenght > 0
remove class if input lenght = 0

Solution :

If by adding and removing class you mean the class of the div, then in jQuery it looks like this:

$(document).on(“change”, “input”, function(){
if($(this).val().length > 0) {
$(“div”).addClass(“form-group”);
} else {
$(“div”).removeClass(“form-group”);
}
});

However if you want pure Javascript it would look something like this

<div id=”myDiv” class=”form-group”>
<input id=”myInput” type=”email” name=”email” onChange=”checkValue()” required>
<label for=”email”>Email</label>
</div>

and the Javascript:

function checkValue(){
if(document.getElementById(“myInput”).value.length > 0){
document.getElementById(“myDiv”).classList.add(“form-group”);
} else {
document.getElementById(“myDiv”).classList.remove(“form-group”);
}
}
checkValue(); //First time run to see if input is empty or not

[Vue.js] Ability to click on content under modal with bootstrap-vue

Want to be able to click on a button or to copy/select content from the background/page when a modal is opened.

Found something at: Allow people to click on links under bootstrap modal when modal backdrop is not present
that recommends to use .modal{bottom:initial!important;} but this doesn’t seem to work with bootstrap-vue.

<!DOCTYPE html>
<html>

<head>
<link rel=”stylesheet” href=”node_modules/bootstrap/dist/css/bootstrap.css” />
<link rel=”stylesheet” href=”node_modules/bootstrap-vue/dist/bootstrap-vue.css” />
<style>
.modal{bottom:initial!important;}
</style>
</head>

<body>
<div id=”app-2”>
<b-navbar toggleable=”lg” type=”dark” variant=”dark”>
<b-navbar-brand href=”#”>NavBar</b-navbar-brand>

<b-navbar-toggle target=”nav-collapse”></b-navbar-toggle>

<b-collapse id=”nav-collapse” is-nav>
<b-navbar-nav>
<b-nav-item href=”#”>Link</b-nav-item>
<b-nav-item href=”#” disabled>Disabled</b-nav-item>
</b-navbar-nav>

<!– Right aligned nav items –>
<b-navbar-nav class=”ml-auto”>
<b-nav-form>
<b-form-input size=”sm” class=”mr-sm-2” placeholder=”Search”></b-form-input>
<b-button size=”sm” class=”my-2 my-sm-0” type=”submit”>Search</b-button>
</b-nav-form>

<b-nav-item-dropdown text=”Lang” right>
<b-dropdown-item href=”#”>EN</b-dropdown-item>
<b-dropdown-item href=”#”>ES</b-dropdown-item>
<b-dropdown-item href=”#”>RU</b-dropdown-item>
<b-dropdown-item href=”#”>FA</b-dropdown-item>
</b-nav-item-dropdown>

<b-nav-item-dropdown right>
<!– Using ‘button-content’ slot –>
<template slot=”button-content”><em>User</em></template>
<b-dropdown-item href=”#”>Profile</b-dropdown-item>
<b-dropdown-item href=”#”>Sign Out</b-dropdown-item>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<b-button v-b-modal.modal-1>Launch demo modal</b-button>
<b-modal id=”modal-1” @shown=’dragable’ title=”BootstrapVue” no-close-on-backdrop hide-backdrop>
<p class=”my-4”>Hello from modal!</p>
</b-modal>
</div>

<script src=”https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src=”node_modules/bootstrap-vue/dist/bootstrap-vue.js”></script>
<script>
window.dragable = function (a) {
let header = a.vueTarget.$refs.header;
let el = a.vueTarget.$refs.content;
let mousePosition;
let offset = [0, 0];
let isDown = false;

header.onmousedown = (e) => {
isDown = true;
offset = [
el.offsetLeft - e.clientX,
el.offsetTop - e.clientY
];
}
header.onmouseup = (e) => {
isDown = false;
};
header.onmousemove = (e) => {
e.preventDefault();
if (isDown) {
mousePosition = {
x: e.clientX,
y: e.clientY
};
el.style.left = (mousePosition.x + offset[0]) + ‘px’;
el.style.top = (mousePosition.y + offset[1]) + ‘px’;
}
};

}

var app2 = new Vue({
el: ‘#app-2’,
methods: {
dragable: dragable
}
})

</script>

</body>

</html>

Solution:
Adding pointer-events:none to the modal css/style

window.dragable = function(a) {
let header = a.vueTarget.$refs.header;
let el = a.vueTarget.$refs.content;
let modal = a.vueTarget.$refs.modal;

let mousePosition;
let offset = [0, 0];
let isDown = false;

modal.onmousedown = (e) => {
document.querySelectorAll(‘.modal’).forEach(e => {
e.parentNode.style.zIndex = e.isSameNode(a.vueTarget.$refs.modal) ? 1041 : 1040;
})
}
header.onmousedown = (e) => {
isDown = true;
offset = [
el.offsetLeft - e.clientX,
el.offsetTop - e.clientY
];
document.querySelectorAll(‘.modal’).forEach(e => {
e.parentNode.style.zIndex = e.isSameNode(a.vueTarget.$refs.modal) ? 1041 : 1040;
})
}
header.onmouseup = (e) => {
isDown = false;
};
header.onmousemove = (e) => {
e.preventDefault();
if (isDown) {
mousePosition = {
x: e.clientX,
y: e.clientY
};
el.style.left = (mousePosition.x + offset[0]) + ‘px’;
el.style.top = (mousePosition.y + offset[1]) + ‘px’;
}
};

}

var n = 0;
var app2 = new Vue({
el: ‘#app-2’,
methods: {
dragable: dragable
}
})
.modal {
pointer-events: none;
}
<!DOCTYPE html>
<html>

<head>
<link rel=”stylesheet” href=”//unpkg.com/bootstrap/dist/css/bootstrap.min.css” />
<link rel=”stylesheet” href=”//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css” />

</head>

<body>
<div id=”app-2”>
<b-navbar toggleable=”lg” type=”dark” variant=”dark”>
<b-navbar-brand href=”#”>NavBar</b-navbar-brand>

<b-navbar-toggle target=”nav-collapse”></b-navbar-toggle>

<b-collapse id=”nav-collapse” is-nav>
<b-navbar-nav>
<b-nav-item href=”#”>Link</b-nav-item>
<b-nav-item href=”#” disabled>Disabled</b-nav-item>
</b-navbar-nav>

<!– Right aligned nav items –>
<b-navbar-nav class=”ml-auto”>
<b-nav-form>
<b-form-input size=”sm” class=”mr-sm-2” placeholder=”Search”></b-form-input>
<b-button size=”sm” class=”my-2 my-sm-0” type=”submit”>Search</b-button>
</b-nav-form>

<b-nav-item-dropdown text=”Lang” right>
<b-dropdown-item href=”#”>EN</b-dropdown-item>
<b-dropdown-item href=”#”>ES</b-dropdown-item>
<b-dropdown-item href=”#”>RU</b-dropdown-item>
<b-dropdown-item href=”#”>FA</b-dropdown-item>
</b-nav-item-dropdown>

<b-nav-item-dropdown right>
<!– Using ‘button-content’ slot –>
<template slot=”button-content”><em>User</em></template>
<b-dropdown-item href=”#”>Profile</b-dropdown-item>
<b-dropdown-item href=”#”>Sign Out</b-dropdown-item>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<b-button v-b-modal.modal-1>Launch demo modal</b-button>
<b-modal id=”modal-1” @shown=’dragable’ title=”BootstrapVue” no-close-on-backdrop hide-backdrop>
<p class=”my-4”>Hello from modal!</p>
</b-modal>
<b-button v-b-modal.modal-2>Launch demo modal</b-button>
<b-modal id=”modal-2” @shown=’dragable’ title=”BootstrapVue” no-close-on-backdrop hide-backdrop>
<p class=”my-4”>Hello from modal!</p>
</b-modal>
</div>

<script src=”https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src=”//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js”></script>

</body>

</html>

Solution :

I don’t quite remember modal backdrop class. But you should try to set backdrop css property pointer-events: none; it would make it “transparent” to all mouse/touch events.

[Vue.js] How to get internal links' URLs right with npm run build?

My app is hosted in a subfolder: my_site.com/my_app/. Although I’m using a vue.config.js file specifying the path of my app on the server (publicPath: ‘/my_app/‘, the internal links in my app are still wrong:

Instead of pointing to my_site/my_app/destination they point to my_site/destination.

How to solve this problem?

Solution :

the internal links are handled by vue.js router.

changing the base option in vue.js router should solve the problem.

https://router.vuejs.org/api/#base

sample

new VueRouter({
base: ‘/my_app/‘,
routes: […]
});

[Vue.js] Vue.JS not update data into nested Component

I’m working with 3 vue.js nested components (main, parent and child) and I’m getting trouble passing data.

The main component useget a simple API data based on input request: the result is used to get other info in other component.

For example first API return the regione “DE”, the first component is populated then try to get the “recipes” from region “DE” but something goes wrong: The debug comments in consolle are in bad order and the variable used results empty in the second request (step3):

app.js:2878 Step_1: DE
app.js:3114 Step_3: 0
app.js:2890 Step_2: DE

This is the parent (included in main component) code:

parent template:

<template>
<div>
<recipes :region=”region”/>
</div>
</template>

parent code:

data: function () {
return {
region: null,
}
},

beforeRouteEnter(to, from, next) {

getData(to.params.e_title, (err, data) => {

console.log(“Step_1: “+data.region); // return Step_1: DE

// here I ned to update the region value to “DE”

next(vm => vm.setRegionData(err, data));
});
},

methods: {
setRegionData(err, data) {
if (err) {
this.error = err.toString();
} else {
console.log(“Step_2: “ + data.region); // return DE
this.region = data.region;

}
}
},

child template:

<template>
<div v-if=”recipes” class=”content”>
<div class=”row”>
<recipe-comp v-for=”(recipe, index) in recipes” :key=”index” :title=”recipe.title” :vote=”recipe.votes”>
</recipe-comp>
</div>
</div>
</template>

child code:

props: [‘region’],
….
beforeMount () {
console.log(“Step_3 “+this.region); // Return null!!
this.fetchData()
},

The issue should be into parent beforeRouteEnter hook I think.

Important debug notes:

1) It looks like the child code works properly because if I replace the default value in parent data to ‘IT’ instead of null the child component returns the correct recipes from second API request. This confirms the default data is updated too late and not when it got results from first API request.

data: function () {
return {
region: ‘IT’,
}
},

2) If I use {region} in child template it shows the correct (and updated) data: ‘DE’!

I need fresh eyes to fix it. Can you help me?

Solution :

Instead of using the beforeMount hook inside of the child component, you should be able to accomplish this using the watch property. I believe this is happening because the beforeMount hook is fired before the parent is able to set that property.

More on the vue.js lifecycle can be found here
More on the beforeMount lifecycle hook can be found here

In short, you can try changing this:

props: [‘region’],
….
beforeMount () {
console.log(“Step_3 “+this.region); // Return null!!
this.fetchData()
},

To something like this:

props: [‘region’],
….
watch: {
region() {
console.log(“Step_3 “+this.region); // Return null!!
this.fetchData()
}
},

Cheers!!

[Vue.js] Laravel & Vue - separate assets for admin and public page

I’m new to vue.js but I really like it. Right now there is my own CMS based on Laravel. to build new CMS as SPA in Vue. But one thing is not clear to me. How should I separate assets for frontend and admin?
For example I would like to have COMPONENTS folder with another folder ADMIN - there will be only admin components.
I also don’t want to have webpack building everything together.
I was thinking about solution like having multiple webpack commands:

npm run dev
npm run dev admin

But maybe I’m completely wrong…

Solution :

If you want to have 2 different commands - you just need to specify different configuration files to webpack –config option
like:
package.json

{
“scripts”: {
“dev”: “webpack-dev-server –inline –progress –config build/webpack.dev.conf.js”,
“dev-admin”: “webpack-dev-server –inline –progress –config build/webpack.dev-admin.conf.js”,
}
}

Another option is to use webpack`s “multiple pages” option. It would allow you to build 2 entry .js files and all of the chunks for both of the apps.

Take a look here: https://webpack.js.org/concepts/entry-points/#multi-page-application

And if you use Vue-cli - https://cli.vuejs.org/config/#pages

[Vue.js] Get the JSON object that matches a specific value

I’m building a little web-app to practice and learn Vue.js and working with APIs.

For a particular problem to solve, I would like to return the object that has the matching uuid that I request.

With my current knowledge, I understand I can do this by implementing some sorts and loops logic.

However I’m still new with JS, Vue.js, so I’m not sure if there is a better way to approach this.

Is there a built in function, or some form of “best practice” to approach this?

methods: {
fetchItem(row) {
// row.target_uuid — this is the UUID I want
// this.$props.todoItems; — this contains the json objects
// return this.$props.todoItems[i] where this.$props.todoItems[i][‘uuid’] == row.target_uuid
},

This is a snippet of my $props.todoItems for context

[
{
“title”: “Install Maris”,
“uuid”: “9ec9ea6b-0efc-4f6a-be2e-143be5748d3a”,
“field_completed”: “False”
},
{
“title”: “Figure out why VS Code sucks”,
“uuid”: “85120da5-ee59-4947-a40f-648699365c73”,
“field_completed”: “False”
},
{
“title”: “Start designing portfolio”,
“uuid”: “243c1960-7ade-4a68-9a74-0ccc4afa3e36”,
“field_completed”: “False”
},
{
“title”: “Meal Prep”,
“uuid”: “85b64b18-9110-44d8-bd2d-8f818b0a810f”,
“field_completed”: “False”
},
{
“title”: “Sharpen knives”,
“uuid”: “8a7ac5f6-8180-4f20-b886-628fd3bcfc85”,
“field_completed”: “False”
},
{
“title”: “Set up SSH keys”,
“uuid”: “f879c441-8c05-4f24-9226-125c62576297”,
“field_completed”: “False”
}
]

Solution :

If you know you’re looking for exactly one item (or the first item that matches) you should take a closer look at the Array.find() method provided by JS. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Array/find)
Also take a look at all the other methods the Array prototype provides, most of them are fairly descriptive and solve most of the basic problems you’ll encounter.

To use this in the vue.js app you can either have a method that returns the todo based on a provided uid like this

todoByUid(uidToFind) {
return this.todos.find(todo => todo.uid == uidToFind)
}

If you only care about a currently selected item a computed value as Jacob mentioned is the way to go:

computed() {
selectedTodo() {
return this.todos.find(todo => todo.uid == this.selectedUid)
}
}

[Vue.js] Vue js data logic - booking table

I need to make a table of bookings (the hours are the y, the slots (actually tennis courts) the x).

I will populate an array from my database with the already occupied
slots (court 5 at 5PM,…);
I’ll then loop trough all possibilities (from 7AM to 12PM and for
each hour, every slots) and put the booking’s name when taken, and
put a button when it’s not.

I can’t figure out how to structurate my data;

In Php I had an array like $bookings[$hour][$court] which, when not empty, should contain the booking name (in the php nested loops (hours and courts), I checked if $bookings[$hour][$court] was empty (and then display the content if any or a button otherwise).

I hope I’m clear enough…

Thank you all !

EDIT:

I tried that way:

new Vue({
el: ‘#app’,
data: {
bookings: [
{
hour: ‘1’,
court: ‘3’,
name: ‘Laurent’
},
{
hour: ‘2’,
court: ‘2’,
name: ‘Gaspard’
}
]

}
})

And

<script src=”https://unpkg.com/vue"></script>

<div id=”app”>
<table>
<tr v-for=”hour in (7, 24)” :key=”hour”>
<td v-for=”court in (1,6)” :key=”court”>
<div v-if=””>

</div>
</td>
</tr>
</table>
</div>

But I don’t kow how to link the data to the template…

Solution :

You could create a method that filters the bookings by the court and hour indexes in the loop.

methods: {
getBookings( hour, court ) {
return this.bookings.filter( booking => booking.hour == hour && booking.court == court );
},
},

This returns an array of appointments so I’d use v-for instead of v-if. This means less code in the js, you don’t have special code to handle the case where the returned array is empty, and the code will show if you have double bookings.

<div v-for=”booking in getBookings( hour, court )” >
{ booking.name }
</div>