There is a Form component.vue, which takes the event object from getter and substitutes it in v-model:
<template>
<form #submit.prevent="submitForm">
<div class="form-group row">
<div class="col-10 d-flex">
<input type="" class="title form-control" v-model="getEvent.title" placeholder="Название">
<input type="" class="content form-control" v-model="getEvent.content" placeholder="Содержание">
<input type="" class="event_date form-control" v-model="getEvent.event_date" placeholder="Дата">
<input type="" class="email form-control" v-model="getEvent.email" placeholder="Email">
</div>
<div class="d-flex flex-column">
<button class="btn btn-success mt-auto" >Создать</button>
</div>
</div>
</form>
</template>
<script>
import { mapGetters, mapActions } from "vuex"
export default {
computed: mapGetters(['getEvent']),
methods: mapActions(['submitForm'])
}
However, vue returns an error stating that getter undefined. store/index.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
Date.prototype.getWeek = function () {
var onejan = new Date(this.getFullYear(), 0, 1);
var today = new Date(this.getFullYear(), this.getMonth(), this.getDate());
var dayOfYear = ((today - onejan + 86400000) / 86400000);
return Math.ceil(dayOfYear / 7)
}
export const store = new Vuex.Store({
actions: {
async getEvents(context) {
var response = await fetch('http://127.0.0.1:8000/rest/');
var data = await response.json()
context('getEvents', data)
},
async createEvent(context) {
await this.getEvents();
await fetch('http://127.0.0.1:8000/rest/', {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({ event: context.state.event })
});
await this.getEvents();
context.commit('createEvent', context.state.event)
},
async editEvent(context) {
await this.getEvents();
await fetch(`http://127.0.0.1:8000/rest/${context.state.event.id}/`, {
method: 'put',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({ event: context.state.event })
});
await this.getEvents();
context.state.event = {};
},
async deleteEvent(context) {
await this.getEvents();
await fetch(`http://127.0.0.1:8000/rest/${context.state.event.id}/`, {
method: 'delete',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({ event: context.state.event })
});
await this.getEvents();
},
submitForm(context) {
if (context.state.event.id === undefined) {
this.createEvent();
} else {
this.editEvent();
}
},
isMonthEqualNow(object) {
var event_date = new Date(object.event_date)
var date_now = new Date()
return event_date.getMonth() === date_now.getMonth()
},
isWeekEqualNow(object) {
var event_date = new Date(object.event_date)
var date_now = new Date()
return event_date.getWeek() === date_now.getWeek()
},
isDayEqualNow(object) {
var event_date = new Date(object.event_date)
var date_now = new Date()
return event_date.getDate() === date_now.getDate()
},
eventsByFilters(context) {
var events = context.state.events
if (context.state.search === '' && context.state.selected) {
switch (context.state.selected) {
case 'month':
return events.filter(item => this.isMonthEqualNow(item))
case 'week':
return events.filter(item => this.isMonthEqualNow(item) && this.isWeekEqualNow(item))
case 'day':
return events.filter(item => this.isMonthEqualNow(item) && this.isWeekEqualNow(item)
&& this.isDayEqualNow(item))
default:
return events
}
} else {
events.filter(item => item.title.indexOf(context.state.search) !== -1)
}
}
},
mutations: {
setEvents(state,events){
state.events = events
},
createEvent(state, event){
state.events.push(event)
}
},
state: {
events: [],
event: {},
selected: '',
search: ''
},
getters: {
eventsByFilters(state) {
return state.events
},
getSearch(state){
return state.search
},
getSelected(state){
return state.selected
},
getEvent(state) {
return state.event
}
},
});
And also i have warning(warning in ./src/main.js
"export 'default' (imported as 'store') was not found in './store')
main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store';
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
}).$mount('#app')
And the components themselves are not output
The only issue, I have seen is
your store is not exporting any default
export const store = new Vuex.Store(...
yet, your main.js uses to import the default
import store from 'src/store'
so use the following and hope your issue gets solved
import { store } from './store';
please check these links
export-const-vs-export-default-in-es6
named-export-vs-default-export-in-es6
One point to suggests
in the following lines, I do not think you need to use await for this.getEvents() because it has already used await inside its action.
for example,
await this.getEvents();
await fetch('http://127.0.0.1:8000/rest/', {
action is for commit data to mutation and in mutation you have to set data to state.
You should not fetch data in action, instead call it from component, in mounted() or something.
an example:
export default {
mounted() {
var response = await fetch('http://127.0.0.1:8000/rest/');
var data = await response.json()
this.$store.dispatch("eventsList", data);
}
}
and in store.js:
actions: {
eventsList({commit}, data) {
commit('eventsList', data)
}
},
mutations: {
eventsList(state, data) {
state.events= data
},
}
dispatch calls action -> commit calls mutation => in mutation set the data directly to state.
Related
I am Japanese. Therefore, my sentences may be strange. Please keep that in mind.
I am writing code using vue.js, vuex, vue-chart.js and vue-chart.js to display the population of each prefecture of Japan when checked.I’m code is written to redraw the graph when the input element for each prefecture is checked.However, it does not redraw when checked.Also, it may redraw after half of the check.I believe this phenomenon can be confirmed from the following URL.
https://yumemi-coding.web.app/
※There are no errors.
Here's a question: what causes the graphs to redraw or not? Also, how can I code to remedy this?
What I have done to counteract the cause is as follows
I went to the official website and used the rendering process as a reference.
URL:https://vue-chartjs.org/migration-guides/#new-reactivity-system
=> The way we did it was right.
We thought there was a problem with VueX and coded in a way that did not use it. => There was nothing wrong with vuex.
TopFroont.vue
<template>
<div class="Bar_area">
<Bar :options="chartOptions" :data="chartData" class="Bar_item" />
</div>
</template>
<script>
import { Bar } from "vue-chartjs"
import { Chart as ChartJS, registerables } from "chart.js"
ChartJS.register(...registerables)
export default {
name: "BarChart",
components: { Bar },
data() {
return {
chartOptions: {
responsive: true,
},
}
},
computed: {
chartData() {
return {
labels: this.$store.state.years,
datasets: this.$store.state.prefectures,
}
},
},
}
</script>
NaviBar.vue
<template>
<div class="navApp">
<ul>
<li v-for="(pref, index) in prefData" :key="index" class="pref_itemBox">
<label>
<input type="checkbox" #change="checkItem(pref)" />
<span class="pref_text">{{ pref.prefName }}</span>
</label>
</li>
</ul>
</div>
</template>
<script>
import resasInfo from "#/library/resas.js"
import axios from "axios"
export default {
data() {
return {
resasInfo: resasInfo,
url: resasInfo.url_prefectures,
api: resasInfo.api,
prefData: [],
prefectures: [],
}
},
async created() {
const request_Header = {
headers: { "X-API-KEY": this.api.key },
}
await axios.get(this.url, request_Header).then((res) => {
const value = res.data.result
this.prefData.push(...value)
})
},
methods: {
checkItem(pref) {
// チェックされてる都道府県のみを配列に入れる
const isExistencePref = this.prefectures.indexOf(pref)
isExistencePref === -1
? this.prefectures.push(pref)
: this.prefectures.splice(isExistencePref, 1)
this.$store.dispatch("getPrefectures", this.prefectures)
},
},
}
</script>
vuex => store/index.js
import axios from "axios"
import { createStore } from "vuex"
import createPersistedState from "vuex-persistedstate"
export default createStore({
state: {
prefectures: [],
years: [],
},
mutations: {
getPrefs(state, payload) {
state.prefectures = payload
},
getYears(state, payload) {
state.years = payload
},
},
actions: {
getPrefectures({ commit }, payload) {
// payload => 各都道府県のprefCode + prefName
const allPrefecture_Data = []
const result = payload.map(async (el) => {
const prefCode_data = el.prefCode
axios
.get(
`https://opendata.resas-portal.go.jp/api/v1/population/composition/perYear?prefCode=${prefCode_data}&cityCode=-`,
{
headers: {
"X-API-KEY": "5RDiLdZKag8c3NXpEMb1FcPQEIY3GVwgQwbLqFIx",
},
}
)
.then((res) => {
const value = res.data.result.data[0].data
const TotalPopulation_Year = []
const TotalPopulation_Data = []
// 都道府県の総人口データと年データを各配列に入れ込む
value.forEach((element) => {
TotalPopulation_Data.push(element.value)
TotalPopulation_Year.push(element.year)
})
// rgbaを自動生成する関数 => backgroundColor
const generateRGBA = () => {
const r = Math.floor(Math.random() * 256)
const g = Math.floor(Math.random() * 256)
const b = Math.floor(Math.random() * 256)
const a = 0.8
return `rgba(${r}, ${g}, ${b}, ${a})`
}
// chart.jsに入れ込むデータ
const prefData = {
label: el.prefName,
data: TotalPopulation_Data,
backgroundColor: generateRGBA(),
}
allPrefecture_Data.push(prefData)
commit("getPrefs", allPrefecture_Data)
commit("getYears", TotalPopulation_Year)
})
.catch((err) => {
console.log(err)
})
})
return result
},
},
plugins: [createPersistedState()],
getters: {},
modules: {},
})
I have been messing around with Vue and trying to learn it. On the first click of the button in LoginForm.vue token and user_data are both null. On the second click it finally gets updated. How can I get the live reactive state of the variables?
I am new to Vue so if there are better common practices please let me know.
store/login.js
import { defineStore } from 'pinia'
import axios from 'axios'
export const useUsers = defineStore('users', {
state: () => ({
token: null,
user_data: null
}),
actions: {
async loginUser(data) {
try {
let response = await axios.post("users/login", data)
// Object.assign(this.token, response.data.token)
this.token = response.data.token
axios.defaults.headers.common['user-token'] = this.token
} catch (error) {
return error
}
},
async logout() {
// Object.assign(this.token, null)
// Object.assign(this.user_data, null)
this.token = null
this.user_data = null
// localStorage.removeItem('user');
delete axios.defaults.headers.common['user-token']
},
async login_and_get_user_data(data) {
axios.post("users/login", data).then(response => {
this.token = response.data.token
axios.defaults.headers.common['user-token'] = this.token
axios.get("users/user").then(response2 => {
this.user_data = response2.data.user
})
})
},
async get_user_data() {
console.log(JSON.parse(localStorage.getItem('user'))['token'])
axios.defaults.headers.common['user-token'] = JSON.parse(localStorage.getItem('user'))['token']
let response = await axios.get("users/user")
// Object.assign(this.user_data, response.data.user)
this.user_data = response.data.user
}
}
})
components/LoginForm.vue
<script>
import { useUsers } from '#/stores/login'
import { mapActions } from 'pinia'
import { storeToRefs } from 'pinia'
import { isProxy, toRaw } from 'vue';
export default {
setup() {
const store = useUsers()
store.$subscribe((mutation, state) => {
localStorage.setItem('user', JSON.stringify(state))
})
},
data() {
return {
email: "",
password: ""
}
},
methods: {
...mapActions(useUsers, ['loginUser']),
...mapActions(useUsers, ['get_user_data']),
...mapActions(useUsers, ['logout']),
on_click() {
var data = new FormData();
data.append('email', this.email);
data.append('password', this.password);
const store = useUsers()
this.loginUser(data)
this.get_user_data()
const { token } = storeToRefs(store)
const { user_data } = storeToRefs(store)
console.log(token.value)
console.log(toRaw(user_data.value))
},
logout_click() {
this.logout().then(
console.log(JSON.parse(localStorage.getItem('user')))
)
}
}
}
</script>
<template>
<input type="email" v-model="email" placeholder="youremail#mail.com">
<br>
<input type="password" v-model="password">
<br>
<button #click="on_click">Submit</button>
<br>
<button #click="logout_click">Logout</button>
</template>
Your method on_click is calling async methods like loginUser or get_user_data without waiting them to be finished.
So by the time your are logging console.log(token.value) your http request is probably not finished yet and your token is still null.
You need to await the methods that are doing those requests.
async on_click() {
var data = new FormData();
data.append('email', this.email);
data.append('password', this.password);
const store = useUsers()
await this.loginUser(data)
await this.get_user_data()
const { token } = storeToRefs(store)
const { user_data } = storeToRefs(store)
console.log(token.value)
console.log(toRaw(user_data.value))
},
Keep in mind that you will probably need to display a loader to give the user a feedback because the on_click is now asynchronous and take a bit more time
In Vue.js 2, I'm using Axios and I can't render the data without refreshing the page, can you help me on what to do?
<div v-for="task in tasks" :key="task.id" class="title">
{{ task.title }}
</div>
export default {
name: "TodoList",
data() {
return {
tasks: [],
newTask: "",
taskId: null,
}
},
methods: {
async addTask() {
this.taskId = this.tasks.length + 1
if (this.newTask.trim().length === 0) {
return
}
const task = {id: this.taskId, title: this.newTask}
const created = await API.createTasks(task)
this.tasks.push(created)
this.newTask = ""
}
},
async created() {
this.tasks = await API.getTasks();
}
}
// API.js
export default {
async createTasks(task) {
return axios.post(this.withPath('/api/v1/tasks'),task).then(r => r.data)
},
async getTasks() {
return axios.get(this.withPath('/api/v1/tasks')).then(r => r.data)
},
}
This is my response body of POST:
{"id":1,"title":"buy a water"}
I'm a beginner in Vue, and I implemented Auth0 to my Web App using Vue3.
My issue: after logging in, my API call to retrieve data get an unauthorized error 403. If I reload the page, everything is working fine.
What should I do to avoid reloading the page to get authenticated directly?
Here are my scripts:
Main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'
import dayjs from 'dayjs'
import Datepicker from 'vue3-date-time-picker'
import 'vue3-date-time-picker/dist/main.css'
import { setupAuth } from './auth/index.js'
import authConfig from './auth/config.js'
function callbackRedirect(appState) {
router.push(appState && appState.targetUrl ? appState.targetUrl : '/' );
}
setupAuth(authConfig, callbackRedirect).then((auth) => {
let app = createApp(App).use(router);
app.config.globalProperties.$dayjs = dayjs;
app.component('Datepicker', Datepicker);
app.use(auth).mount('#app');
})
My App.vue script:
<template>
<div v-if="isAuthenticated">
<NavBar />
<router-view/>
</div>
</template>
<script>
import NavBar from './components/NavBar.vue'
export default {
components: { NavBar },
data(){
return {
isAuthenticated: false,
}
},
async mounted(){
await this.getAccessToken()
},
methods: {
async getAccessToken(){
try {
const accessToken = await this.$auth.getTokenSilently()
localStorage.setItem('accessToken', accessToken)
this.isAuthenticated = true
} catch (error) {
console.log('Error occured while trying to retrieve Access Token...', error)
}
},
},
}
</script>
and my Home.vue loading the data:
<template>
<div class="home">
<div class="py-10">
<header>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold leading-tight text-gray-900">Monitoring Dashboard</h1>
</div>
</header>
<main>
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<h3 class="m-5 text-lg leading-6 font-medium text-gray-900">Main KPIs</h3>
<div class="md:grid md:grid-cols-3 md:gap-6">
<div v-for="(item, index) in stats" :key="index" class="md:col-span-1">
<div class="bg-white p-5 border-gray-50 rounded-lg shadow-lg mb-5">
<span class="text-sm font-medium text-gray-500 truncate">{{ item.name }}</span>
<p class="mt-1 text-3xl font-bold text-gray-900">{{ parseFloat(item.stat.toFixed(2)) }}</p>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</template>
<script>
import _ from 'lodash'
import ProductsService from '../services/products.service'
export default {
name: 'Home',
data(){
return{
user: '',
products: '',
stats: '',
}
},
async mounted(){
await this.readProducts()
await this.buildStats()
},
methods: {
async readProducts(){
let temp = null
try {
temp = await ProductsService.readProducts()
this.products = temp.data
} catch (error) {
console.log('Error: cannot retrieve all products...')
}
},
async buildStats(){
//Nb products
const nbProducts = this.products.length
//Nb offers & Uniq NbRetailers
let nbOffers = 0
let retailers = []
for(let product of this.products){
for(let offer of product.offers){
retailers.push(offer.retailer)
nbOffers += 1
}
}
const nbRetailers = _.uniq(retailers).length
this.stats = [
{ name: 'Number of Retailers', stat: nbRetailers },
{ name: 'Number of Products', stat: nbProducts },
{ name: 'Number of Offers', stat: nbOffers },
]
},
},
watch: {
products: function(){
this.buildStats()
}
}
}
</script>
My ./auth/index.js file:
import createAuth0Client from '#auth0/auth0-spa-js'
import { computed, reactive, watchEffect } from 'vue'
let client
const state = reactive({
loading: true,
isAuthenticated: false,
user: {},
popupOpen: false,
error: null,
})
async function loginWithPopup() {
state.popupOpen = true
try {
await client.loginWithPopup(0)
} catch (e) {
console.error(e)
} finally {
state.popupOpen = false
}
state.user = await client.getUser()
state.isAuthenticated = true
}
async function handleRedirectCallback() {
state.loading = true
try {
await client.handleRedirectCallback()
state.user = await client.getUser()
state.isAuthenticated = true
} catch (e) {
state.error = e
} finally {
state.loading = false
}
}
function loginWithRedirect(o) {
return client.loginWithRedirect(o)
}
function getIdTokenClaims(o) {
return client.getIdTokenClaims(o)
}
function getTokenSilently(o) {
return client.getTokenSilently(o)
}
function getTokenWithPopup(o) {
return client.getTokenWithPopup(o)
}
function logout(o) {
return client.logout(o)
}
export const authPlugin = {
isAuthenticated: computed(() => state.isAuthenticated),
loading: computed(() => state.loading),
user: computed(() => state.user),
getIdTokenClaims,
getTokenSilently,
getTokenWithPopup,
handleRedirectCallback,
loginWithRedirect,
loginWithPopup,
logout,
}
export const routeGuard = (to, from, next) => {
const { isAuthenticated, loading, loginWithRedirect } = authPlugin
const verify = () => {
// If the user is authenticated, continue with the route
if (isAuthenticated.value) {
return next()
}
// Otherwise, log in
loginWithRedirect({ appState: { targetUrl: to.fullPath } })
}
// If loading has already finished, check our auth state using `fn()`
if (!loading.value) {
return verify()
}
// Watch for the loading property to change before we check isAuthenticated
watchEffect(() => {
if (loading.value === false) {
return verify()
}
})
}
export const setupAuth = async (options, callbackRedirect) => {
client = await createAuth0Client({
...options,
})
try {
// If the user is returning to the app after authentication
if (
window.location.search.includes('code=') &&
window.location.search.includes('state=')
) {
// handle the redirect and retrieve tokens
const { appState } = await client.handleRedirectCallback()
// Notify subscribers that the redirect callback has happened, passing the appState
// (useful for retrieving any pre-authentication state)
callbackRedirect(appState)
}
} catch (e) {
state.error = e
} finally {
// Initialize our internal authentication state
state.isAuthenticated = await client.isAuthenticated()
state.user = await client.getUser()
state.loading = false
}
return {
install: (app) => {
app.config.globalProperties.$auth = authPlugin
},
}
}
This is a Vue3 project. When Domains.vue is mounted, getDomains is dispatched to vuex, and the data is properly set as indicated by vue dev tools.
For some reason, the data is not displayed in the template for loop. Perhaps one of you wonderful people can help me figure out why not?
Domains.vue
<template>
<div class="domains">
<h1>This is an domains page</h1>
<ul>
<li v-for="item in domains" :key="item.post_name">
<h3>{{ item.post_title }}</h3>
<p>{{ item.post_excerpt }}</p>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Domains',
computed: {
domains() {
return this.$store.state.domains.domains
},
},
mounted() {
this.$store.dispatch('getDomains')
}
}
</script>
vuex store
import { createStore } from 'vuex'
import axios from 'axios'
export default createStore({
state: {
user: {
'id': localStorage.getItem('id'),
'token': localStorage.getItem('token'),
},
domains: {
domains: [],
totalDomains: '',
totalPages: ''
},
},
mutations: {
SET_USER(state, user) {
state.user = user
localStorage.setItem('id', user.id)
localStorage.setItem('token', user.token)
},
DELETE_USER(state) {
state.user = { token: '' }
localStorage.setItem('id', '')
localStorage.setItem('token', '')
},
SET_DOMAINS(state, data, headers) {
state.domains.domains = data
state.domains.totalDomains = headers['X-WP-Total']
state.domains.totalDomains = headers['X-WP-TotalPages']
},
SET_ME(state, data) {
state.user.me = data
},
},
actions: {
login({ commit }, payload) {
return new Promise(async (resolve, reject) => {
try {
const { data } = await axios.post(`http://sslchkr.com/wp-json/jwt-auth/v1/token`, payload)
commit('SET_USER', data)
resolve(data)
} catch(e) {
reject(e)
}
})
},
logout({ commit }) {
commit('DELETE_USER')
},
validate({ state }) {
return new Promise(async (resolve, reject) => {
try {
const { data } = await axios({
url: `http://sslchkr.com/wp-json/jwt-auth/v1/token/validate`,
method: 'post',
headers: {
'Authorization': `Bearer ${state.user.token}`
}
})
//commit('SET_USER', data)
resolve(data)
} catch(e) {
reject(e)
}
})
},
getDomains({ commit, state }) {
return new Promise(async (resolve, reject) => {
try {
const { data, headers } = await axios.get(`http://sslchkr.com/wp-json/sslchkr/v1/author/${state.user.id}/domain`, {
headers: {
Authorization: `Bearer ${state.user.token}`
}
})
commit('SET_DOMAINS', data, headers)
resolve(data)
} catch(e) {
reject(e)
}
})
},
getMe({ commit, state }) {
return new Promise(async (resolve, reject) => {
try {
const { data } = await axios.get(`http://sslchkr.com/wp-json/wp/v2/users/me`, {
headers: {
Authorization: `Bearer ${state.user.token}`
}
})
commit('SET_ME', data)
resolve(data)
} catch(e) {
reject(e)
}
})
},
},
modules: {
}
})
convert this
<li v-for="item in domains" :key="item.post_name">
to
<li v-for="item in domains" :key="item">
and if this doesn't work, add index as key
<li v-for="(item,idx) in domains" :key="idx">
Please disregard this. I jumped the gun and posted the question before I knew what was wrong.