strong text
I'm new in laravel and vue js . I'm trying to learn Vue js .In a Laravel+Vue project, i tried to use axios to post an API response. axios is not defined in Vue js 2. How to solve this problem.When i add some data. data didn't show and also didn't work my delete function. and why I face this problem ? thanks for advance
app.js
import Vue from 'vue';
import App from './vue/app';
import { library } from '#fortawesome/fontawesome-svg-core'
import { faPlusSquare, faTrash } from '#fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome'
library.add(faPlusSquare, faTrash)
Vue.component('font-awesome-icon', FontAwesomeIcon)
const app = new Vue ({
el: '#app',
components: { App }
});
addItemForm
<template>
<div class="addItem">
<input type="text" v-model="item.name" />
<font-awesome-icon
icon="plus-square"
#click="addItem()"
:class="[item.name ? 'active' : 'inactive', 'plus']"
/>
</div>
</template>
<script>
export default {
data: function () {
return {
item: {
name: "",
},
};
},
methods: {
addItem() {
if (this.item.name == "") {
return;
}
axios
.post("api/item/store", {
item: this.item,
})
.then((response) => {
if (response.status == 201) {
this.item.name = "";
this.$emit("reloadlist");
}
})
.catch((error) => {
console.log(error);
});
},
},
};
</script>
<style scoped>
.addItem {
display: flex;
justify-content: center;
align-content: center;
}
input {
background: rgb(236, 164, 138);
border: 0px;
outline: none;
padding: 5px;
margin-right: 10px;
width: 100%;
}
.plus {
font-size: 20px;
}
.active {
color: rgb(34, 211, 57);
}
.inactive {
color: rgb(63, 66, 63);
}
</style>
app.vue
<template>
<div class="todoListContainer">
<div class="heading">
<h2 id="title">Todo List</h2>
<add-item-form v-on:reloadlist="getList()" />
</div>
<list-view :items="items"
v-on:reloadlist="getList()" />
</div>
</template>
<script>
import addItemForm from "./addItemForm.vue";
import listView from "./listView.vue";
export default {
components: {
addItemForm,
listView,
},
data: function () {
return {
items: [],
};
},
methods: {
getList() {
axios
.post('api/items')
.then((response) => {
this.items = response.data;
})
.catch((error) => {
console.log(error);
});
},
},
created() {
this.getList();
},
};
</script>
<style scoped>
.todoListContainer {
width: 350px;
margin: auto;
}
.heading {
background: wheat;
padding: 10px;
}
#title {
text-align: center;
}
</style>
Firstly, install axios and vue-axios
npm install axios vue-axios
Seconly, import it inside your script
<script>
import addItemForm from "./addItemForm.vue";
import listView from "./listView.vue";
import axios from 'axios'; // <-- add this line
export default {
components: {
addItemForm,
listView,
},
data: function () {
return {
items: [],
};
},
methods: {
getList() {
axios
.post('api/items')
.then((response) => {
this.items = response.data;
})
.catch((error) => {
console.log(error);
});
},
},
created() {
this.getList();
},
};
</script>
In order to use, axios you have to import the axios. Considering you have already installed axios already in your project as it is third party library.
import axios from 'axios';
Add above line in the component, wherever you use the package.
First install both axios and vue-axios packages.
npm install axios vue-axios
Then in app.js file write this code:
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
// this is the default base url in laravel
axios.defaults.baseURL = 'http://127.0.0.1:8000';
// this line is written to avoid csrf error
window.axios.defaults.headers.common = {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content')
};
Then when you want to use axios just write this.axios.
hi you must install Axios first
npm install axios vue-axios
Related
I'm currently working on my first vue application, currently building the login logics.
For State management, pinia is being used. I created a Pinia Store to manage the "isLoggedIn" state globally.
import { defineStore } from "pinia";
export const useLoginStatusStore = defineStore('loginStatus', {
id: 'loginStatus',
state: () => ({
isLoggedIn: false
}),
actions: {
logIn() {
this.isLoggedIn = true
console.log("Login", this.isLoggedIn)
},
logOut() {
this.isLoggedIn = false
console.log("Logout", this.isLoggedIn)
}
}
})
So far so good, its working, i can access the state and actions in the components and router file.
**<roouter.js>**
import { createRouter, createWebHistory } from 'vue-router'
import { createPinia } from 'pinia'
import { createApp, ref } from 'vue'
import { useLoginStatusStore } from '../stores/loginStatus.js'
import App from '../App.vue'
import WelcomeView from '../views/public/WelcomeView.vue'
import SplashView from '../views/public/SplashView.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
const loginStatusStore = useLoginStatusStore()
let isLoggedIn = ref(loginStatusStore.isLoggedIn)
console.log("isLoggedIn", loginStatusStore.isLoggedIn)
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'splash',
component: SplashView
},
{
path: '/welcome',
name: 'welcome',
component: WelcomeView
},
{
path: '/login',
name: 'login',
component: () => import('../views/public/LoginView.vue')
},
{
path: '/signup',
name: 'signup',
component: () => import('../views/public/SignUpView.vue')
},
{
path: '/resetpassword',
name: 'resetpassword',
component: () => import('../views/public/ForgotPasswordView.vue')
},
{
path: '/home',
name: 'home',
component: () => import('../views/protected/HomeView.vue'),
meta: { requiresAuth: true }
},
{
path: '/sounds',
name: 'sounds',
component: () => import('../views/protected/SoundsView.vue'),
meta: { requiresAuth: true }
},
{
path: '/player',
name: 'soundPlayer',
component: () => import('../views/protected/SoundPlayerView.vue'),
meta: { requiresAuth: true }
},
{
path: '/profile',
name: 'profile',
component: () => import('../views/protected/ProfileView.vue'),
meta: { requiresAuth: true }
},
{
path: '/meditation',
name: 'meditation',
component: () => import('../views/protected/MeditationView.vue'),
meta: { requiresAuth: true }
},
{
path: '/tools',
name: 'tools',
component: () => import('../views/protected/ToolsView.vue'),
meta: { requiresAuth: true }
}
]
})
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
console.log("Router", isLoggedIn.value)
if (!isLoggedIn.value) {
next({
name: 'welcome'
})
} else {
next()
}
} else {
next()
}
})
export default router
In the router it's being used for protected routes and in App.vue for conditional class rendering.
The Problem is, that when the state gets updated, it doesn't get updated in the components and the components themselves don't update either. I tried with the $subscribe method in pinia, but didnt manage to get it working. I know, whats needed is something that creates reactivity here. But no clue how to do that. I'm grateful for any help with this :)
thanks for reading
**App.vue**
<script setup>
import { RouterView } from 'vue-router';
import DevNavItem from '#/components/header/DevNavItem.vue'
import HeaderItem from '#/components/header/HeaderItem.vue'
import FooterItem from '#/components/footer/FooterItem.vue'
import { useLoginStatusStore } from './stores/loginStatus.js';
const loginStatusStore = useLoginStatusStore()
const isLoggedIn = loginStatusStore.isLoggedIn
console.log("App.vue", loginStatusStore.isLoggedIn)
</script>
<template>
<DevNavItem />
<HeaderItem v-if="isLoggedIn" />
<RouterView :class="isLoggedIn ? 'mainProtected' : 'mainPublic'" />
<FooterItem v-if="isLoggedIn" />
</template>
<style>
/*FONT-IMPORT*/
#import url("#/assets/font/alegreya_font.scss");
/* GENERAL STYLES */
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
header {
position: top;
}
.mainProtected {
width: 100vw;
height: 83vh;
overflow: hidden;
}
.mainPublic {
width: 100vw;
height: 100vh;
overflow: hidden;
}
/* GLOBAL CLASSES */
.mainLogo {
height: 350px;
width: 350px;
background: url("./img/icons/main.png") center/cover no-repeat;
}
.leavesBackground {
background-color: #253334;
background-image: url("./src/img/images/background_partial.png");
background-repeat: no-repeat;
background-position: bottom;
background-size: contain;
}
.logoSmall {
background: url("./img/icons/main.png") center/contain no-repeat;
height: 100px;
width: 100px;
}
.buttonPublic {
padding: 20px 0;
text-align: center;
background-color: #7c9a92;
color: #fff;
border-radius: 15px;
width: 90%;
text-decoration: none;
font-size: 24px;
border: none;
}
</style>
I tried subscribing to the state with $subscribe, but it didn't work.
storeToRefs()
You need to use storeToRefs() to extract properties from the store while keeping those properties reactive.
import { storeToRefs } from 'pinia'
const themeStore = useThemeStore();
const { isDark } = storeToRefs(themeStore);
Computed property
Thanks to #Fennec for suggesting the computed way of getting reactive state. Although I don't recommend this method since there is a dedicated storeToRefs() available.
import { computed } from 'vue'
const themeStore = useThemeStore();
const isDark = computed(() => themeStore.isDark);
WRONG ways to get reactive state from the Pinia store:
All the ways listed below of getting the state (properties, getters) from the Pinia store are WRONG:
import { useThemeStore } from "./stores/theme.js";
const themeStore = useThemeStore();
// WRONG ways of extracting state from store
let isDark = themeStore.isDark; // not reactive
let isDark = ref(themeStore.isDark); // reactive, but will not be updated with the store
let { isDark } = themeStore; // not reactive, cannot destructure
Destructuring actions directly from the store.
Its worth to note here that "you can destructure actions directly from the store as they are bound to the store itself." (docs)
If you have an action named "increment" in your store, you can just extract it directly from the store in your component:
...
const { increment } = store // actions can be destructured directly
...
Also, according to Pinia docs, the first argument is the unique ID, so you do not need to specify the id again inside the options object. Or you can just ignore the first argument and just specify the id as an option. Either way is fine.
Hi Everyone I am a newbie in React. I am building my react app with typescript and would like to add Stripe to do the online payment. But I cannot find the typescript tutorial on stripe, so I try to use javascript to write the stripe part. But when I trigger the stripe. The errors below appear:
Referring to other solutions on stackOverFlow, i have used different import methods like
import stripe from './stripe';
import * as stripe from './stripe';
but none of them can solve my problem.
What's wrong with my code?
Here are the codes:
For Stripe file:
import React from 'react'
import { Element } from "#stripe/react-stripe-js"
import { loadStripe } from '#stripe/stripe-js'
import "./Stripe.css"
const PaymentForm = require ('./PaymentForm.js')
const PUBLIC_KEY = "pk_test_XXXXXXX"
const stripeTestPromise = loadStripe(PUBLIC_KEY)
export default function Stripe() {
return (
<Element stripe={stripeTestPromise}>
<PaymentForm />
</Element>
)
}
For paymentFrom file:
import React, { useState } from 'react'
import { CardElement, useElements, useStripe } from "#stripe/react-stripe-js"
import * as axios from 'axios'
import "./Stripe.css"
const CARD_OPTIONS = {
iconStyle: "solid",
style: {
base: {
iconColor: "#c4f0ff",
color:"fff",
fontWeight: 500,
fontSize: "16px",
fontSmoothing:"antialiased",
},
invaild: {
iconColor: "#ffc7ee",
color: "ffc7ee"
}
}
}
export default function PaymentForm() {
const [success, setSuccess] = useState(false)
const stripe = useStripe()
const elements = useElements()
const handleSubmit = async (e) => {
e.preventDefault()
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: "card",
card: elements.getElement(CardElement)
})
if (!error) {
try {
const { id } = paymentMethod
const response = await axios.post('http://localhost:8080/checkout', {
amount: 500,
id
})
if (response.data.success) {
console.log('Successful payment')
setSuccess(true)
}
} catch (error) {
console.log('Error', error)
}
} else {
console.log(error.message)
}
}
return (
<div>
{!success ?
<form onSubmit={handleSubmit}>
<fieldset className="FormGroup">
<div className="FormRow">
<CardElement options={CARD_OPTIONS} />
</div>
</fieldset>
<button>Pay</button>
</form >
:
<div>
<h2>You just bought a sweet saptula</h2>
</div>
}
</div>
)
}
I'd like to put a comment but I don't have the reputation to do it, so I'll submit an answer:
If you're trying to insert the elements provider following the documentation
the provider needs to be inserted this way:
import {Elements} from '#stripe/react-stripe-js';
you are importing this like
import {Element} from '#stripe/react-stripe-js';
it's possible that the element you're importing it's an interface or another object and not the provider you want
I've been trying to use a Twitter login option for a sports social media dashboard that I am trying to dissolve. I have been following this helpful tutorial I have scraped the HelloWorld component and have kept the app.vue and main.js component. Below is my code. I am receiving the error 'router not defined'. This may just be a routing issue. I have both the Twitter app and Firebase authentication correct. Any thoughts? Thanks
firebaseConfig.js
const firebaseConfig = {
apiKey: "AIzaSyBaWJ2p6TDNq1WuOVLLtjsJq1xDypaXqdM",
authDomain: "sportlydatabase.firebaseapp.com",
databaseURL: "https://sportlydatabase.firebaseio.com",
projectId: "sportlydatabase",
storageBucket: "sportlydatabase.appspot.com",
messagingSenderId: "287835560944",
appId: "1:287835560944:web:46024fe79c1d870531db35",
measurementId: "G-48VM19JE6M"
};
sign.vue
<template>
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<h3>Sign In with Twitter</h3>
<button class="btn btn-primary"
#click="signIn">
<i class="fa fa-twitter"></i>
SignIn with Twitter
</button>
</div>
</div>
</div>
</template>
<script>
export default {
methods: {
signIn () {
this.$store.dispatch('signIn')
}
}
}
</script>
<style scoped>
h3 {
font-weight: 700;
}
button {
background-color: #1dcaff;
border: 1px solid #1dcaff;
}
div button:hover {
background-color: #00aced;
border: 1px solid #00aced;
}
</style>
Home.vue
<template>
<div container-fluid>
<div>
<h2>Welcome {{ user.userDetails[0].displayName }}
</h2>
<p>You are logged in</p>
<img :src="user.userDetails[0].photoURL" alt=""
class="img-circle" height="100px" width="100px"
>
</div>
</div>
</template>
<script>
export default {
computed: {
user () {
return this.$store.getters.user
}
}
}
</script>
<style scoped>
h2 {
font-weight: 700
}
</style>
store.js
import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
user: null
},
getters: {
user (state) {
return state.user
}
},
mutations: {
SET_USER (state, payload) {
state.user = payload
},
LOGOUT (state, payload) {
state.user = null
}
},
actions: {
autoSignIn({ commit }, payload) {
const newUser = {
userDetails: payload.providerData
}
commit('SET_USER', newUser)
},
signIn({ commit }) {
var provider = new firebase.auth.TwitterAuthProvider();
firebase.auth().signInWithRedirect(provider);
firebase.auth().getRedirectResult().then(result => {
// The signed-in user info.
var user = result.user;
commit('SET_USER', user)
}).catch(error => {
alert(error)
return
})
},
logout({ commit }) {
firebase.auth().signOut().then(function () {
commit('LOGOUT')
}).catch(function (error) {
alert(error)
return
});
}
}
})
index.js
router.beforeEach((to, from, next) => {
const currentUser = firebase.auth().currentUser;
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
if (requiresAuth && !currentUser) {
next('/');
}
else if (!requiresAuth && currentUser) {
next('/home');
}
else {
next();
}
});
export default router
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue';
import App from './App';
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>',
});
It seems that you need to modify your main.js file as follows:
import Vue from 'vue';
import App from './App';
import router from './router'
See the main.js file from your tutorial: https://github.com/chuks-o/twitterauth/blob/master/src/main.js. Note that we do from './router' because your router index.js file is under a specific router directory.
I am relatively new to Vue and I've been reading the documentation and forums for quite a while for a solution to this one but haven't found it yet.
I am using the Vue Webpack template: here
I'm trying to create an app where I have an API endpoint to get the currency and country for the user as well as the user language from the browser.
I am using this.$store.dispatch('setlanguage') on initialisation of the Vue Component to set the state of the language, and save it to a cookie. The problem here though is that I am unable to alter the vuei18n as my app says it does not exist. The reason I am using vuei18n instead of vueXi18n is because the latter does not have the numberFormat options and this is needed in order to set correctly the currency symbols.
So to get things started:
Project structure:
main.js
App.Vue
store
getters.js
index.js
mutation-types.js
mutations.js
router
index.js
lang
locales
en.js
fr.js
de.js
lang.js
components
LocaleSwitcher.vue
pages
Footer.vue
Home.vue
main.js
import Vue from 'vue'
import VueResource from 'vue-resource'
import Cookies from 'js-cookie'
import App from './App.vue'
import i18n from './lang/lang'
import store from './store'
import router from './router'
Vue.use(VueResource)
Vue.config.productionTip = false
Vue.config.language = Cookies.get('lang')
Vue.config.country = Cookies.get('country')
Vue.config.currency = Cookies.get('cur')
export const localeStrings = {
en: 'English',
de: 'Deutsch',
fr: 'Français',
it: 'Italiano',
nl: 'Nederlands',
sv: 'Svenska',
es: 'Español',
ja: '日本語'
}
export const app = new Vue({
el: '#app',
router,
store,
i18n: i18n,
render: h => h(App),
created () {
this.$store.dispatch('setLang', Vue.config.language)
this.$store.dispatch('setCountry', Vue.config.country)
}
})
lang.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
let i18n = new VueI18n({
locale: 'en',
messages: {},
fallbackLocale: 'en',
numberFormats: {}
})
export default {i18n}
App.vue
template>
<div id="app">
<app-header></app-header>
<div class="main-content">
<router-view></router-view>
</div>
<app-footer></app-footer>
</div>
</template>
<script>
export default {
name: 'myapp',
components: {
'app-footer': Footer
},
data () {
return {
msg: 'Welcome to Your Vue.js App',
language: ''
}
}
}
<style>
body {
margin:0;
padding:0;
}
</style>
Home.vue
<template>
<h1>Hello Home! {{msg}}</h1>
</template>
<script>
export default {
data () {
return {
msg: 'Home msg'
}
}
}
</script>
<style scoped>
h1 {
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
}
</style>
Footer.vue
<template>
<footer>
<p>{{copyright}}</p>
<local-switcher></local-switcher>
</footer>
</template>
<script>
import LocaleSwitcher from '../components/LocaleSwitcher.vue'
export default {
name: 'Footer',
components: {
'local-switcher': LocaleSwitcher
},
data () {
return {
copyright: 'Copyright 2018 Francesco'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
footer{
background: lightgrey;
padding: 10px;
}
</style>
LocaleSwitcher.vue
<template>
<div class="locale-switcher">
<select v-model="activeLocale" #change="changeLang">
<option v-for="(lang, id) in locales" :key="id" v-bind:value="id">{{lang}}</option>
</select>
</div>
</template>
<script>
import {localeStrings} from '../main'
export default {
name: 'locale-switcher',
data: function () {
return {
activeLocale: this.$store.getters.getLanguage,
locales: localeStrings
}
},
methods: {
changeLang () {
this.setLang(this.activeLocale)
},
setLang (lang) {
this.$store.dispatch('setLang', lang)
}
}
}
</script>
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import p404 from '../pages/error/404.vue'
import Home from '../pages/Home.vue'
Vue.use(Router)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '*',
name: '404',
component: p404
}
]
let router = new Router({
mode: 'history',
routes
})
// I still have to figure out how to use this to set www.mypage.com/mylanguage/home
// use beforeEach route guard to set the language
router.beforeEach((to, from, next) => {
// use the language from the routing param or default language
let language = to.params.lang
console.log(language)
console.log('router end')
if (!language) {
language = 'en'
}
// set the current language for vuex-i18n. note that translation data
// for the language might need to be loaded first
// Vue.i18n.set(language)
next()
})
export default router
store/getters.js
export const getters = {
getLanguage: state => {
return state.language
},
getCountry: state => {
return state.country
},
getCurrency: state => {
return state.currency
}
}
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import { state, mutations, actions } from './mutations'
import { getters } from './getters'
Vue.use(Vuex)
// const mapState = Vuex.mapState
const store = new Vuex.Store({
state,
mutations,
actions,
getters
})
export default store
store/mutation-types.js
export const SET_LANG = 'SET_LANG'
export const SET_COUNTRY = 'SET_COUNTRY'
export const SET_CURRENCY = 'SET_CURRENCY'
store/mutations.js
import Vue from 'vue'
import Cookies from 'js-cookie'
import * as types from './mutation-types'
import {app, supportedLocale, supportedCurrencies} from '../main'
import CountryCurrency from '../data/country_currency.json'
import locale2 from 'locale2'
export const state = {
language: Cookies.get(settings.languageCookie),
country: Cookies.get(settings.countryCookie),
currency: Cookies.get(settings.currencyCookie),
loading: false
}
export const mutations = {
[types.SET_LANG] (state, payload) {
Cookies.set('lang', payload)
state.language = payload
},
[types.SET_COUNTRY] (state, payload) {
Cookies.set('country', payload)
state.country = payload
},
[types.SET_CURRENCY] (state, payload) {
Cookies.set('currency', payload)
state.currency = payload
}
}
export const actions = {
async setLang ({commit}, language) {
console.log(app)
console.log(Vue)
var vueMessages = app.$i18n.messages
var userLocale = 'en'
var browserLocale = locale2.split('-', 1)[0]
// testing browser language
if (locale === undefined) {
// get browser language
userLocale = browserLocale
} else if (browserLocale !== locale) {
console.log('browser language changed')
userLocale = browserLocale
} else {
userLocale = locale
}
// check for supported languages
if (!supportedLocale.includes(userLocale)) {
userLocale = 'en'
}
if (language in vueMessages) {
console.log('already in messages')
commit(types.SET_LANG, language)
} else if (!supportedLocale.includes(language)) {
console.log('not supported so commiting default en')
commit(types.SET_LANG, 'en')
} else {
try {
// you can use fetch or import which ever you want.
// Just make sure your webpack support import syntax
// const res = await axios.get(`./src/lang/${payload}.json`)
const res = await import(`../lang/locales/${language}.json`)
app.$i18n.locale = language
app.$i18n.setLocaleMessage(language, res)
var addNumberFormats = {
currency: {
style: 'currency', currencyDisplay: 'symbol', currency: `${app.$i18n.currency}`
}
}
app.$i18n.mergeNumberFormat(language, addNumberFormats)
Cookies.set('lang', language)
commit(types.SET_LANG, language)
} catch (e) {
console.log(e)
}
}
},
setCountry ({commit}, countryCode) {
var userCountry = 'NA'
if (countryCode === undefined || countryCode === 'NA') {
Vue.http.get('https://www.myapi.com/api/v2/geo/country-code', {
timeout: 100
}).then(response => {
state.country = response.data.code
Cookies.set('country', response.data.code)
}, response => {
// error callback
state.country = userCountry
Cookies.set('country', userCountry)
})
} else {
console.log(countryCode)
state.country = countryCode
Cookies.set('country', countryCode)
}
},
setCurrency ({commit}, countryCode) {
var userCurrency = 'USD'
console.log('user country ' + countryCode)
console.log('user currency ' + CountryCurrency[countryCode])
console.log('currency supported: ' + supportedCurrencies.includes(CountryCurrency[countryCode]))
if (CountryCurrency[countryCode] && supportedCurrencies.includes(CountryCurrency[countryCode])) {
userCurrency = CountryCurrency[countryCode]
}
Cookies.set('currency', userCurrency)
app.$i18n.currency = userCurrency
try {
var addNumberFormats = {
currency: {
style: 'currency', currencyDisplay: 'symbol', currency: `${app.$i18n.currency}`
}
}
if (!app.$i18n.numberFormats[app.$i18n.locale]) {
console.log('merge currency')
app.$i18n.setNumberFormat(app.$i18n.locale, addNumberFormats)
}
} catch (error) {
console.log(error)
}
}
}
The problem is that once loaded, I cannot access the app vue i18n. Am I accessing it incorrectly or is there another way to add language and currency settings to this? I hope I have provided enough info Thanks!
Could this answer be relevant in your case? https://stackoverflow.com/a/45460729/2964531
If you need to access or mutate properties of i18n, you can import it directly from store/mutations.js
I believe what I am trying to achieve has been done many times, but I can't manage it.
I would just like to be able to test if an element has a certain class on a certain element.
Splash
import React from 'react';
import { NavLink } from 'react-router-dom'
import Logo from '../shared/logo/index';
import * as styles from './style.css';
class Splash extends React.Component {
render(){
return (
<div className={styles.indexAppContent}>
<NavLink to="/home" className={styles.index}>
<Logo />
</NavLink>
</div>
);
}
}
export default Splash;
style.css
.index {
div {
color: #FFF;
//font-size: 8rem;
}
position: absolute;
left: 50%;
top: 50%;
display: block;
transform: translate3d(-50%, -50%, 0);
-webkit-transform: translate3d(-50%, -50%,0);
-moz-transform: translate3d(-50%, -50%,0);
-ms-transform: translate3d(-50%, -50%,0);
}
.indexAppContent {
height: 100vh;
width: 100vw;
position: relative;
}
However this is the output:
{ className: undefined,
children:
{ '$$typeof': Symbol(react.element),
type: { [Function: NavLink] propTypes: [Object], defaultProps: [Object] },
key: null,
ref: null,
props:
{ to: '/home',
className: undefined,
children: [Object],
activeClassName: 'active',
ariaCurrent: 'true' },
_owner: null,
_store: {} } }
Splash
/* eslint-disable object-property-newline */
import React from 'react';
import ReactTestUtils from 'react-dom/test-utils'
import { expect } from 'chai';
import { NavLink } from 'react-router-dom'
import { shallow } from 'enzyme';
//Splash
import Splash from '../../../src/components/Splash';
import * as styles from '../../../src/components/Splash/style.css';
//logo
import Logo from '../../../src/components/shared/logo';
describe('<Splash />', () => {
const wrapperSplash = shallow(<Splash/>);
const wrapperNavLink = shallow(<NavLink />);
const wrapperLogo = shallow(<Logo />);
it('must be defined', () => {
expect(wrapperSplash).to.be.defined;
});
it('should have one logo', () => {
expect(wrapperSplash.find(Logo)).to.have.length(1);
})
it('should have className', () => {
expect(wrapperSplash.first().prop('className'))
.to.contain('indexAppContent');
})
it('Logo links to Home', () => {
expect(wrapperSplash.find(NavLink).first().props().to)
.equals('/Home');
})
});
Test
/* eslint-disable object-property-newline */
import React from 'react';
import ReactTestUtils from 'react-dom/test-utils'
import { expect } from 'chai';
import { NavLink } from 'react-router-dom'
import { shallow } from 'enzyme';
it('should have className', () => {
console.info(wrapperSplash.first().props());
expect(wrapperSplash.first().prop('className'))
.to.contain('indexAppContent');
})
Test Helper
import path from 'path';
import csshook from 'css-modules-require-hook/preset' // import hook before routes
import routes from '/shared/views/routes'
import requireHacker from 'require-hacker';
import sass from 'node-sass';
import {jsdom} from 'jsdom';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
hook({
extensions: ['.css'],
generateScopedName: '[local]',
preprocessCss: (data, filename) =>
sass.renderSync({
data,
file: filename,
importer: (url) => {
if (url.indexOf('~') === 0) {
const node_modules_path = path.resolve(__dirname, '../..', 'node_modules');
return {
file: path.join(node_modules_path, url.replace('~', ''))
};
}
return {file: url};
}
}).css
});
const fakeComponentString = `
module.exports = require('react').createClass({
render() {
return null;
}
});
`;
requireHacker.hook('svg', () => fakeComponentString);
// jsdom
const exposedProperties = ['window', 'navigator', 'document'];
global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
global[property] = document.defaultView[property];
}
});
global.navigator = {
userAgent: 'node.js'
};
You are checking a prop of that component and not the existence of a class in the root node that was rendered by this component.
Obviously you are not passing this prop.
You set the class on the root element of this component, thus you should check for nested element that hold this class value in the dom and not the attribute (prop) className
You can do it with this syntax for example:
it('should have class of indexAppContent', () => {
expect(wrapperSplash.find('.indexAppContent')).to.have.length(1);
})