How can I loop object observer on vue.js 2? - vue.js

If I console.log(this.list), the result like this :
this.list.forEach(function (user) {
selected.push(user.id);
});
There exist error :
Uncaught TypeError: this.list.forEach is not a function
How can I solve this error?

Is this.list not an Array?
If this.list is array-like (there must be a length property on that object), you should be able to do:
Array.prototype.forEach.call(this.list, user => {
// ...
})
or
Array.from(this.list).forEach(user => {
// ...
})
or
[...this.list].forEach(user => {
// ...
})
Otherwise if this.list is just a plain object, you can do:
Object.keys(this.list).forEach(key => {
const user = this.list[key]
// ...
})
or
Object.entries(this.list).forEach(([key, user]) => {
// ...
})

Here is a way to loop over an observer array in Vue:
let keys = Object.keys(myObserverArray);
keys.forEach(key => {
let item = myObserverArray[key];
//...work with item
})

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 []
}

this.state return empty array when render

I wanted to display the array series and when I tried to console the array this.state.series in the function it does has the result and the value inside but when I render this.state.series just keep giving empty array. I wonder is it because of the componentDidMount()?
constructor(props){
super(props);
this.state={series:[]}
}
GetTransaction=()=> {
var APIURL="http://10.0.2.2:80/api/getTransaction.php";
var headers={
'Accept':'application/json',
'Content-Type':'application.json'
}
fetch(APIURL,
{
method:'POST',
headers: headers,
})
.then((response)=>response.json())
.then((response)=>
{
this.setState({results:response});
this.state.results[0].map((a) => {
this.state.series.push(a.count)
});
console.log(this.state.series)
})
.catch((error)=>
{
alert("Error"+error);
}
)
}
componentDidMount(){ // runs after the component output has been rendered to the DOM
this.GetTransaction();
}
render(){
console.log(this.state.series)
output
Array []
Array []
Array []
Array []
Array []
Array []
Array []
Array [
"1",
"2",
"1",
"1",
]
There are basically 2 errors in GetTransaction state assignment:
you can't read a state just assigned because this.setState is async. If you want to get the very last value of state you should use this.setState's callback:
this.setState({results:response}, () => {
console.log(this.state.result); //<-- here you have the very last value of result
});
state must be always setted with this.setState: this.state.series.push(a.count) is not good.
So you have to rewrite your code in this way:
...
this.setState({results:response}, () => {
let seriesAppo = [];
this.state.results[0].map((a) => {
seriesAppo.push(a.count);
});
this.setState({series: seriesAppo}, () => {
console.log(this.state.series);
})
});
...
That‘s weird
this.state.results[0].map((a) => {
this.state.series.push(a.count)
});
Don‘t manipulate state that way, only with setState.
const series = response[0];
this.setState({series: series});
Even if you wanna add elements to an array you have to recreate the array. You can achieve this as follows:
const series = response[0];
this.setState({series: […this.state.series, …series]});

How to get array of specific attributes values in cypress

I have a few elements in DOM and each of them has its own attribute 'id'. I need to create a function which iterates throw all of these elements and pushes values into the array. And the happy end of this story will be when this function will give me this array with all 'id' values.
I have tried this:
function getModelIds() {
let idList = [];
let modelId;
cy.get(someSelector).each(($el) => {
cy.wrap($el).invoke('attr', 'id').then(lid => {
modelId = lid;
idList.push(modelId);
});
});
return idList;
}
Will be very appreciated if you help me with rewriting this code into a function which will return an array with all 'id' values.
You can have a custom command:
Cypress.Commands.add(
'getAttributes',
{
prevSubject: true,
},
(subject, attr) => {
const attrList = [];
cy.wrap(subject).each($el => {
cy.wrap($el)
.invoke('attr', attr)
.then(lid => {
attrList.push(lid);
});
});
return cy.wrap(attrList);
}
);
You can use it later like this:
cy.get(someSelector)
.getAttributes('id')
.then(ids => {
cy.log(ids); // logs an array of strings that represent ids
});

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

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.