If I use Vue2 with no build step, is there a way to use Vue-I18n the same way?
<!doctype html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
<script src="https://unpkg.com/vue-i18n#8"></script>
</head>
<body>
<div id="vueApp"></div>
<script>
const VueI18n = window.VueI18n;
if (VueI18n) {
const i18n = new VueI18n({
locale: 'en',
messages: {
en: {
hello: 'Hello there!',
}
}
});
Vue.use(i18n);
}
new Vue({
template: '<div><p>This is Vue!</p><p>{{welcome}} and {{hello}}</p></div>',
el: document.querySelector('#vueApp'),
data: function() {
return {
welcome: 'Welcome',
hello: this.$t('hello'),
};
},
});
</script>
</body>
</html>
I hope to see
This is Vue!
Welcome and Hello there!
Instead, the dev console has the message
TypeError: Cannot read properties of undefined (reading '_t')
at Vue.$t (vue-i18n#8:242:19)
at Vue.data (vuei18.html:29:29)
at Vue.mergedInstanceDataFn (vue.js:1240:22)
at getData (vue.js:4758:19)
at initData (vue.js:4715:9)
at initState (vue.js:4654:7)
at Vue._init (vue.js:5014:7)
at new Vue (vue.js:5092:10)
at vuei18.html:23:5
Am I completely out of luck, or is there a way to make this happen?
Thanks for any help.
this.$t() is the same as t() from the VueI18n instance (i.e., the result of new VueI18n()), so you can use it here:
const VueI18n = window.VueI18n;
let i18n = null
if (VueI18n) {
👇
i18n = new VueI18n({⋯});
Vue.use(i18n);
}
new Vue({
â‹®
data: function() {
return {
welcome: 'Welcome',
👇
hello: i18n?.t('hello'),
};
},
});
<head>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
<script src="https://unpkg.com/vue-i18n#8"></script>
</head>
<body>
<div id="vueApp"></div>
<script>
const VueI18n = window.VueI18n;
let i18n = null
if (VueI18n) {
i18n = new VueI18n({
locale: 'en',
messages: {
en: {
hello: 'Hello there!',
}
}
});
Vue.use(i18n);
}
new Vue({
template: `<div><p>This is Vue!</p><p>{{welcome}} and {{hello}}</p></div>`,
el: document.querySelector('#vueApp'),
data: function() {
return {
welcome: 'Welcome',
hello: i18n?.t('hello'),
};
},
});
</script>
</body>
Related
what I want to do is to send a value to the file "Notification.vue" when the button is clicked in the hello word file and I want to show Notification
toastify
helloword.vue
<template>
<button #click="toast">Toast it!</button>
</template>
<script>
export default {
name: "helloword",
methods: {
toast() {
}
}
}
</script>
Notification.vue
<script setup>
import {createToast} from 'mosha-vue-toastify';
import 'mosha-vue-toastify/dist/style.css'
const props = defineProps({title: String})
const toast = () => {
createToast(props.title)
}
</script>
I just created a demo with Vue 2 for your understanding how components will communicate. You can migrate this in Vue 3.
Demo :
Vue.use(VueToast, {
// global options
});
Vue.component('notification', {
props: ['title'],
mounted() {
if (this.title) {
this.$toast.open({
message: this.title,
type: "success",
duration: 5000,
dismissible: true
})
}
}
});
var app = new Vue({
el: '#app',
data: {
title: null,
},
methods: {
toast: function() {
this.title = 'Welcome!'
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-toast-notification#0.6/dist/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vue-toast-notification#0.6/dist/theme-sugar.css"/>
<div id="app">
<button #click="toast">Toast it!</button>
<notification v-if="title" :title="title"></notification>
</div>
I have a simple set of data that will come in from my method. I need the data to display inside of my vue model thats all which is inside an object or array. Honestly, any that works. Normally, just adding vm.array name or object name works on success but cannot get it to display.
new Vue({
el: "#app",
data: {
mydata:{}
},
methods: {
getTokenData(){
$.ajax({
url: "https://jsonplaceholder.typicode.com/posts/1",
success: function (data, status) {
alert("success");
console.log(data);
this.mydata=data;
},
mounted: function(){
this.getTokenData();
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{mydata}}
</div>
This might work well
new Vue({
el: "#app",
data() {
return {
mydata: {}
}
},
methods: {
getTokenData(){
axios
.get("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => {
// this.mydata=data;
if (response.status) {
this.mydata = response.data;
console.log("myData ===>", this.mydata);
}
});
}
},
mounted: function(){
this.getTokenData();
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="app">
title: {{mydata.title}}
<br>
body: {{mydata.body}}
</div>
I try to render components dynamically based on descriptions.
From
{component: 'customComponent', props: {value: "val1"}, ...}
I'd render
<custom-component :value="val1" #input="v=>val1=v" />`
I aim to do this for arbitrary events and dynamic props.
I have no idea though how to pass dynamic props to render.
Partial solution:
A solution that works but re-renders everytime val1 changes, based on (https://symfonycasts.com/screencast/vue/vue-instance) is
render: function(h){
const template = "...building up the html here..."
return Vue.compile(template).render.call(this, h);
}
My attempt using the VueJS docs
I could not find in the docs on render how I could pass dynamic variables.
In the minimal implementation you can see how far I've got, if you can help me finish it, it would be awesome!
Minimal implementation so far
I expect to see 'hello' instead of 'values.value1' and values.value1 should update once I change the text in the text box.
demo.html:
<!DOCTYPE html>
<html>
<body>
<div id="q-app">
The text input should say 'hello' instead of 'values.value1'
<custom-component :descriptor="mainComponent"></custom-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.15.15/dist/quasar.umd.min.js"></script>
<script>
Vue.component('custom-component', {
props: ['descriptor'],
render: function (createElement) {
const attributes = {
on: this.descriptor.events,
props: this.descriptor.props
}
return createElement(
this.descriptor.component,
attributes)
}
})
const app = new Vue({
el: '#q-app',
data: function(){
return {
mainComponent: {
component: 'q-input',
props: {
value: 'values.value1'
},
events: {
input: value => this.values.value1 = value
}
},
values: {
value1: 'hello'
}
}
}
})
</script>
</body>
I guess, I have fixed your example.
Of course, you can watch the value in the main app. But it is better to sent an input event with the value.
Added the reference to the component
ref="mc"
and the input event binding
#input="logEventValue"
Vue.component('custom-component', {
props: ['descriptor'],
render: function (createElement) {
const attributes = {
on: this.descriptor.events,
props: this.descriptor.props
}
return createElement(
this.descriptor.component,
attributes)
}
})
const app = new Vue({
el: '#q-app',
data: function(){
return {
mainComponent: {
component: 'q-input',
props: {
value: 'hello'
},
events: {
input: value => {
this.values.value1 = value;
// with ref="mc"
this.$refs.mc.$emit('input', value);
// or over the list of children
this.$children[0].$emit('input', value);
}
}
},
values: {
value1: 'hello'
}
}
},
watch: {
'values.value1': (newVal) => console.log(`1. watcher: ${newVal}`),
// or deeply
values: {
handler(newVal) {
console.log(`2. watcher: ${newVal.value1}`)
},
deep: true,
}
},
methods: {
logEventValue(value) {
console.log(`logEventValue: ${value}`);
}
}
})
<div id="q-app">
<custom-component ref="mc" #input="logEventValue" :descriptor="mainComponent"></custom-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.15.15/dist/quasar.umd.min.js"></script>
Is it possible to declare and pass a data-attribute value from a html tag of the Vue instance, and then have it available in the data object?
index.html:
<div id="app" data-title="My app title"></div>
App.vue:
data () {
return {
appTitle: // whatever is declared in data-title
}
}
This code works for me:
index.html:
<div id="app" data-id="123"></div>
index.js:
(function (el) {
new Vue({
el,
render: h => h(Module),
data: () => Object.assign({}, el.dataset) ,
});
})(document.getElementById('app'));
Module.vue:
export default {
name: 'Module',
data() {
return {
id: this.$parent.id,
};
},
};
Yes it is:
data () {
return {
appTitle: document.getElementById('app').dataset.title
}
}
However, it is possible that the DOM is not available on component initialization. So you should probably put that code into the mounted hook of your component:
<script>
export default {
data () {
return {
appTitle: null
}
},
mounted () {
this.appTitle = document.getElementById('app').dataset.title
}
}
</script>
Here's a different approach that doesn't rely on the DOM API, but cannot be used to get data-attributes from the root (#app) element:
{
el: '#app',
template: `
<div ref="mydiv" data-attribute="data attribute">
Hello from template
<div>
Hello from {{attribute}}
</div>
</div>`,
data(){
return {
attribute: ''
}
},
mounted(){
this.$data.attribute = this.$refs.mydiv.dataset.attribute;
}
});
Here's a pen with a working example
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