Hi take a look this code, if I set the message asynchronously whenever new data resolved, it doesn't re render the translation.
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-i18n/dist/vue-i18n.js"></script>
<div id="app">
<p>{{ $t("home") }}</p>
</div>
const locale = {
id: {
home: 'Beranda'
},
en: {
home: 'Home'
}
}
const i18n = new VueI18n({
locale: 'id'
})
new Vue({
el: '#app',
i18n,
created () {
setTimeout(() => {
this.$i18n.setLocaleMessage(locale)
}, 100)
}
})
Updated
My current workaround is define a method that return Promise and the variable that will hold the text. When the promise is resolved, then I set the translation.
const locale = {
id: {
home: 'Beranda'
},
en: {
home: 'Home'
}
}
const i18n = new VueI18n({
locale: 'id'
})
new Vue({
el: '#app',
i18n,
data: {
text: null
},
methods: {
getData () {
return new Promise(resolve => {
setTimeout(() => {
this.$i18n.setLocaleMessage('id', locale.id)
this.$i18n.setLocaleMessage('en', locale.en)
resolve()
}, 1000)
})
}
},
created () {
this.getData().then(() => {
this.text = this.$t('home')
})
}
})
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-i18n/dist/vue-i18n.js"></script>
<div id="app">
<p>{{ text }}</p>
</div>
Looking at the docs, you need to set the keypath.
Define:
const messages = { // keypath
id: {
home: 'Beranda'
},
en: {
home: 'Home'
}
}
And use the messages to set the default language:
const i18n = new VueI18n({
locale: 'id', // default locale
messages // keypath is set
})
If you use keypath name other than messages:
const translations = { // different keypath constant
id: {
home: 'Beranda'
},
en: {
home: 'Home'
}
}
const i18n = new VueI18n({
locale: 'id',
messages: translations // messages now use translations keypath
})
new Vue({
el: '#app',
i18n,
/* created () { // you don't need to set locale here
setTimeout(() => {
this.$i18n.setLocaleMessage(locale)
}, 100)
} */
})
Here's a working demo
Update
As per your comment, to set locale asynchronously - you can use like this:
const i18n = new VueI18n({
messages
})
new Vue({
el: '#app',
i18n,
created () {
setTimeout(() => {
this.$i18n.locale = 'id'
}, 100)
}
})
demo
Related
I am following an upgrade guide on how to go from Vue to Vue3. It shows how to handle it if the app is structured like:
new Vue({
router,
render: h => h(App)
}).$mount("#app");
The problem is that my my app is structured like this:
new Vue({
el: '#app',
data() {
return {
// initialData
};
},
mounted() {
// mounted
},
methods: {
}
}
Where do I place the data, mounted, methods, etc to have it work with the new structure in Vue 3?
You could import h to render the App component and use your usual options :
import {createApp,h} from 'vue'
...
createApp({
data() {
return {
// initialData
};
},
mounted() {
// mounted
},
methods: {
},
render: () => h(App)
})
isn't it the same as just creating an App Component?
const app = createApp(App);
app.mount("#app");
in the App Component
import { defineComponent, onMounted } from "vue";
export default defineComponent({
name: "App",
components: {},
setup() {
const initialData = "";
onMounted(() => {
console.log("mounted");
});
const aMethod = () => {
return null;
};
return {
initialData,
aMethod
};
}
});
</script>
I'm trying to use axios and router in the same time by using CDN, so I have these following codes that create an error when I try to run my webpage, I've been searching the whole day but couldn't help myself with it, I would appreciate if anyone has an idea.
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
listHotels: {},
hotel: {
name: '',
price: 0,
location: ''
}
}
},
methods: {
getHotels() {
axios.get('/database.json')
.then(res => {
this.listHotels = res.data.hotels.data;
});
},
addHotel() {
if (this.hotel.name === '' || this.hotel.price <= 0 || this.hotel.location === '') {
return alert('BOOOO ERROR');
}
const data = { ...this.hotel };
axios.post('/hotels.php', data)
.then(res => {
console.log(res.data);
this.getHotels();
});
this.hotel.name = '';
this.hotel.price = 0;
this.hotel.location = '';
}
},
created() {
this.getHotels();
}
});
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes // raccourci pour `routes: routes`
})
const app = new Vue({
router
}).$mount('#app')
</script>
The error I have :
A cookie associated with a cross-site resource at http://cloudflare.com/ was set without the `SameSite` attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.
Also, when I remove one of these code, axios or route, then it works.
Using cue-cli 3. Is it possible to do this (router.js):
axios.get( `${process.env.VUE_APP_API_DOMAIN}/wp-json/api/v1/routes`).then( r => r.data ).then(routes => {
routes.pages.forEach( (e) => {
router.addRoutes([
{
path: `/${e.slug}`,
component: e.template,
},
]);
});
});
e.template is a string 'Default' and of course VueJS says:
route config "component" for path: /privacy-policy cannot be a string id. Use an actual component instead. Tried with Vue.component(e.template) no luck.
What I want to do here is create dynamic routes based on XHR response.
Here is all router.js code:
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Default from './views/Default.vue'
import Test from './views/Test.vue'
import axios from "axios";
Vue.use(Router);
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
]
});
axios.get( `${process.env.VUE_APP_API_DOMAIN}/wp-json/api/v1/routes`).then( r => r.data ).then(routes => {
routes.pages.forEach( (e) => {
router.addRoutes([
{
path: `/${e.slug}`,
component: e.template,
},
]);
});
});
export default router;
Currently I ended up with this solution:
function getComponent(name) {
let component = null;
switch(name)
{
case 'Default':
component = Default;
break;
case 'Test':
component = Test;
break;
}
return component;
}
axios.get( `${process.env.VUE_APP_API_DOMAIN}/wp-json/api/v1/routes`).then( r => r.data ).then(routes => {
routes.pages.forEach( (e) => {
router.addRoutes([
{
path: `/${e.slug}`,
component: getComponent(e.template),
},
]);
});
});
Another one more cleaner solution:
const components = { Default, Test }
axios.get( `${process.env.VUE_APP_API_DOMAIN}/wp-json/api/v1/routes`).then( r => r.data ).then(routes => {
routes.pages.forEach( (e) => {
router.addRoutes([
{
path: `/${e.slug}`,
component: components[e.template],
},
]);
});
});
If e.template stores the template string,
You should wrap it as one options object like {template: e.template, props: {}, data: function () {} }, then call Vue.extend to construct the component.
or you can ignore Vue.extend because Vue will call Vue.extend to construct the component automatically.
Check the usage at Vue Guide: Vue.component
Edit as the OP states e.tempate is one component name:
if e.template is the name of component, uses Vue.component(e.template).
Vue.config.productionTip = false
const router = new VueRouter({
routes: [
]
})
Vue.component('test', {
template: '<div>I am Predefined component -> {{index}}</div>',
props: ['index']
})
let routerIndex = 1
setInterval(()=> {
let newComponent = routerIndex%2 ? {template: '<div>I am User -> {{index}}</div>', props: ['index']} : Vue.component('test')
router.addRoutes([{
path: '/Test' + routerIndex,
name: 'Test' + routerIndex,
component: newComponent,
props: { index: routerIndex }
}])
console.log('add route = ', '/Test' + routerIndex, ' by ', routerIndex%2 ? 'options object' : 'Vue.component')
routerIndex++
}, 2000)
Vue.use(VueRouter)
app = new Vue({
el: "#app",
router,
data: {
routeIndex: 0
},
watch: {
routeIndex: function (newVal) {
this.$router.push({'name': 'Test'+newVal})
}
}
})
div.as-console-wrapper {
height: 100px;
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<p>Current Route Index: {{routeIndex}}</p>
Test Route: <input v-model="routeIndex" type="number">
<router-view></router-view>
</div>
//this is my signupform.js where i have an object which have my form keys
import Datepicker from 'vuejs-datepicker'
import store from '../../store';
export default {
name: 'Signupform',
components: {
Datepicker,store
},
data() {
return {
enter_details:
{
username: '',
email: '',
contactNumber: '',
firstName: '',
lastName:'',
dob: '',
password: '',
repeat_password: ''
}
}
},
methods:{
addtoAPI() {
this.$store.dispatch('addtoapi',this.enter_details)
}
}
};
//this is my store's action
import vuex from 'vuex';
import axios from 'axios'
vue.use(vuex);
const store = new vuex.Store({
actions: {
addtoapi: ({commit}, enter_details) => {
let newuser = {
username: enter_details.username,
email: enter_details.email,
contactNumber: enter_details.contactNumber,
firstName: enter_details.firstName,
lastName: enter_details.lastName,
dob: enter_details.dob,
password: enter_details.password,
repeat_password: enter_details.repeat_password,
}
console.log(newuser);
axios.post('https://dev-api.mysc.io/int/api/v1', newuser)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
})
}
}
});
//now i am getting an error i.e
Signupform.js?22e4:28 Uncaught TypeError: this.$store.dispatch is not a function
at VueComponent.addtoAPI (Signupform.js?22e4:28)
at boundFn (vue.esm.js?efeb:190)
at invoker (vue.esm.js?efeb:2004)
at HTMLButtonElement.fn._withTask.fn._withTask
i am also getting one more error that when i try to see my store on vue on my browser it shows that "no vuex store"
please help me to resolve this error because i have alreaady
//this is my main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
/* eslint-disable no-new */
export const bus = new Vue();
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
In your store.js write this:
export default new Vuex.Store({
//
});
instead of
export default({
//
});
UPD: demo
And you don't need to include store as a component:
// signupform.js file ...
components: {
Datepicker,
store // <--- this is unnessesary
},
const store = new Vuex.Store({
actions: {
theAction() {
alert('Action fired');
},
},
});
const app = new Vue({
el: "#app",
store,
methods: {
fireAction() {
this.$store.dispatch('theAction')
},
},
})
<script src="https://unpkg.com/vue"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<div id="app">
<button #click="fireAction">Press me</button>
</div>
I have a test lister products and detail. Now when i go back with de backbutton in the browser is doesn't go back to the wright position.
So if i scroll down in the lister , click product to detail and back it doesn't go to the position i clicked before.
How can i achieve that?
Main.js
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})
Router:
export default new Router({
mode: 'history',
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
console.log(savedPosition)
return savedPosition;
} else {
return {x: 0, y: 0};
}
},
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/products',
name: 'Products',
component: Products,
props: true,
},
{
path: '/product/:id',
name: 'Productdetail',
component: Productdetail,
props: true
}
]
})
Lister:
<template>
<ul v-if="posts && posts.length">
<li v-for="post of posts" v-bind:id="post.id">
<p><strong>{{post.title}}</strong></p>
<p>{{post.body}}</p>
<router-link :to="{path: '/product/'+post.id, replace: true}">{{post.title}}</router-link>
<hr>
</li>
</ul>
</template>
import axios from 'axios';
export default {
name: 'Products',
props: ["guid"],
data() {
return {
posts: [],
msg: 'Products'
}
},
created() {
axios.get('http://jsonplaceholder.typicode.com/posts')
.then(response => {
// JSON responses are automatically parsed.
this.posts = response.data
})
.catch(e => {
this.errors.push(e)
})
//window.addEventListener('load', () => {
setTimeout(() => {
var str = window.location.hash;
var res = str.replace("#bas", "");
var div = document.getElementById(res);
var rect = div.getBoundingClientRect();
$('html, body').animate({
scrollTop: rect.top
}, 500);
}, 100)
//})
}
}
Detail :
Vue Router supports this behavior.
EDIT:
All you need to do is add scrollBehavior to your routerOptions.
export default new Router({
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
} else {
return { x: 0, y: 0 };
}
},
routes: []
});