Why "Error in render: TypeError: Cannot read property 'filter' of undefined" returned even data already available? - vue.js

I already initialize the data.
data () {
return {
current_product: {},
current_ID: '',
}
}
Then, I fetch data from a REST API on lifecycle created hook.
created () {
var skuID = this.$store.state.selected_productSKU.productSKU_ID
axios.get(`http://localhost:8081/api/products/${skuID}`)
.then(response => {
this.current_ID = response.data.product_ID
this.current_product = response.data
})
.catch(e => {
alert(e)
})
}
And finally, I use computed property to get some value
// THIS JUST RETURN ['XL', 'M']
focusedProduct_SKUS_NoDupSizes () {
var newArr = this.current_product.product_SKU.filter((sku, index, self) =>
index === self.findIndex(t => (
t.productSKU_size === sku.productSKU_size
))
)
var x = newArr.map(a => a.productSKU_size)
return x
}
The vue instance show expected result
But if i call {{ focusedProduct_SKUS_NoDupSizes }} in template.
It doesn't rendered.
The browser return error Error in render: "TypeError: Cannot read property 'filter' of undefined"
What is happening? My first guess is the computed property using the initial structure of current_product which is {} empty object. But isn't that how to initialize an object?

Because of:
computed:
// ...
focusedProduct_SKUS_NoDupSizes () {
var newArr = this.current_product.product_SKU.filter((sku, index, self) =>
^^^^^^^^^^^
You should initialize product_SKU with an empty array:
data () {
return {
current_product: {product_SKU: []}, // changed here
current_ID: '',
}
}
This is needed because the computed property will be executed right away, even before your Ajax gets a chance to return.
Declare it as empty so the computed doesn't throw an error. When the Ajax fulfills, it will recompute automatically.
Even though the Ajax is started at the created(), it won't return before the computed is executed for the first time. More details about this here.

Related

Vuex getter returns undefined value

I'm trying to write a getter for my state the problem is that it returns an undefined value but I'm 100% sure that in articleEan is an object that has an Are_EanNr value of 1234567.
This is the getter I'm writing is supposed to return the first object in the articleEan Array that has the same EanNr as the parameter.
const getters = {
findArByEan: state => {
return (eancode) => { // logging eancode results in 1234567
state.articleEan.find(item => {
return item.Are_EanNr === eancode
})
}
}
}
Where's my mistake?
After Changing it to:
findArByEan: (state) => (eancode) => state.articleEan.find(item => item.Are_EanNr === eancode),
Problem still occurs. This is how I'm calling the getter from a component:
const getters = {
...useGetters('vm', [
'orderRow',
'customer',
'article',
'additionalData',
'findArByEan',
]),
...useGetters('user', ['user']),
};
const Ar = getters.findArByEan.value(eancode.value); // Ar = undefined
Edit:
When looping over the state I'm getting just the indices of the object in array.
log('ArtEan:', artEan.value); // correct output => Array with 38 objects
for(const item in artEan.value) {
log(item); // Logs just the index of array
}
Your second arrow function does not return anything so it's undefined
const getters = {
findArByEan: state => {
return (eancode) => { // logging eancode results in 1234567
return state.articleEan.find(item => {
return item.Are_EanNr === eancode
})
}
}
}
You can also do it this way without any return.
const getters = {
findArByEan: (state) => (eancode) => state.articleEan.find(item => item.Are_EanNr === eancode)
}
I would recommand reading the arrow function documentation.
For example, those 2 functions works the same but one is tidier ;)
const numberSquare1 = (number) => {
return number * number
}
const numberSquare2 = (number) => number * number
console.log(numberSquare1(2))
console.log(numberSquare2(2))

TypeError: Cannot read properties of undefined (reading 'products')

I am trying to get products, then check if the product pId is in an array, and filter if it is.
I get an error when i soft refresh of 'TypeError: Cannot read properties of undefined' (reading 'products'), almost like my 'this.products' isnt populated yet when computed is trying to get the data. Tried adding some if statements to check data is there but no luck.
<script>
export default {
data() {
return {
popular_products: [],
products: [],
}
},
computed: {
bestsellers() {
const keywords = this.popular_products
let array = []
for (var index = 0; index < keywords.length; index++) {
const keyword = this.products.data.products.product.filter(
(product) => product.pId == keywords[index].ProductNumber
)
array = array.concat(keyword)
}
return array
},
},
mounted() {
axios
.get(
'https://myurl/admin/api/collections/get/popularproducts?token=account-9306f9192049d3c442e565f2de5372'
)
.then((response) => (this.popular_products = response.data.entries))
axios
.get('https://myurl/products.json')
.then((response) => (this.products = response))
},
}
</script>
The problem is with this line:
let keyword = this.products.data.products.product.filter(product => product.pId == keywords[index].ProductNumber);
more specific with this read: data.products.
You see, computed property bestsellers is evaluated before your axios calls are finished.
Because of that, Vue can't find products in data because your this.products doesn't have data key.
The best solution would be to change this assignment:
- .then(response => (this.products = response)); // delete this line
+ .then(response => (this.products = response.data.products)); // add this line
Update After comment.
if (this.products.product) {
return this.products.product.filter(...)
} else {
return []
}

Item inside <nuxeo-data-table-column> component passed to a function as an argument yields empty object

<nuxeo-data-table-column>
[[item.title]]
</nuxeo-data-table-column>
This works. Here 'item.title' renders title.
<nuxeo-data-table-column>
[[_callme(item)]]
</nuxeo-data-table-column>
_callme: function (item) {
console.log(item);
}
This doesn't work. Here 'item' is an empty object
Where my I wrong ?
I end up fetching page provider manually and fed to 'items' property to 'nuxeo-data-table' which then works.
Template
<nuxeo-page-provider id="nxProvider">
<nuxeo-data-table items="[[data.entries]]">
<nuxeo-data-table-column>
[[_callme(item)]]
</nuxeo-data-table-column>
</nuxeo-data-table>
</nuxeo-page-provider>
Script
setIntialValue:function(){
this.$.nxProvider.fetch().then(data=>{
this.data = Object.assign({}, data);
})
}
_callme: function (item) { console.log(item); } ->works

Why html shows the object returned by the computed property is ‘undefined’?

I have a error at my vue project.I use computed to return a object.
computed: {
getOpLog() {
if (this.product_menu) {
this.product_menu.forEach(opLogItem => {
if(opLogItem.id === 'menu_item_oplog') {
return opLogItem;
}
});
}
}
},
and my debugger shows that I have the right return object.
But when i run it in brower, it just not work.
[Vue warn]: Error in render: "TypeError: Cannot read property 'hidden' of undefined"
Here is my html.
<el-menu-item v-if="getOpLog.hidden" :id="getOpLog.id">
...
</el-menu-item>
But when I use this
getOpLog() {
if (this.product_menu) {
return this.product_menu[8]
}
}
It work.I want to know how can i fix this.Thx
When your if condition inside the getter is false i.e. if (this.product_menu), then getter will return undefined object. And thus, Vue.js complains.
As a simple remedy, add an extra check in v-if like:
<el-menu-item v-if="getOpLog && getOpLog.hidden" :id="getOpLog.id">
...
</el-menu-item>
Further, using return inside the forEach function of an array doesn't really cause a return from actual getter function. It is just returning from the inner arrow function. You will need to modify your code using Array.prototype.find method:
computed: {
getOpLog() {
if (this.product_menu) {
const item = this.product_menu.find(opLogItem => {
return opLogItem.id === 'menu_item_oplog';
});
return item;
}
}
};
But, you still should have v-if check for getOpLog in case find method returns undefined value.

Iterating with v-for on dynamic item

I'm trying to iterate through a db object I fetch during created(), I get the values in a console.log but the v-for template part remains empty. My sub-question is : is this good practice ? I'm quite new to Vue and my searches on this issue make me think it's a lifecycle issue.
Thanks for the help.
TEMPLATE PART :
.content(v-for="(content, key, index) in contents")
h3 {{key}}
.line
| {{getValue(content)}} // this is blank
METHODS PART:
getValue(value) {
PagesService.fetchDataWrap({
id: value
}).then((response) => {
const test = response.data.values[0].value
console.log(test) //this is working and gives the right value
return test
})
},
getPage() {
PagesService.fetchPage({
id: this.$route.params.page
}).then((response) => {
this.name = response.data.result.name
this.langs = response.data.result.langs
this.project = response.data.result.parent
this.contents = response.data.result.values
})
this.getProject()
}
console.log(this.contents) result :
{__ob__: Observer}
footer: "5a29943b719236225dce6191"
header: "5a29a9f080568b2484b31ee1"
which is the values I want to send when v-for iterates on contents so the getValue can process it to fetch corresponding values
I wouldn't recommend attempting to output the value of an asynchronous method. It's highly unlikely that it will work correctly.
Instead, populate your contents array / object fully during the created hook. For example, this can replace the contents hash value with whatever comes back from fetchDataWrap...
getPage () {
PagesService.fetchPage({
id: this.$route.params.page
}).then(response => {
this.name = response.data.result.name
this.langs = response.data.result.langs
this.project = response.data.result.parent
let contents = response.data.result.values
Promise.all(Object.keys(contents).map(key => {
// map each key to a "fetchDataWrap" promise
return PageService.fetchDataWrap({
id: contents[key]
}).then(res => {
// replace the hash with the resolved value
contents[key] = res.data.values[0].value
})
}).then(() => {
// all done, assign the data property
this.contents = contents
})
})
}
Then you can trust that the content has been loaded for rendering
.content(v-for="(content, key, index) in contents")
h3 {{key}}
.line
| {{content}}