is there a way to pass a single-spa prop to a vue i18n instance, assigning it to the messages i18n prop.
I18n constructor:
const i18n = new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE,
messages: {},
});
Vue single-spa instance:
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
el: '#account',
render() {
return (
<App
eventBus={this.$data.eventBus}
lang={this.$data.lang}
></App>
);
},
i18n,
},
});
Info: I dont have access to lang outside the render function.
Basically, I need the lang prop inside my i18n messages object. I tried already to return the lang and but it into the constructor, doesnt work.
I also tried to reinstantiate i18n/messages after lang is received, doesnt work either.
Any other ideas?
So I figured it out. It is only possible to alter the messages in your mounted vue instance with:
this.$i18n.setLocaleMessage = newLangObj
Related
I'm trying to write a story for a component that references this.$route.params. I'm not sure how to synthetically define this.$route in the context of a story. I think the solution is to use decorators, but all the examples in the docs focus on rendering, like adding a wrapping <div> etc. I'm not sure how to inject values.
I also found this project which appears designed for this exact situation, but it hasn't been maintained in years and README references outdated syntax that doesn't match modern versions of Storybook, so I don't think it's an option.
Here's what doesn't work:
import AssetShow from '../app/javascript/src/site/components/assets/Show'
export default {
title: 'Site/AssetShow',
component: AssetShow,
parameters: {
}
};
export const CustomerSpotlight = () => ({
components: { AssetShow },
template: '<AssetShow />',
});
import Vue from 'vue'
import VueRouter from 'vue-router'
import StoryRouter from 'storybook-vue-router';
CustomerSpotlight.decorators = [
(story) => {
Vue.use(VueRouter)
return {
components: { story },
template: '<story />'
}
}
];
The component I'm writing the story for has this:
mounted() {
axios.get(`.../bla/${this.$route.params.id}.json`)
},
...which causes Storybook to throw this error: TypeError: Cannot read properties of undefined (reading 'params')
I suppose that your intention is to do something with the story's component based on the route parameters?
If that is the case, then I don't think you need to define the route.params within the story context. I suggest either keeping that code within the component itself, or create an option within the story for the user to simulate adding parameters to the path. Which you can simply have as an input text / select field that you send down to the component as a prop.
In Vue3 - is there any way to globally disable Attribute Inheritance? I know that it's possible to set inheritAttrs to false when registering / creating a new component but what if I want to generally disallow this kind of behavior without having to change / add inheritAttrs: false to every single component I create?
A related question is Vue JS Non prop attributes and Disabling Attribute Inheritance - but it's only about if it's possible, not how you can do this globally...
The reason I want to disable it is that I want to achieve the same kind of behavior as in React / Angular - forwarding any props without receiving any error / warnings leads to inconsistency / unexpected behavior (possibly - especially with properties such as class and other native HTML Attributes).
A workaround we currently have is to import and re-export any component and "pre-processing" them:
import * as components from './components.ts'; // all components are re-exported with names
export * from './components.ts';
// Disable attribute-inheritance for every single component
Object.values(components).forEach((v) => (v.inheritAttrs = false));
It's technically possible to set inheritAttrs=false for every component by using a global mixin:
// main.js
import { createApp } from 'vue'
createApp(App)
.mixin({ inheritAttrs: false }) 👈
.mount('#app')
However, you should be aware that this does not cause Vue to emit warnings/errors when trying to set nonexistent props. Any such usage is silently ignored.
demo
We ended up writing a vite plugin to avoid mixins (since we're using vue3 and mixins are only there for backwards compatibility) to automatically inject { inheritAttrs: false }:
import { Plugin } from 'vite';
const DISABLED_INHERIT_SCRIPT = `
<script lang="ts">
export default { inheritAttrs: false };
</script>
`;
export const disableAttributeInheritance = (disable = true): Plugin => ({
name: 'DisableInheritAttributesPlugin',
transform: (src, id) => ({
code:
id.endsWith('.vue') && disable
? `${src}\n\n${DISABLED_INHERIT_SCRIPT}`
: src,
map: null
})
});
and use it like that:
export default defineConfig({
plugins: [
disableAttributeInheritance(),
vue()
]
});
I want to write a simple JS method that I will use both in Store GETTERS.
I created a new file: /plugins/myMethod.js and added it to nuxt.config.js (at plugins part).
Follows the content of the file:
export default ({ app }, inject) => {
// Inject $hello(msg) in Vue, context and store.
inject('exportaData', msg => console.log(`Data is: ${msg}!`))
}
I can use this method in Vue Components and in store ACTIONS, but not in Store GETTERS. I tried this.$myMethod(1) without any success.
Follows the code of store/data.js
export const getters = {
hoje: state => {
console.log('Running getter HOJE')
this.$exportaData('12345')
},
}
and in my Vue component:
<p>DATA: {{ $store.getters['datas/hoje'] }}</p>
Any idea how to access my custom method in the store getter?
Thanks
I'm trying to make a global function with help of plugin which it worked fine but i couldn't show my notification. I was doing my homework and i tried to not write everywhere those show notification methods, so I've searched and i found this solution and i managed to add plugin now i wan to use it in my component. here's the code :
AppNotifications.js
export default {
failedNotification(title, data) {
return this.$vs.notify({
title:title,
text:data,
color:'danger',
position:'bottom-center',
});
}
};
App.js
import Vue from 'vue'
import notifications from './Helpers/AppNotifications'
const plugin = {
install () {
Vue.notifications = notifications
Vue.prototype.$notifications = notifications
}
}
Vue.use(plugin)
const app = new Vue({
vuetify,
el: '#app',
render: h => h(App),
router
});
And in componenets when i use a button with #click="SomeMethod" i use plugin like this :
this.$notifications.failedNotification('Test','Just Failed, yay')
So function work but i get this error
Error in v-on handler: "TypeError: Cannot read property 'notify' of undefined"
Since I'm in learning process i wasn't familiar with this issue and I've tried to import vue and notification component itself but didn't worked.
Edit 01 : Notification is belong to Vuesax library and it's already imported in App.js and it's working fine when i use it in vue components but it's not working when i use it in AppNotification.js
So i found the solution for my problem and it fixed with sending this as parameter to function.
Vue Component :
//this was before the problem
this.$notifications.failedNotification('Test','Just Failed, yay')
//then i added this as parameter
this.$notifications.failedNotification(this,'Test','Just Failed, yay')
And in AppNotification.js
//Before changing
failedNotification(title, data) {
return this.$vs.notify({
title:title,
text:data,
color:'danger',
position:'bottom-center',
});
}
//Then i added self and replaced self with `this`
failedNotification(self,title, data) {
return self.$vs.notify({
title:title,
text:data,
color:'danger',
position:'bottom-center',
});
}
And it's worked.
The error you're getting suggests that the notification library you're using isn't being loaded and if you posted the entire code of your App.js file then it looks like you're missing some code.
The file probably needs to look something like this:
import Vue from 'vue'
import Vuesax from 'vuesax'
import notifications from './Helpers/AppNotifications'
import 'vuesax/dist/vuesax.css' //Vuesax styles
const plugin = {
install () {
Vue.notifications = notifications
Vue.prototype.$notifications = notifications
}
}
Vue.use(Vuesax)
Vue.use(plugin)
const app = new Vue({
vuetify, // <-- not sure where vuetify is coming from?
el: '#app',
render: h => h(App),
router
});
I just want to be able to call
{{ globalThing(0) }}
in templates, without needing to define globalThing in each .vue file.
I've tried all manner of plugin configurations (or mixins? not sure if Nuxt uses that terminology.), all to no avail. It seems no matter what I do, globalThing and this.globalThing remain undefined.
In some cases, I can even debug in Chrome and see this this.globalThing is indeed defined... but the code crashes anyway, which I find very hard to explain.
Here is one of my many attempts, this time using a plugin:
nuxt.config.js:
plugins: [
{
src: '~/plugins/global.js',
mode: 'client'
},
],
global.js:
import Vue from 'vue';
Vue.prototype.globalFunction = arg => {
console.log('arg', arg);
return arg;
};
and in the template in the .vue file:
<div>gloabal test {{globalFunction('toto')}}</div>
and... the result:
TypeError
_vm.globalFunction is not a function
Here's a different idea, using Vuex store.
store/index.js:
export const actions = {
globalThing(p) {
return p + ' test';
}
};
.vue file template:
test result: {{test('fafa')}}
.vue file script:
import { mapActions } from 'vuex';
export default {
methods: {
...mapActions({
test: 'globalThing'
}),
}
};
aaaaaaaaand the result is.........
test result: [object Promise]
OK, so at least the method exists this time. I would much prefer not to be forced to do this "import mapActions" dance etc. in each component... but if that's really the only way, whatever.
However, all I get is a Promise, since this call is async. When it completes, the promise does indeed contain the returned value, but that is of no use here, since I need it to be returned from the method.
EDIT
On the client, "this" is undefined, except that..... it isn't! That is to say,
console.log('this', this);
says "undefined", but Chrome's debugger claims that, right after this console log, "this" is exactly what it is supposed to be (the component instance), and so is this.$store!
I'm adding a screenshot here as proof, since I don't even believe my own eyes.
https://nuxtjs.org/guide/plugins/
Nuxt explain this in Inject in $root & context section.
you must inject your global methods to Vue instance and context.
for example we have a hello.js file.
in plugins/hello.js:
export default (context, inject) => {
const hello = (msg) => console.log(`Hello ${msg}!`)
// Inject $hello(msg) in Vue, context and store.
inject('hello', hello)
// For Nuxt <= 2.12, also add 👇
context.$hello = hello
}
and then add this file in nuxt.config.js:
export default {
plugins: ['~/plugins/hello.js']
}
Use Nuxt's inject to get the method available everywhere
export default ({ app }, inject) => {
inject('myInjectedFunction', (string) => console.log('That was easy!', string))
}
Make sure you access that function as $myInjectedFunction (note $)
Make sure you added it in nuxt.config.js plugins section
If all else fails, wrap the function in an object and inject object so you'd have something like $myWrapper.myFunction() in your templates - we use objects injected from plugins all over the place and it works (e.g. in v-if in template, so pretty sure it would work from {{ }} too).
for example, our analytics.js plugin looks more less:
import Vue from 'vue';
const analytics = {
setAnalyticsUsersData(store) {...}
...
}
//this is to help Webstorm with autocomplete
Vue.prototype.$analytics = analytics;
export default ({app}, inject) => {
inject('analytics', analytics);
}
Which is then called as $analytics.setAnalyticsUsersData(...)
P.S. Just noticed something. You have your plugin in client mode. If you're running in universal, you have to make sure that this plugin (and the function) is not used anywhere during SSR. If it's in template, it's likely it actually is used during SSR and thus is undefined. Change your plugin to run in both modes as well.
This would be the approach with Vuex and Nuxt:
// store/index.js
export const state = () => ({
globalThing: ''
})
export const mutations = {
setGlobalThing (state, value) {
state.globalThing = value
}
}
// .vue file script
export default {
created() {
this.$store.commit('setGlobalThing', 'hello')
},
};
// .vue file template
{{ this.$store.state.globalThing }}