Calling a method into another method in vue - vuejs2

I'm trying to call a method from inside another method in vue.
What I get is an undefined in my console, but what I really want is the id that is called in the getId function
In a whole what I'm tring to do is use the addEvent function to get the checkbox events so that I can get a true or false from it and then send that to the saveCheckbox function and from the saveCheckbox function call the getId function to get the ID of that specific checkbox.
I hope I was able to explain it properly. If it's still unclear please let me know.
This is what I have
<template>
<div class="card-body">
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">Active</th>
<th scope="col">Title</th>
</tr>
</thead>
<tbody>
<tr v-for="(category, index) in categories" >
<td>
<input name="active" type="checkbox" v-model="category.active" #change="getId(category.id)" #click="addEvent">
</td>
<td>
{{ category.title }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: [
'attributes'
],
data(){
return {
categories: this.attributes,
}
},
methods: {
getId(id){
console.log(id);
return id
},
saveCheckbox(event){
console.log(this.getId());
},
addEvent ({ type, target }) {
const event = {
type,
isCheckbox: target.type === 'checkbox',
target: {
value: target.value,
checked: target.checked
}
}
this.saveCheckbox(event.target.checked)
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>

You have to pass argument (Id) to getId method

Having a sort overview, you are not passing any Id to the method, and it trys to return that id. so maybe, that is what is not defined ?
The method calling is done well. with the this. keyword before it

Related

Vue 3 Array state change doesn't trigger watcher

I have a table with a checkbox for each row and a head checkbox which selects all of them, when any checkbox state is changed, it should trigger an event but for some reason when i use the main checkbox to check them all, the watcher doesn't get triggered until i unchecked it:
template:
<table>
<thead>
<tr>
<th>
<input
type="checkbox"
class="form-check-input widget-9-check"
:name="name"
v-model="areAllItemsSelected"
/>
</th>
</tr>
</thead>
<tbody>
<tr v-for="..."> //here is rowIndex
<td>
<input
type="checkbox"
class="form-check-input widget-9-check"
:value="rowIndex"
v-model="selectedItems"
/>
</td>
</tr>
</tbody>
</table>
setup:
setup(props, {emit}) {
const selectedItems = ref([])
const areAllItemsSelected = ref(false)
watch(areAllItemsSelected, (newValue) => {
if(newValue) {
items.value.forEach((item, index) => {
selectedItems.value.push(index) //this should trigger the below watcher
})
} else {
selectedItems.value = []
}
})
watch(selectedItems, (newValue) => { //this doesn't run when areAllItemsSelected is checked, only when is unchecked
emit('itemSelected', newValue)
})
return {
items,
selectedItems,
areAllItemsSelected
}
}
Vue 3 requires the deep watcher flag when watching arrays. Pass the deep flag in the third argument of watch():
watch(selectedItems, (newValue) => {/*...*/}, { deep: true })
👆
demo

How can I get a result from a POST request into a v-for?

I have something like this:
<table class="table">
<tbody>
<tr v-for="(option, index) in Weapons">
<td>Primary</td>
<td>[[ getWeaponType(option.WeaponType) ]]</td>
</tr>
</tbody>
</table>
In my Vue object, in methods, I have this:
getWeaponType: function(weaponTypeNumber){
axios.get('/path/to/api')
.then(response => {
return response.data
})
}
I send an ID and it returns the name for that ID. But I need for it to show in my table whose rows are being generated by the v-for. This isn't working since it is a Promise and the values are not showing. Is there any way I can achieve getting that value to show in the table? I didn't want to do it server side so I'm trying to see if I have any options before I do that.
May I suggest an alternative method?
data() {
return {
weaponsMappedWithWeaponTypes: [];
}
}
mounted() { // I am assuming the weapons array is populated when the component is mounted
Promise.all(this.weapons.map(weapon => {
return axios.get(`/path/to/api...${weapon.weaponType}`)
.then(response => {
return {
weapon,
weaponType: response.data
}
})
).then((values) => {
this.weaponsMappedWithWeaponTypes = values
})
}
computed: {
weaponsAndTheirWeaponTypes: function () {
return this.weaponsMappedWithWeaponTypes
}
}
And then in your template
<table class="table">
<tbody>
<tr v-for="(option, index) in weaponsAndTheirWeaponTypes">
<td>Primary</td>
<td>option.weaponType</td>
</tr>
</tbody>
</table>

Load More Data On Scroll With Vue And Vuex

I would like to ask how can I display more data by using Vue and vuex. all data stored in vuex-store management already. From State management now I want to load more data on scrolling.
I found online solution by ajax. but I need to loading form state management (Vuex).
This is my Vue template:
<template>
<div>
<div class="panel panel-default">
<div class="panel-body">
<table class="table table-bordered table-striped">
<thead>
<tr>
<tr>
<th>Name - Number of Products: <span style="color: red"> {{products}} </span></th>
<th width="100"> </th>
</tr>
</tr>
</thead>
<tbody v-if="isLoaded">
<tr v-for="company, index in companies">
<td>{{ company.name }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
data: function () {
return { }
},
computed: {
companies(){
return this.$store.getters['exa1Company/getProducts'];
},
products(){
return this.$store.getters['exa1Company/countProducts'];
}
},
mounted() {
this.$store.dispatch('exa1Company/indexResource');
}
}
</script>
My vuex store file is partial for simplicity
export const getters = {
countProducts(state) {
return state.list.data.length;
},
getProducts(state) {
return state.list.data;
},
getTodoById: (state) => (id) => {
return state.list.data.find(tod => tod.id === id)
}
};
export default {
namespaced: true,
state: customerState,
getters,
actions,
mutations,
};
something like this should work. use companiesLoaded in the template, and increase page when scrolled to bottom. I hope this helps.
data: function () {
return {
page: 1,
perPage: 20
}
},
computed: {
companies(){
return this.$store.getters['exa1Company/getProducts'];
},
companiesLoaded(){
return this.companies.slice(0, this.page * this.perPage)
},
...

Vue - axios - handling same requests

In my project I've got such structure:
Client page which has sidebar, general client's info and router-view for children views.
routes:
{ path: '/clients/:id', component: Client,
children: [
{
path: '/',
component: ClientReview,
name: 'client-review'
},
{
path: 'balances',
component: ClientBalances,
name: 'client-balances'
},
{
path: 'report',
component: MainReport,
name: 'client-report'
},
Client's component (Client.vue):
<template>
<el-row>
<client-menu></client-menu>
<el-col class="client-view" :md="{ span: 22, offset: 2}" :sm="{ span: 20, offset: 4}" :xs="{ span: 18, offset: 6}">
<client-bar></client-bar>
<transition name="el-zoom-in-center">
<router-view></router-view>
</transition>
</el-col>
</el-row>
</template>
<script>
import ClientMenu from './ClientMenu.vue'
import ClientBar from './ClientBar.vue'
export default {
data () {
return {
loading: false,
};
},
components: {
'client-menu': ClientMenu,
'client-bar': ClientBar,
}
}
</script>
ClientBar component (ClientBar.vue):
<template>
<div class="client-bar">
<el-col :span="18">
<h3>{{ client.Name }}</h3>
<h4>{{ client.Address }}</h4>
</el-col>
<el-col :span="6" style="text-align: right;">
<el-button-group>
<el-button icon="edit" size="small"></el-button>
<el-button icon="share" size="small"></el-button>
</el-button-group>
</el-col>
<div class="clrfx"></div>
</div>
</template>
<script>
export default {
data () {
return {
client: {}
}
},
mounted () {
this.loadClient()
},
methods: {
loadClient: function() {
self = this;
this.axios.get('http://127.0.0.1:8020/clients/'+self.$route.params.id)
.then(function(response) {
self.client = response.data;
self.loading = false;
})
.catch(function(error) {
console.log(error);
});
}
}
}
</script>
And I've got ClientReview component, which is root component for clients/:id route and use the same api to load clients information as ClientBar:
<template>
<div>
<el-row v-loading.body="loading">
<el-col :span="12">
<table class="el-table striped">
<tr>
<td class="cell">Полное наименование</td>
<td class="cell">{{ clientInfo.FullName }}</td>
</tr>
<tr>
<td class="cell">УНП</td>
<td class="cell">{{ clientInfo.UNP }}</td>
</tr>
<tr>
<td class="cell">ОКЭД</td>
<td class="cell">{{ clientInfo.Branch.code }}<br>{{ clientInfo.Branch.name }}</td>
</tr>
<tr>
<td class="cell">Адрес</td>
<td class="cell">{{ clientInfo.Address }}</td>
</tr>
<tr>
<td class="cell">Аналитик</td>
<td class="cell">{{ clientInfo.Analytic.first_name }} {{ clientInfo.Analytic.last_name }}</td>
</tr>
<tr>
<td class="cell">Менеджер</td>
<td class="cell">{{ clientInfo.Manager.first_name }} {{ clientInfo.Manager.last_name }}</td>
</tr>
</table>
</el-col>
<el-col :span="12">
<classification-report></classification-report>
</el-col>
</el-row>
</div>
</template>
<script>
import ClassificationReport from '../reports/ClassificationReport.vue'
export default {
data () {
return {
loading: false,
clientInfo: {}
}
},
created () {
this.Client();
},
methods: {
Client: function() {
self = this;
self.loading = true;
self.axios.get('http://127.0.0.1:8020/clients/'+self.$route.params.id)
.then(function(response) {
self.clientInfo = response.data;
self.loading = false;
})
.catch(function(error) {
console.log(error);
});
}
},
components: {
'classification-report': ClassificationReport
}
}
</script>
The problem is when I load page client/:id first time or refresh the page client's data in ClientReview doesn't load.
The component is rendered (as I see it in Vue Devtools), and both requests to server are sent, but clientInfo object in ClientReview still empty.
Than if I go to balances or report page and after that go to client-review page everything is loaded.
Hope someone could help me.
It's because self happens to be another reference to the window object, and is available in all modules.
Let's walk thru the steps and see why this bug is happening.
You load up client:/id.
The created method in ClientReview does ajax request, and assigns self to this.
The mounted method in ClientBar does ajax request, and reassigns self to this. Note that this also changed the self variable reference in ClientReview.
The ClientReview ajax finishes and assigns self.clientInfo = response.data;. Since self is a reference to ClientBar, and ClientBar does not declare clientInfo as a root data property, this assignment does nothing.
ClientBar ajax finishes and assigns self.client = response.data;, which works.
You route away from ClientReview.
You route back to ClientReview. Repeat step 2.
ClientReview successfully renders because ClientBar has already rendered, and does not reassign self.
The answer is to do let self = this instead of self = this.
The lesson is ALWAYS DECLARE YOUR VARIABLES with var, let or const.

Vue data referencing issue

This is strange because it was just working last night, but basically I have a Vue app that's pulling JSON from my backend. Code below. The strange part is that while the loadData function is running and I see the 'Loaded Data' message in console along with the list of items from the JSON, I then get a console error saying 'items is not defined'. I must have made a subtle typo or some dumb change but I can't find it anywhere!! Any ideas?
HTML snippet:
<div id="app">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Query</th>
<th>Initiated By</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr>
<div v-for="item in items">
<td>{{ item.id }}</td>
<td>{{ item.query }}</td>
<td>{{ item.user }}</td>
<td>{{ item.type }}</td>
</div>
</tr>
</tbody>
</table>
</div>
</div>
(And then <script src="app.js"></script> right before </body>)
JS code:
new Vue({
el: '#app',
data: {
items: [],
interval: null
},
methods: {
loadData: function () {
$.get('http://localhost:4567/getQueue', function (response) {
this.items = response.results;
console.log("Loaded data.")
console.log(response.results)
}.bind(this));
}
},
created: function () {
console.log("Loading data...")
this.loadData();
console.log(items)
this.interval = setInterval(function () {
this.loadData();
}.bind(this), 3000);
},
beforeDestroy: function(){
clearInterval(this.interval);
}
});
You are getting the error
items is not defined
because of following line:
created: function () {
console.log("Loading data...")
this.loadData();
console.log(items) <== this should be console.log(this.items)
Turns out there was a few issues in my code.
1) As was pointed out by Saurabh, I forgot to put this.items instead of items.
2) this can't be referenced inside of the function I defined as I have it... instead, the function has to be defined with =>, for example:
$.get('http://localhost:4567/getQueue').then((response) => {
this.items = response.data.results;
console.log("loadData finished - items length is: "+this.items.length)
})
3) The big error I had was that my div bind with items was inside the table tag, which apparently isn't okay to do. Instead I applied the Vue binds to the existing tags (table, tr).