TypeError: Cannot set property of undefined - vue.js

need some support.
I want to show data by click a button or link
<div v-for="hpTheme in hpThemes" :key="hpTheme.id">
<button class="button round success" #click="showDetails(hpTheme.id)">{{hpTheme.hpTitle
}}</button>
</div>
<script>
export default {
data() {
return {
hpTheme: { hpTitle: '', hpContent: '' },
hpThemes: [
{
id: 1,
hpTitle: 'title',
hpContent: 'content'
},
{
id: 2,
hpTitle: 'title2',
hpContent: 'content2'
}
]
}
},
methods: {
showDetails(id) {
for (var i = 0; i <= this.hpThemes.length; i++) {
if (id === this.hpThemes[i].id) {
this.theme.hpTitle = this.hpThemes[i].hpTitle
this.theme.hpContent = this.hpThemes[i].hpContent
}
}
}
}
</script>
But I get this error: TypeError: Cannot set property 'hpTitle' of undefined.
How to solve?
Thanks for support.

variable i shouldn't equal to the this.hpThemes.length
for (var i = 0; i < this.hpThemes.length; i++) { // replace '<=' operator with '<'
...
}

#WilliamWang's answer is perfect to remove that error, but your code be more clean and shorter if you just pass the clicked theme as parameter then assign it to this.theme :
#click="showDetails(hpTheme)"
and
methods: {
showDetails(theme) {
this.hpTheme={hpTitle: theme.hpTitle, hpContent: theme.hpContent }
}
}

I have just changed the this.theme to this.hpTheme below. Hope this works for you.
showDetails(id) {
for (var i = 0; i <= this.hpThemes.length; i++) {
if (id === this.hpThemes[i].id) {
this.hpTheme.hpTitle = this.hpThemes[i].hpTitle
this.hpTheme.hpContent = this.hpThemes[i].hpContent
}
}
}

Related

How can I use a computed function inside a method function?

Hi I am trying to call a computed function inside a method function.
VueJs Code:
<script>
export default {
created() {
this.isDisabled(0);
},
data: function() {
return {
form: {
branch_office_id: null,
cashier_id: null,
gross_amount: '',
released_tickets: '',
start_ticket: '',
end_ticket: '',
z_inform_number: '',
created_at: '',
support: null,
error_end_bill_number_validation: ''
},
postsSelected: "",
branch_office_posts: [],
cashier_posts: []
}
},
methods: {
checkEndBillNumber() {
if(this.form.start_ticket > this.form.end_ticket) {
this.isDisabled(1);
this.$awn.alert("El número de boleta inicial no puede ser ", {labels: {success: "Error"}});
} else {
this.isDisabled(0);
}
}
},
computed: {
isDisabled(value) {
if(value == 0) {
return true;
} else {
return false;
}
}
}
}
</script>
I am trying to user isDisabled() function inside checkEndBillNumber() method function but when I do that it says:
[Vue warn]: Error in v-on handler: "TypeError: this.isDisabled is not a function"
So I wonder how can I use it? how can I do that? Thanks!
Computed properties as mentioned above are not functions. Hence passing arguments like isDisabled(value) wont work. But you can trick it to anonymously accept the value like this
computed: {
isDisabled() {
return (value) => {
if(value == 0) return true;
else return false;
}
}
}
This way you don't need a data property.
You do not have computed functions, but computed properties! So you have to store the value you want to use as a parameter in your computed property - e.g. in a data attribute, and then use that:
<script>
export default {
created() {
this.disabledParam = 0;
this.isDisabled; // Evaluates to "true" - what do you want with that result?
},
data: function() {
return {
form: {
branch_office_id: null,
cashier_id: null,
gross_amount: '',
released_tickets: '',
start_ticket: '',
end_ticket: '',
z_inform_number: '',
created_at: '',
support: null,
error_end_bill_number_validation: ''
},
postsSelected: "",
branch_office_posts: [],
cashier_posts: [],
disabledParam: null,
}
},
methods: {
checkEndBillNumber() {
if (this.form.start_ticket > this.form.end_ticket) {
this.disabledParam = 1;
this.isDisabled; // Evaluates to "false" - what to you want to do with that value?
this.$awn.alert("El número de boleta inicial no puede ser ", {labels: {success: "Error"}});
} else {
this.disabledParam = 0;
this.isDisabled; // Evaluates to "true" - what to you want to do with that value?
}
}
},
computed: {
isDisabled() {
if (this.disabledParam == 0) {
return true;
} else {
return false;
}
}
}
}
</script>
Also, please note that your calls to isDisabled(1) wouldn't so anything even if you could use them as functions. You should probably do something with the return values of isDisabled.
And you do not need computed properties in this way - in your example, you should simply create isDisabled(value) as another method and call that. But I guess your code is just an example, not your real code. Computed properties usually are being used as values in your template.
My example code is just there to illustrate how you can pass parameters into the code of computed properties. Besides that, your code has some issues.

Prevent Vue Multiple Select to Store an Empty Array

I want this select multiple to pre-select one option, and not be able to deselect all options.
Whenever the last selected option is deselected it should be reselected. In other words when the user tries to deselect the last selected option it should visually not be deselected.
<template>
<b-select
if="Object.keys(doc).length !== 0 /* wait until firebase has loaded */"
:options="computedOptions"
v-model="model"
multiple
#input="onChange"
/>
</template>
<script>
//import Vue from 'vue'
import { fb } from "../fbconf";
export default {
name: "MyMultiSelect",
props: {
doc: Object, // firestore document
},
data() {
return {
options: []
};
},
firestore() {
var options = fb.db.collection("options");
return {
options: options
};
},
computed: {
computedOptions: function() {
return this.options.map(function(option) {
return {
text: option.name,
value: option.id
};
});
},
// to make sure mySelectedOptions is an array, before this.doc is loaded
// I use the following custom model
// because not using 'get' below causes a warning:
// [Vue warn]: <select multiple v-model="localValue"> expects an Array value for its binding, but got Undefined
model: {
get: function() {
if (!this.doc.hasOwnProperty('mySelectedOptions')) return []; // empty array before this.doc is loaded
else return this.doc['mySelectedOptions'];
},
set: function(newValue) {
// here I can prevent the empty array from being stored
// but visually the user can deselect all options, which is bad UX
//if (Array.isArray(newValue) && newValue.length > 0) this.doc['mySelectedOptions'] = newValue;
}
},
},
methods: {
onChange: function(newValue){
// I can manually store the array as I want here
// but I cannot in any way prevent the user from deselecting all options
if (Array.isArray(newValue) && newValue.length > 0) this.doc['mySelectedOptions'] = newValue;
else {
// none of these reselects the last selected option
var oldValue = this.doc['mySelectedOptions'];
this.doc['mySelectedOptions'] = this.doc['mySelectedOptions'];
//this.$forceUpdate();
//this.$emit("change", newValue);
//Vue.set(this.doc, 'mySelectedOptions', this.doc['mySelectedOptions']);
}
}
}
};
</script>
You could add watcher and when length becomes 0 just add previous value.
watch: {
model(val, oldVal) {
if(val.length == 0 && oldVal.length > 0) {
// take only one item in case there's clear button or etc.
this.model = [oldval[0]];
}
}
}

How to pass an array values from one function to another function in vuejs?

I am trying to get the array values from
"validateBeforeSubmit" function to "saveForm" function. But I am
getting values of "undefined" in "arrlength". Please help me to solve.
This my code in vue.js
export default {
name: '',
data() {
return {}
},
ready: function() {
this.validateBeforeSubmit()
this.saveForm();
},
methods: {
validateBeforeSubmit() {
var fieldsVal = new Array();
var firstName = document.getElementById('firstName').value
var lastName = document.getElementById('lastName').value
var designation = document.getElementById('designation').value
if (firstName != "" && lastName != "" && designation != "") {
fieldsVal.push(firstName);
fieldsVal.push(lastName);
fieldsVal.push(designation);
return fieldsVal;
} else {
fieldsVal.length = 0;
return fieldsVal;
}
return fieldsVal;
},
saveForm() {
var fieldsValArray = this.validateBeforeSubmit();
var arrLength = fieldsValArray.length;
}
}
}
I can see multiple issues in your code:
1) Don't apply jQuery-like approach for getting input values. Use v-model instead. This will simplify your code
<template>
<input v-model="form.firstName" type="text"/>
</template>
<script>
export default {
data: {
form: {
firstName: '',
}
},
methods: {
validateBeforeSubmit() {
// take `firstName` directly from `data` not need for `getElementById`
const firstName = this.form.firstName;
}
},
}
</script>
2) Remove validateBeforeSubmit and saveForm from ready. Ready hook is obsolete in vue#2. And also it makes no sense. It's better to call it on form #submit.
3) It's better to create array using [] syntax instead of new Array()
Why never use new Array in Javascript
4) Always provide name for your component for easier debug
export default {
name: 'ValidationForm',
}
5) I don't know where was an issue but it works. Check this link below. I have updated your code. Try to submit form and check the console:
https://codesandbox.io/s/w6jl619qr5?expanddevtools=1&module=%2Fsrc%2Fcomponents%2FForm.vue

Use props inside method in vue.js

I have props like below
props: ['applicants',],
I would like to use props like below
methods : {
formated (item) {
var _self = this;
_self.values.length = 0;
if(item == "") {
console.log(this.applicants); //I am getting output here
_self.values = this.applicants
}
else {
console.log(this.applicants); //I am not getting output here
this.applicants.filter(applicant => { })
}
}
}
Why it is happening like this?
You don't need to create a reference to this. Assuming this.values is an array:
methods: {
formatted (item) {
this.values = item == "" ? this.applicants : this.applicants.filter(applicant => { })
}
}

How to use domProps in render function?

here is a custom select component, it works, but I just can not understand some part of the code,
jsFiddle
Vue.component("myselect", {
props: ['option'],
render: function (createElement) {
var self = this
var items = []
for (var i = 0; i < 16; i++) {
items.push(createElement('option', { attrs: { value: i } }, i))
}
return createElement('select', {
domProps: { value: self.option.value }, // v-bind:value = this binds the default value
on: {
input: function (event) {
console.log(event.target.value)
}
}
}, items)
}
})
this sets the default value of select to option.value, is it <select value='2'>, but the html select tag uses <option selected>, looks like magic to me.
domProps refers to element properties, not attributes.
Think of it as something like this...
document.getElementById('mySelect').value = 'Two'
<select id="mySelect">
<option>One</option>
<option>Two</option>
<option>Three</option>
<option>Four</option>
</select>
When you set the value property on a select element, it selects the option with the corresponding value (at least in Firefox and Chrome).