I like to get a store running to get a api call, Ive tryed a lot of examples end all ends up with
[vuex] unknown action type: loadUsers
thats my store:
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);
axios.defaults.baseURL = "https://jsonplaceholder.typicode.com/";
export default new Vuex.Store({
state: {
users: [],
},
actions: {
loadUsers({ commit }) {
Vue.axios.get("users").then((result) => {
commit("SAVE_USERS", result.data);
}).catch((error) => {
throw new Error(`API ${error}`);
});
},
},
mutations: {
SAVE_USERS(state, users) {
state.users = users;
},
},
});
and thats my component to display the received data
<template>
<div class="hello">
<table class="users">
<tr>
<th>Name</th>
<th>Username</th>
<th>Email</th>
</tr>
<tr v-for="user in users" :key="user.id">
<td>{{ user.name }}</td>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
</tr>
</table>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "storenews",
computed: mapState(["users"]),
created() {
this.$store.dispatch("loadUsers");
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
table {
width: 100%;
}
</style>
taken from a working fiddle from this codepen
Is this because of the Quasar Framework that I miss some fancy special stuff?
Thank you
Can you try to call your dispatch like this:
this.$store.dispatch('loadUsers', null, {root:true})
?
Related
Version: Vue CLI 2.6.x
I am trying to resolve two issues:
Issue 1:
My Vue app has subscribed to updates via a websocket. I am getting the data continuously and need to keep the table updated with the received data. However the table remains empty even when the list (aqiDataList) has content in it.
Issue 2:
I also need to pass the aqiDataList to the AQITableComponent (where the actual table was originally suppose to be) but having this same issue
App.vue
<template>
<v-container>
<AQITableComponent :aqiList="aqiDataList" />
<v-simple-table>
<template v-slot:default>
<thead>
<tr>
<th class="text-left">
Name
</th>
<th class="text-left">
Age
</th>
<th>Location</th>
</tr>
</thead>
<tbody>
<tr
v-for="item in aqiDataList"
:key="item.id"
>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td>{{ item.location }}</td>
</tr>
</tbody>
</template>
</v-simple-table>
</v-container>
</template>
<script>
import AQITableComponent from './AQITableComponent';
export default {
name: 'AQIComponent',
components: {
AQITableComponent
},
data: function () {
return {
connection: null,
aqiDataList: []
};
},
mounted() {
},
methods: {
},
created: function () {
console.log("Starting connection to WebSocket Server");
this.connection = new WebSocket("wss://my-websocket.com");
this.connection.onmessage = function (event) {
//console.log(event.data);
let aqiDataString = event.data;
this.aqiDataList = [];
let parsedData = JSON.parse(aqiDataString);
parsedData.forEach((aqiData) => {
this.aqiDataList.push({
... object
});
});
console.log(this.aqiDataList);
};
this.connection.onopen = function (event) {
console.log(event);
console.log("Successfully connected to the echo websocket server...");
};
},
}
</script>
AQITableComponent.vue
<template>
<v-container>
<v-simple-table>
<template v-slot:default>
.. same table as shown above
</template>
</v-simple-table>
</v-container>
</template>
<script>
export default {
name: 'AQITableComponent',
props: ['aqiList'],
data: function () {
},
}
</script>
(1) Try using the arrow function for the onmessage event:
from: this.connection.onmessage = function (event) {...}
to: this.connection.onmessage = (event) => {...}
or: this.connection.addEventListener("message", (event) => {...});
This way the this.aqiDataList will be available on your component. Inside the event callback.
This should also solve the problem (2) since your array is not being updated on the first place.
I deployed my Vue app to Netlify and the backend to heroku. Everything works fine, I can edit, delete and get data from my database, except when I submit the form (creating a new client) and I redirect to this.$router.push("/tabela"); . The data is created, but when I go to the ListComponent.vue (path:'tabela') my data isn't there. It only shows when I refresh the page. Before deploying to heroku, I fixed the issue with window.location.href="/tabela"; instead this.$router.push but now, If I use window.location.href="/tabela" I cannot save to my database anymore. I need to use this.$router.push in order to make it "work" but as I said, then I need to refresh the page to update my table with the new client.
Here is my app https://cadastro-app.netlify.app/ .
CreateComponent.vue
methods: {
submitForm(){
if(this.cliente.cpf === ''){
this.cliente.cpf = 'Não Informado'
}else if(this.cliente.cnpj === ''){
this.cliente.cnpj = 'Não Informado'
}
axios.post('https://cadastro-backend-app.herokuapp.com/clientes', {
data: this.cliente
}).then(function(){
this.cliente = {
nome: '',
sobrenome: '',
email: '',
telefone: '',
cnpj: '',
cpf: ''
}
}).catch(function (error) {
console.log(error);
});
/* window.location.href="/tabela"; */
this.$router.push("/tabela");
}
}
ListComponent.vue
<template>
<div class="row">
<div class="col-md-12 ">
<div class="search">
<input #keyup.enter.prevent="search()" v-model='nomePesquisado' class="form-control mb-3" type="text" placeholder="Pesquisar" aria-label="Search"/>
</div>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Nome completo</th>
<th>Email</th>
<th>telefone</th>
<th>CNPJ</th>
<th>CPF</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="cliente in clientes" :key="cliente._id">
<td>{{ cliente.nome }}</td>
<td>{{ cliente.email }}</td>
<td>{{ cliente.telefone }}</td>
<td>{{ cliente.cnpj }}</td>
<td>{{ cliente.cpf }}</td>
<td>
<router-link :to="{name: 'edit', params: { id: cliente._id }}" class="btn btn-success">Editar
</router-link>
<button #click.prevent="removerCliente(cliente._id)" class="btn btn-danger">Remover</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
clientes: [],
nomePesquisado:''
}
},
created() {
let apiURL = 'https://cadastro-backend-app.herokuapp.com/clientes/';
axios.get(apiURL).then(res => {
this.clientes = res.data;
console.log(this.clientes);
}).catch(error => {
console.log(error)
});
},
methods: {
removerCliente(id){
const apiURL = `https://cadastro-backend-app.herokuapp.com/clientes/${id}`;
const indexOfArrayItem = this.clientes.findIndex(i => i._id === id);
if (window.confirm("Tem certeza que deseja remover este item?")) {
axios.delete(apiURL).then(() => {
this.clientes.splice(indexOfArrayItem, 1);
}).catch(error => {
console.log(error)
});
}
},
search(){
this.$router.push(`results/${this.nomePesquisado}`);
}
}
}
</script>
router index.js
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: () => import("../components/CreateComponent")
},
{
path: "/tabela",
name: "tabela",
component: () => import("../components/ListComponent")
},
{
path: "/edit/:id",
name: "edit",
component: () => import("../components/EditComponent")
},
{
path: "/results/:id",
name: "results",
component: () => import("../components/Results")
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
You are changing the route (this.$router.push("/tabela");) too early
This is what is happening:
You make a POST request
Without waiting for a request to complete, you are telling Vue router to switch to ListComponent (this.$router.push("/tabela");)
Router activates ListComponent component
ListComponent runs a GET request to the server in it's created hook
Result is a "race". Will POST request be fast enough so the GET request sees the new data ?
To be sure, move this.$router.push("/tabela"); inside then
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)
},
...
I wrote such code:
<template>
<div class="home">
<HelloWorld tableTitle="Goods:">
<table class="table table-striped">
<tbody>
<tr v-for="(i, index) in items.data" :key="index">
<td>{{ i.id }}</td>
<td>{{ i.name }}</td>
<td>{{ i.producer }}</td>
<td><font-awesome-icon v-if="i.received" icon="check" /><font-awesome-icon v-else icon="times" /><td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import HelloWorld from "#/components/HelloWorld.vue";
import axios from "axios";
export default {
name: "home",
components: {
HelloWorld
},
data: () => ({
items: {},
errors: []
}),
beforeMount() {
axios
.get("http://40.115.119.247/AgileSelection/tnt/status")
.then(response => {
this.items = response.data;
console.log(this.items);
})
.catch(e => {
this.error.push(e);
});
}
};
<script>
Now, for refreshing information I just use the refresh button.
What and where should I add some lines of code to update information but without refreshing the page? Because, I am updating data every 5 seconds. So I think that manually updating is not so good idea.
do something like this
// data property
data () {
return {
...
interval: null
}
},
// in your created hook
created () {
this.interval = setInterval(this.refreshData, 5000)
},
beforeDestroy () {
clearInterval(this.interval)
},
// in methods property
methods: {
refreshData () {
// fetch data
axios.get("http://40.115.119.247/AgileSelection/tnt/status")
.then(response => {
this.items = response.data
})
}
}
this will fetch your data from your API and update the list automatically. this will update your UI as well.
you can try using location.reload() after the code where you register the update
for example
handleSubmit() {
this.registerServices(this.organization)
location.reload();
}
I'm having this setup where I have child component props that have datetime format inside it and I want to change it to more human readable format in my table, so i use moment js to change the format and to do those kinds of task it will be made more sense if I use computed property. Like this in my index.vue
<div class="page-container">
<div class="page-content">
<div class="content-wrapper">
<data-viewer :source="source" :thead="thead">
<template scope="props">
<tr>
<td>{{props.item.name}}</td>
<td>{{props.item.creator}}</td>
<td>
<i class="icon-checkmark5" v-if="props.item.publish === '0'"></i>
<i class="icon-cancel-circle2" v-else></i>
{{props.item.publish}} //for testing purpose to see returned value
</td>
<td>{{publishDate}}</td> //this is where i put my computed to change created_at format
</tr>
</template>
</data-viewer>
</div>
</div>
</div>
<script type="text/javascript">
import DataViewer from '../../components/dataviewer.vue'
import moment from 'moment'
export default{
components:{
DataViewer
},
data(){
return{
source: '/api/article',
thead: [
{title: 'Name', key: 'name', sort: true},
{title: 'Creator', key: 'creator_id', sort: true},
{title: 'Publish', key: 'publish', sort: true},
{title: 'Created', key: 'created_at', sort: true}
],
}
},
computed: {
publishDate: function(){
return moment(props.item.created_at).format('YYYY-MM-DD')
}
}
}
</script>
and here is what inside my dataviewer file
<template>
<table class="table">
<thead class="bg-primary">
<tr>
<th v-for="item in thead">
<span>{{item.title}}</span>
</th>
</tr>
</thead>
<tbody>
<slot v-for="item in model.data" :item="item"></slot>
</tbody>
</table>
</template>
<script>
import Vue from 'vue'
import axios from 'axios'
export default {
props: ['source', 'thead'],
data() {
return {
model: {
data: []
},
}
},
beforeMount() {
this.fetchData()
},
methods: {
fetchData() {
var vm = this
axios.get(this.source)
.then(function(response) {
Vue.set(vm.$data, 'model', response.data.model)
})
.catch(function(error) {
console.log(error)
})
}
}
}
</script>
but it just won't work, it can't find props.item.created_at, so how I can change created_at or any other property item to change from my index.vue?
Seems like using a filter will work here:
Instead of using computed props:
filters: {
publishDate: function(value){
return moment(value).format('YYYY-MM-DD')
}
}
In place of {{publishDate}}
<td>{{props.item.created_at | publishedDate }}</td>