Sending and initializing data to another component with vue 3 - vue.js

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>

Related

Can I use Vue-I18n without a build step?

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>

get returned data to display inside of vue model

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>

Passing data-attribute from Vue instance html tag

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

VueJs Nested props coming through undefined

I am trying to access an array which is part of a prop (event) passed into a component, but when in created() or mounted() the array part of the event prop (the rest is fine) comes through as undefined.
As can be seen below, when I inspect the props in the vue chrome plugin, the registration_fields are there.
I can add a watcher to the event prop and can access the registration_fields that way, but this seems very awkward to have to do this to access already passed in data.
This is from the Chrome vue inspector:
event:Object
address1_field:"Some Address 1"
address2_field:"Some Address 2"
approved:true
registration_fields:Array[1]
This is what part of my vue file looks like:
export default {
props: ['event'],
data() {
return {
regFields: []
}
},
created() {
this.regFields = this.event.registration_fields // Undefined here!
},
watch: {
event() {
this.regFields = this.event.registration_fields //Can access it here
});
}
}
}
I am using Vue 2.4.4
This is how the component is called:
<template>
<tickets v-if="event" :event="event"></tickets>
</template>
<script>
import tickets from './main_booking/tickets.vue'
export default {
created() {
var self = this;
this.$http.get('events/123').then(response => {
self.event = response.data
}).catch(e => {
alert('Error here!');
})
},
data: function () {
return {event: {}}
},
components: {
tickets: tickets
}
}
</script>
Thank you
It actually works fine without the watcher.
new Vue({
el: '#app',
data: {
event: undefined
},
components: {
subC: {
props: ['event'],
data() {
return {
regFields: []
}
},
created() {
this.regFields = this.event.registration_fields // Undefined here!
}
}
},
mounted() {
setTimeout(() => {
this.event = {
registration_fields: [1, 3]
};
}, 800);
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<sub-c v-if="event" :event="event" inline-template>
<div>
{{regFields}}
</div>
</sub-c>
</div>
If, as Belmin Bedak suggests in the comment below, event is populated asynchronously, it comes in as undefined because it's undefined. In that case, you need a watcher, or, somewhat more elegantly, use a computed:
new Vue({
el: '#app',
data: {
event: {}
},
components: {
subC: {
props: ['event'],
computed: {
regFields() {
return this.event.registration_fields;
}
}
}
},
// delay proper population
mounted() {
setTimeout(() => { this.event = {registration_fields: [1,2,3]}; }, 800);
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<sub-c :event="event" inline-template>
<div>
{{regFields}}
</div>
</sub-c>
</div>

How to pass property to component used in main.js from other components in vuejs

Basically I want to a loadingbar component globally (included in app template)
Here is my loadingbar component
<template>
<div class="loadingbar" v-if="isLoading">
Loading ...
</div>
</template>
<script>
export default {
name: 'loadingbar',
props: ['isLoading'],
data () {
return {
}
}
}
</script>
<style scoped>
</style>
and in main.js, I have included this component as
import LoadingBar from './components/LoadingBar.vue';
new Vue({
router,
data () {
return {
isLoading: true
};
},
methods: {
},
created: function () {
},
components: {
LoadingBar
},
template: `
<div id="app">
<LoadingBar :isLoading="isLoading"/>
<router-view></router-view>
</div>
`
}).$mount('#app');
My aim is to show loading component based upon the value of variable isLoading. The above code working fine. But I want to use set isLoading variable from other component (so that to decide whether to show loading component). Eg. In post components
<template>
<div class="post container">
</div>
</template>
<script>
export default {
name: 'post',
data () {
return {
posts: []
}
},
methods: {
fetchPosts: function() {
// to show loading bar
this.isLoading = true;
this.$http.get(APIURL+'listpost')
.then(function(response) {
// to hide loading bar
this.isLoading = false;
console.log("content loaded");
});
}
},
created: function() {
this.fetchPosts();
}
}
</script>
<style scoped>
</style>
Of coarse we can't access isLoading directly from main.js so i decided to use Mixin so i put following code in main.js
Vue.mixin({
data: function () {
return {
isLoading: false
};
}
});
This however allow me to access isLoading from any other component but I can't modify this variable. Can any help me to achieve this?
Note: I know i can achieve this by including loadingbar in individual component (I tried that and it was working fine, But i do not want to do that as loadingbar is needed in every component so i was including in main template/component)
You could use Vuex like so:
// main.js
import Vuex from 'vuex'
let store = new Vuex.Store({
state: {
isLoading: false,
},
mutations: {
SET_IS_LOADING(state, value) {
state.isLoading = value;
}
},
getters: {
isLoading(state) {
return state.isLoading;
}
}
})
import LoadingBar from './components/LoadingBar.vue';
new Vue({
router,
store, // notice you need to add the `store` var here
components: {
LoadingBar
},
template: `
<div id="app">
<LoadingBar :isLoading="$store.getters.isLoading"/>
<router-view></router-view>
</div>
`
}).$mount('#app');
// script of any child component
methods: {
fetchPosts: function() {
// to show loading bar
this.$store.commit('SET_IS_LOADING', true);
this.$http.get(APIURL+'listpost')
.then(function(response) {
// to hide loading bar
this.$store.commit('SET_IS_LOADING', false);
console.log("content loaded");
});
}
},