link1370 link1371 link1372 link1373 link1374 link1375 link1376 link1377 link1378 link1379 link1380 link1381 link1382 link1383 link1384 link1385 link1386 link1387 link1388 link1389 link1390 link1391 link1392 link1393 link1394 link1395 link1396 link1397 link1398 link1399 link1400 link1401 link1402 link1403 link1404 link1405 link1406 link1407 link1408 link1409 link1410 link1411 link1412 link1413 link1414 link1415 link1416 link1417 link1418 link1419 link1420 link1421 link1422 link1423 link1424 link1425 link1426 link1427 link1428 link1429 link1430 link1431 link1432 link1433 link1434 link1435 link1436 link1437 link1438 link1439 link1440 link1441 link1442 link1443 link1444 link1445 link1446 link1447 link1448 link1449 link1450 link1451 link1452 link1453 link1454 link1455 link1456 link1457 link1458 link1459 link1460 link1461 link1462 link1463 link1464 link1465 link1466 link1467 link1468 link1469 link1470 link1471 link1472 link1473 link1474 link1475 link1476 link1477 link1478 link1479 link1480 link1481 link1482 link1483 link1484 link1485 link1486 link1487 link1488 link1489 link1490 link1491 link1492 link1493 link1494 link1495 link1496 link1497 link1498 link1499 link1500 link1501 link1502 link1503 link1504 link1505 link1506

[Vue.js] vuejs undefined value when switching template

I’m porting a list to a table to further expand out the columns in the future, but I’m running into an undefined variable error, which I don’t understand.

Here’s the existing list:

<ul class=”collection with-header”>
<li class=”collection-item” v-for=”day in days”>
<drop @drop=”function(data, event) { handleDrop(data, day, event); }”>
<div>{ day.getLabel() }</div>
<drag class=”chip” v-for=”meal in day.meals”>{ meal.title }<i class=”close material-icons” v-on:click=”deleteMeal(meal)”>close</i></drag>
</drop>
</li>
</ul>

And here’s the new table:

<table>
<tr class=”collection-item” v-for=”day in days”>
<td>{ day.getLabel() }</td>
<drop @drop=”function(data, event) { handleDrop(data, day, event); }” tag=”td”>
<drag class=”chip” v-for=”meal in day.meals”>{ meal.title }<i class=”close material-icons” v-on:click=”deleteMeal(meal)”>close</i></drag>
</drop>
</tr>
</table>

When running the code, I get a “day is not defined” error, which seems to occur on the drag line as commenting it out fixes the error. What I don’t understand is why that variable isn’t defined. In both an element has access to the day object to get its label, but in the drop tag, which is identical in both examples, the day object is now out of scope.

Is there something about tables specifically that is causing a problem here?

Solution :

The problem is that the replacement of the component tag with the tag passed to it in the props occurs after the template is transformed into DOM. And in the case of a table, tags that are not allowed to be inside the table are transferred to the DOM before the table:

new Vue({
el: “#app”
})
table {
border: 4px solid green;
}

td {
border: 1px solid red;
}
<script src=”https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id=”app”>
<table>
<tr>
<td>First column</td>
<component :is=”‘td’” tag=”td”>Second column</component>
<td>Third column</td>
</tr>
</table>
</div>

And, accordingly, there will be no variable day in tr scope. So do not use in this case the attribute tag:

<table>
<tr class=”collection-item” v-for=”day in days”>
<td>{ day.label }</td>
<td>
<drop @drop=”function(data, event) { handleDrop(data, day, event); }”>
<drag class=”chip” v-for=”meal in day.meals”>{ meal.title }
<i class=”close material-icons” v-on:click=”deleteMeal(meal)”>x</i>
</drag>
</drop>
</td>
</tr>
</table>

[Vue.js] How to load just routs that I call using Vue.js and Vue-router

when developing an application SPA with Vue.js and I realized that when I call imports to load the routes using Vue-router it is loading everything.

My current code:

import Home from ‘./components/Home/Home.vue’;
import Product from ‘./components/Product/Index.vue’;
import Participant from ‘./components/Participant/Index.vue’;

export const routes = [
{
path: ‘’,
component: Home,
name: ‘home’,
comments: {
default: Home
}
},
{
path: ‘/product’, component: Product
},
{
path: ‘/participant’, component: Participant
},
{ path: ‘*‘, redirect: ‘/‘ }
];

I was wondering if is there anything to load just part of the screen in order to be a truly SPA, I mean when it receives a click on the menu.

My menu code:

<router-link class=”nav-item” tag=”li” to=”/“><a class=”nav-link”>Home</a></router-link>
<router-link class=”nav-item” tag=”li” to=”/product”><a class=”nav-link”>Product</a></router-link>
<router-link class=”nav-item” tag=”li” to=”/participant”><a class=”nav-link”>Participant</a></router-link>

Solution :

there is implemented something in a Vue.js project that I believe is what you looking for using in the application.

You need to change imports to const using resolve approach, however, Home should be as is because it is the default page

You can try the code below:

import Home from ‘./components/Home/Home.vue’;

const Product = resolve => {
require.ensure([‘./components/Product/Index.vue’], () => {
resolve(require(‘./components/Product/Index.vue’));
});
};

const Participant = resolve => {
require.ensure([‘./components/Participant/Index.vue’], () => {
resolve(require(‘./components/Participant/Index.vue’));
});
};

It allows to use lazy load concept, it will only load when called.

[Vue.js] Calculated properties for each element in array

there is a use case where my data store has an array of products, each with a price and quantity.

What I would like to do is calculate the ‘total’ for each product (price x quantity). I can do so by created a new computed property which re-calculates the entire array, appending a new property with the total.

The issue is, this requires recalculating every item in the array every time a single item changes.

I could use a component to calculate and display, but I also need to calculate a total (which is the sum of all computed prices on each product).

Is there a more efficient way to do this?

[
{
“Product ID”: 1,
“Price”: 10,
“Quantity”: 5,
“Calculated Total”: 50
},
{
“Product ID”: 2,
“Price”: 12,
“Quantity”: 10,
“Calculated Total”: 120
}
]

Solution :

You can use a computed value to map through the original array and sum the values. e.g say the original array is named originalArray, do:

computed: {
computedTotal() {
let sum = 0
originalArray.map(item => sum += item[“Calculated Total”])
return sum
}
}

[Vue.js] How to loop a list of object in to a table with custom row using Vue.js

im currently develeping a new application by using Vue.js. there is this list of object i take from my db:

list = [
{ “main”: “main 1”, “sub_main”: “sub main 1”, “title”: “testing”, “description”: “this is description” },
{ “main”: “main 1”, “sub_main”: “sub main 1”, “title”: “trying”, “description”: “this is description 2” },
{ “main”: “main 1”, “sub_main”: “sub main 2”, “title”: “testing again”, “description”: “this is description” },
{ “main”: “main 1”, “sub_main”: “sub main 2”, “title”: “still trying”, “description”: “this is description 2” },
{ “main”: “main 2”, “sub_main”: “sub main 1”, “title”: “testing another”, “description”: “this is description” },
{ “main”: “main 2”, “sub_main”: “sub main 2”, “title”: “i need help”, “description”: “this is description 2” }
]

to loop it with v-for in a table but I need to customize it, so its looks like this

+———————+———————–+
| Main/Sub Main/Title | Description |
+———————+———————–+
| main 1 | |
+———————+———————–+
| sub main 1 | |
+———————+———————–+
| testing | this is description |
+———————+———————–+
| trying | this is description 2 |
+———————+———————–+
| sub main 2 | |
+———————+———————–+
| testing again | this is description |
+———————+———————–+
| still trying | this is description 2 |
+———————+———————–+
| main 2 | |
+———————+———————–+
| sub main 1 | |
+———————+———————–+
| testing another | this is description |
+———————+———————–+
| sub main 2 | |
+———————+———————–+
| i need help | this is description 2 |
+———————+———————–+

currently im just manage to make it every record in one row

<tr v-for=”(data) in list” >
<td>{data.main}</td>
<td>{data.sub_main}</td>
<td>{data.title}</td>
</tr>

can you guys give me a pointer on how to solve this problem?

Solution :

first you need to transform the data type into suitable type to loop. I transform the data in computed become like this:

// computed function

computed: {
sortedList() {
const sortedList = this.list.reduce((result, item) => {
const { main, sub_main, title, description } = item;

// check main exists, example: main 1
if (!result[main]) {
result[main] = {};
}

// check sub_main exsts, example: sub main 1
if (!result[main][sub_main]) {
result[main][sub_main] = [
{
title,
description
}
];
}

// if exists, add other data
result[main][sub_main] = [
…result[main][sub_main],
{ title, description }
];

return result;
}, {});
return Object.entries(sortedList);
}
}

// result
{
‘main 1’:
{
‘sub main 1’: [
{ title: ‘testing’, description: ‘this is description’ },
{ title: ‘testing’, description: ‘this is description’ },
{ title: ‘trying’, description: ‘this is description 2’ }
],
‘sub main 2’: [
{ title: ‘testing again’, description: ‘this is description’ },
{ title: ‘testing again’, description: ‘this is description’ },
{ title: ‘still trying’, description: ‘this is description 2’ }
},
‘main 2’: { … }
}

then I loop in triple v-for in the list I sorted.

<template>
<div id=”app”>
<div class=”wrapper” v-for=”([mainKey, mainValue], index) in sortedList” :key=”index”>
<tr>
<td>{mainKey}</td>
</tr>
<template v-for=”([submainKey, submainValue], index) in Object.entries(mainValue)”>
<tr :key=”index”>
<td>{submainKey}</td>
</tr>
<tr v-for=”({title, description}, index) in submainValue” :key=”index”>
<td>{title}</td>
<td>{description}</td>
</tr>
</template>
</div>
</div>
</template>

Screeshot of the result:

the result screeshot

The codesandbox is provided in below:

https://codesandbox.io/s/64o1p6xv4r

Hope I can solve the problem!

[Vue.js] How to change key name of JSON object via vue js

there is some problems with changing key names “User1” and “User2” of the JSON object with vue.

myJSON = {“User1”: {“damage”: “10000”}, “User2”: {“damage”: “10000”}
users = [“User1”,”User2”,”User3”,”User4”]

This is code of loop, and some comments. Actually problem is I can’t use “key” in v-model…

<div class=”mb-3” v-for=”(item, key, index) in myJSON”>
<el-select v-model=”key” filterable placeholder=”Select”> // This is doesn’t work - it’s my problem =)
<el-option
v-for=”cl in users”
:key=”cl”
:label=”cl”
:value=”cl”>
</el-option>
</el-select>
<el-input-number v-model=”item.damage”></el-input-number> // It’s okey, damage is changing.
</div>

there is already tried to change v-model on:

v-model=”item.key” // JSON after this
myJSON = {“User1”: {“damage”: “10000”, “key”: “User3”}, “User2”: {“damage”: “10000”, “key”: “User4”}

v-model=”myJSON[key]“ // Have error
TypeError: Cannot read property ‘myJSON’ of undefined

v-model=”myJSON[key]“ // Same
TypeError: Cannot read property ‘myJSON’ of undefined

After select user in <el-select> i need smth like this:

{“User2”: {“damage”: “10000”}, “User3”: {“damage”: “10000”}

Or

{“User3333”: {“damage”: “10000”}, “User312321”: {“damage”: “10000”}

But I’m on the not right way, please help.

Solution :

Not sure if you can directly change an obj’s key with v-model, but there is a workaround.

<div id=”app”>
<ol>
<li v-for=”(item, index) in myJSON_format2”>
{item}
<input v-model=”item.damage”/>
<input v-model=”item.key”/>
</li>
</ol>
</div>

new Vue({
el: “#app”,
data: {
myJSON: {“User1”: {“damage”: “10000”}, “User2”: {“damage”: “10000”},
myJSON_format2: []
},
methods: {
change_myJSON_toFormat2 () {
for (let i in this.myJSON) {
this.myJSON_format2.push({ damage: this.myJSON[i].damage, key: i })
}
}
},
created () {
this.change_myJSON_toFormat2()
}
})

Pls check it out here: https://jsfiddle.net/shivampesitbng/dync94kt/24/

Workaround:

Changed the ds of myjson to array of obj
looped the arr with v-for in vue-template
changed the “user” key as you were changing “damage” key.

[Vue.js] Why routes are not added $router.addRoutes?

Why routes are not added $ router.addRoutes?
I tried everything I can not

async loadMenu() {
try{
let res = await this.$http.get(‘/menu’)
this.menuItems = res.data
res.data.forEach((e) => {
this.$router.addRoutes([
{
path: /${e.url},
name: ${e.name},
component: require(`${e.compURL}`)
},
])
console.log(e)
})
}catch(err){
console.log(err)
}
},

I can not understand why not add dynamic routes?
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

const router = new Router({
routes: [
{
path: ‘/‘,
name: ‘home’,
component: Home,
meta: {
title: ‘EHZ’,
layout: ‘default-layout’,
catId: 1
}
},
],
mode: ‘history’,
// base: locale,
})

router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {

Vue.axios.post(‘/auth/token’)
.then((res) => {
if ( res.status === 200 )
next()
})
.catch((e) => {
store.dispatch(‘logout’)
next({ path: ‘/auth/login’})
})
}
else {
next()
}
})

export default router;

I added the code from the router.js.
Something else needs to be shown?

I added a picture that I get in res.data

image res.data

Solution :

Well, you can achieve it as per below

Inside header.vue.js file

<template>
<div class=”hello”>
<h1>{ msg }</h1>
<router-link to=”/“>Home</router-link>
<div v-for=”menu in dynamic” :key=”menu.path”>
<router-link :to=”menu.path”>{menu.name}</router-link>
</div>
</div>
</template>

<script>
import About from “@/components/About”;
import Contact from “@/components/Contact”;
export default {
name: “Header”,
data: function() {
return {
msg: “Header Component!”,
dynamic: [
{
name: “About”,
component: “About”,
path: “/about”
},
{
name: “Contact”,
component: “Contact”,
path: “/contact”
}
]
};
},
created() {
console.log(“inside created”);
const routes = this.routerFormat(this.dynamic);
console.log(“routes “, routes);
this.$router.addRoutes(routes);
},
methods: {
routerFormat: function rFormat(routers) {
console.log(“inside routerFormat”);
if (!(routers instanceof Array)) {
return false;
}
let fmRouters = [];
routers.forEach(router => {
let { path = “/404”, component = “Error”, name, children } = router;
path = path || “”;
component = component || “Error”;
if (children && children instanceof Array) {
children = rFormat(children);
}
console.log(“component”, component);
let fmRouter = {
path: path,
// component: name,
component: () => import(`./${name}.vue`).then(m => m),
name: name,
children: children
};
console.log(fmRouter);
fmRouters.push(fmRouter);
});
console.log(“fmRouters”, fmRouters);
return fmRouters;
},
addRoutes() {}
}
};
</script>

Hope it helps!

[Vue.js] How can I do something like React componentwillreceiveprops in vue

I sent props to child component by click event and then I use computed to take condition but I cant control newprops and oldprops. I dont need the computed take action every click. How can I do this?

Solution :

I think You Have to Use Watchers in vue.js
That watch always when data change
Follow this guideline
Computed Property and Watchers in vue.js

[Vue.js] vuejs not update component

When I click on links, mounted() works, but new template not loading from server, vue.js not send AJAX request if route is changed.

<section class=”content”>
<router-view :key=”$route.fullPath”></router-view>
</section>

<router-link to=”/foo”></router-link>
<router-link to=”/bar”></router-link>
<router-link to=”/somelink”></router-link>

var testComponent = Vue.component(‘main-section’, (resolve) => {
axios.post(‘/test.php’).then( (res) => {
resolve({
template: res.data,
mounted: () => {
console.log(‘mounted-‘ + new Date().getTime());
}
});
});
});

var router = new VueRouter({
routes: [
{ path: ‘/foo’, component: testComponent },
{ path: ‘/bar’, component: testComponent },
{ path: ‘*‘, component: testComponent }],
mode: ‘history’
});

Solution :

the component is the same for all of the routes, so vue.js will load testComponent only one time. Once it has loaded a component, vue.js will never reload it again.

[Vue.js] bind Kendo vue dropdownlist to array of objects

SAMPLE https://stackblitz.com/edit/usjgwp?file=index.html

to show a number of kendo dropdownlist(s) on a page. The exact number depends on an API call. This API call will give me an array of stakeholder objects. Stakeholder objects have the following properties: Id, name, type, role and isSelected.

The number of dropdownlist that has to be shown on this page should be equal to the number of unique type values in the API response array. i.e,
numberOfDropdowns = stakeholders.map(a => a.type).distinct().count().

Now, each dropdown will have a datasource based on the type property. i.e, For a dropdown for type = 1, dataSource will be stakeholders.filter(s => s.type == 1).

Also the default values in the dropdowns will be based on the isSelected property. For every type, only one object will have isSelected = true.

there is achieved these things by using the following code:

<template>
<div
v-if=”selectedStakeholders.length > 0”
v-for=”(stakeholderLabel, index) in stakeholderLabels”
:key=”stakeholderLabel.Key”
\>
<label>{ stakeholderLabel.Value }:</label>
<kendo-dropdownlist
v-model=”selectedStakeholders[index].Id”
:data-source=”stakeholders.filter(s => s.type == stakeholderLabel.Key)”
data-text-field=”name”
data-value-field=”Id”
\></kendo-dropdownlist>

<button @click=”updateStakeholders”>Update form</button>
</div>
</template>

<script>
import STAKEHOLDER_SERVICE from “somePath”;
export default {
name: “someName”,
props: {
value1: String,
value2: String,
},
data() {
return {
payload: {
value1: this.value1,
value2: this.value2
},
stakeholders: [],
selectedStakeholders: [],
stakeholderLabels: [] // [{Key: 1, Value: “Stakeholder1”}, {Key: 2, Value: “Stakeholder2”}, … ]
};
},
mounted: async function() {
await this.setStakeholderLabels();
await this.setStakeholderDataSource();
this.setSelectedStakeholdersArray();
},
methods: {
async setStakeholderLabels() {
let kvPairs = await STAKEHOLDER_SERVICE.getStakeholderLabels();
kvPairs = kvPairs.sort((kv1, kv2) => (kv1.Key > kv2.Key ? 1 : -1));
kvPairs.forEach(kvPair => this.stakeholderLabels.push(kvPair));
},
async setStakeholderDataSource() {
this.stakeholders = await STAKEHOLDER_SERVICE.getStakeholders(
this.payload
);
}
setSelectedStakeholdersArray() {
const selectedStakeholders = this.stakeholders
.filter(s => s.isSelected === true)
.sort((s1, s2) => (s1.type > s2.type ? 1 : -1));

selectedStakeholders.forEach(selectedStakeholder =>
this.selectedStakeholders.push(selectedStakeholder)
);
},
async updateStakeholders() {
console.log(this.selectedStakeholders);
}
}
};
</script>

The problem is that when not able to change the selection in the dropdownlist the selection always remains the same as the default selected values. Even when I choose a different option in any dropdownlist, the selection does not actually change.

I’ve also tried binding like this:

<kendo-dropdownlist
v-model=”selectedStakeholders[index]“
value-primitive=”false”
:data-source=”stakeholders.filter(s => s.type == stakeholderLabel.Key)”
data-text-field=”name”
data-value-field=”Id”
\></kendo-dropdownlist>

If I bind like this, when able to change selection but then the default selection does not happen, the first option is always the selection option i.e, default selection is not based on the isSelected property.

My requirement is that there is to show the dropdown with some default selections, allow the user to choose different options in all the different dropdowns and then retrieve all the selection then the update button is clicked.

UPDATE:
When I use the first method for binding, The Id property of objects in the selectedStakeholders array is actually changing, but it does not reflect on the UI, i.e, on the UI, the selected option is always the default option even when user changes selection.
Also when I subscribe to the change and select events, I see that only select event is being triggered, change event never triggers.

Solution :

So it turns out that it was a Vue.js limitation (or a JS limitation which vue.js inherited),
Link

I had to explicitly change the values in selectedStakeholders array like this:

SAMPLE https://stackblitz.com/edit/usjgwp?file=index.html

to show a number of kendo dropdownlist(s) on a page. The exact number depends on an API call. This API call will give me an array of stakeholder objects. Stakeholder objects have the following properties: Id, name, type, role and isSelected.

The number of dropdownlist that has to be shown on this page should be equal to the number of unique type values in the API response array. i.e, numberOfDropdowns = stakeholders.map(a => a.type).distinct().count().

Now, each dropdown will have a datasource based on the type property. i.e, For a dropdown for type = 1, dataSource will be stakeholders.filter(s => s.type == 1).

Also the default values in the dropdowns will be based on the isSelected property. For every type, only one object will have isSelected = true.

there is achieved these things by using the following code:

<template>
<div
v-if=”selectedStakeholders.length > 0”
v-for=”(stakeholderLabel, index) in stakeholderLabels”
:key=”stakeholderLabel.Key”
\>
<label>{ stakeholderLabel.Value }:</label>
<kendo-dropdownlist
v-model=”selectedStakeholders[index].Id”
:data-source=”stakeholders.filter(s => s.type == stakeholderLabel.Key)”
data-text-field=”name”
data-value-field=”Id”
@select=”selected”
\></kendo-dropdownlist>

<button @click=”updateStakeholders”>Update form</button>
</div>
</template>

And in methods:

selected(e) {
const stakeholderTypeId = e.dataItem.type;
const selectedStakeholderIndexForTypeId = this.selectedStakeholders.findIndex(
s => s.type == stakeholderTypeId
);
this.$set(
this.selectedStakeholders,
selectedStakeholderIndexForTypeId,
e.dataItem
);
}

[Vue.js] Vue equivalent of {{content?.body}} interpolation

In angular we could do something like {content?.body} and it will render the content body if it exist in the data.

This doesn’t seem to work in Vue. Is there a way to achieve this or there is to check manually.

Solution :

In vue.js you can use v-if directive. For example;

<div v-if=”content.body”>
{content.body}
</div>

See for more at vue.js official docs

Solution 2:

This syntax does not exist in vue.js and it will probably never exists according to the creator of Vue.js (see this post)

However you could use get from lodash combined with computed property to simulate this behavior :

computed: {
nestedProperty() {
return get(this, ‘here.is.my.nested.property’)
}
}

But the easiest way is probably to just add v-if directive to the template to check that property exists

Solution 3:

Im guessing youre looking for a similar approach to optional unwrap from swift or safe call operator from kotlin.
Neither JS or Vue.js support this.

the safest bet is to use a v-if on the entire chain

<span v-if=content && content.body>
{content.body}
</span>