Nuxt.js3 plugin's context becomes undefined - javascript

I am developing an application using Nuxt.js3 and supabase.
Nuxt.js in plugins/supabase.server.js (I haven't figured out if server or client is better for this too.) I want to use "supabase = createClient(~~)" from index.vue.
However, I get undefined, either because the import is not working or because I am calling it the wrong way.
If I use the mustache syntax and call it like "{{ $supabase }}", the function will appear.
(I am not good at English, so I use translated sentences.)
plugins/supabase.server.js
import { defineNuxtPlugin } from '#app'
import { createClient } from '#supabase/supabase-js/dist/main/index.js'
export default defineNuxtPlugin(nuxtApp => {
const config = useRuntimeConfig();
nuxtApp.provide('supabase', () => createClient(config.supabaseUrl, config.supabaseKey))
})
declare module '#app' {
interface NuxtApp {
$supabase (): string
}
}
pages/index.vue
<script setup>
console.log($supabase) //$supabase is not defined
</script>
<template>
{{ $supabase }} // () => createClient(config.supabaseUrl, config.supabaseKey)
</template>

Please import useRuntimeConfig from '#app'. So in your example change the first line:
import { defineNuxtPlugin } from '#app'
Into:
import { defineNuxtPlugin, useRuntimeConfig } from '#app'

Related

JSONForms Vue Basic String Custom Renderer

So I'm starting out with Vue JSONForms and I'm trying to create a bare-bones custom text renderer. I know there JSONForms has the vue-vanilla package, but I want to understand what are the basics needed for a custom renderer because later on I will need to do much more customization to each custom renderer I create. Here is what I have so far:
<template>
<v-input />
</template>
<script lang="ts">
import { ControlElement, JsonFormsRendererRegistryEntry, rankWith, isStringControl } from '#jsonforms/core'
import { useJsonFormsControl, RendererProps } from '#jsonforms/vue'
import { defineComponent } from 'vue'
const renderersText = defineComponent({
name: 'renderers-text',
setup (props: RendererProps<ControlElement>) {
return useJsonFormsControl(props)
},
})
export default renderersText
export const entry: JsonFormsRendererRegistryEntry = {
renderer: renderersText,
tester: rankWith(1, isStringControl),
}
</script>
But I'm getting a r.tester is not a function error. Any idea what this means and/or what I need to fix? Thanks in advance!

How do I create a function library which I can used across all my Vuejs components?

I currently writing a financial application using Vue.js and Vuetify. I have a few component files and javascript files like
Dashboard.vue
Cashflow.vue
NetWorth.vue
stores.js <- Vue Vuex
I have some functions which I need to use across all the Vue.js and javascript files. Would it be possible for me to perhaps write a function library which can be used across all
the component and js files.
function moneyFormat(num)
function IRRCalc(Cashflow)
function TimeValueMoneyCalc(I,N,PV,FV,PMT)
function PerpetualAnnuityCalc(I,PV)
function CarLoanInstallment(V,N)
function HouseLoanInstallment(V,N)
I know in C it is very simple just #include<financial.h> was wondering is there something similar in javascript.
Thanks.
There are 3 ways to do this:
1/You can create a helper.js file and import it to .vue files
// helper.js
export default {
function moneyFormat(num) { // some logic}
}
// Dashboard.vue
<script>
import helper from "helper.js" //the path may change depends on where you put the js file
methods: {
useHelper(value) {
helper.moneyFormat(value)
}
}
</script>
2/Another way is bind the function to Vue prototype
in main.js
Vue.prototype.$moneyFormat= function moneyFormat(num) {}
then in Dashboard.vue just call this.$moneyFormat(num). No need to import anything
3/ Use mixins. You can search online on how to use this https://v2.vuejs.org/v2/guide/mixins.html
You can create a single JS file that holds all the helper/util methods, and then export them individually:
export function moneyFormat(num) { ... }
export function IRRCalc(Cashflow) { ... }
export function TimeValueMoneyCalc(I,N,PV,FV,PMT) { ... }
export function PerpetualAnnuityCalc(I,PV) { ... }
export function CarLoanInstallment(V,N) { ... }
export function HouseLoanInstallment(V,N) { ... }
Then, you can simply import individual methods as of when needed, i.e.:
import { CarLoanInstallment, HouseLoanInstallment } from '/path/to/helper/file';
This can be quite usefuly for tree-shaking when you're bundling with webpack, for example, so that you don't bundle unnecessary functions that are never used in your project.
You can use Mixin
In your main.js, add Vue.mixin:
import Vue from "vue";
import App from "./App.vue";
Vue.mixin({
methods: {
helloWorld() {
alert("Hello world");
}
}
});
new Vue({
render: h => h(App)
}).$mount("#app");
and then you can call helloWorld() method from your component script with this.helloWorld() or just helloWorld() from the template.
You also can use filters if the method is to apply common text formatting
In your main.js, add Vue.filter:
import Vue from "vue";
import App from "./App.vue";
Vue.filter("capitalize", function(value) {
if (!value) return "";
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
});
new Vue({
render: h => h(App)
}).$mount("#app");
and then you can do {{ "some text" | capitalize }} to apply capitalize filter on "some text"
Example here: https://codesandbox.io/s/heuristic-dirac-esb45?file=/src/main.js:0-226

VueJS; wait for element before running local JavaScript File

I have a few components, javascript, and elements that needs to be ran in a certain order.
1st - opensheetmusicdisplay.min.js which I have in my index.html file. This isn't an issue.
2nd - <div id="xml">
3rd - xml-loader.js which depends on both the "xml" div and opensheetmusicdisplay.min,js
This is the index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<script rel="preload" src="<%= BASE_URL %>js/osmd/opensheetmusicdisplay.min.js"></script>
</head>
<body>
<div id="xml2">words go here</div>
<div id="app"></div>
</body>
</html>
And this is the JavaScript part I'm attempting to test:
window.onload = function() {
alert("xx == ", document.getElementById("xml2"));
}
alert("xx2 == ", document.getElementById("xml2"));
alert(JSON.stringify(opensheetmusicdisplay, null, 1));
When I run this, they both instances of "xml2" show blanks. The opensheetmusicdisplay does show data, which means it is reading from the source in the head section in index.html
It was pointed out to me in the comments that alert only take one argument. That's a mistake that I'm going to let sit for the moment. The error in the console is TypeError: document.getElementById(...) is null.
Now, this is the main.js. There are a lot of comments because of my various ideas:
// vue imports and config
import Vue from 'vue'
import App from '#/App'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
Vue.config.productionTip = false
// page imports
import Notation from '#/components/Notation'
import HomePage from '#/components/HomePage'
// component imports and registration
import { FoundationCSS } from '#/../node_modules/foundation-sites/dist/css/foundation.min.css'
Vue.component('foundation-css', FoundationCSS)
import SideNav from '#/components/SideNav'
Vue.component('side-nav', SideNav);
// import * as Osmd from '#/../public/js/osmd/opensheetmusicdisplay.min.js'
// Vue.component('osmd-js', Osmd)
// import { OsmdJs } from '#/components/Osmd'
import * as XmlJs from '#/../public/js/osmd/xml-loader.js'
Vue.component('xml-js', XmlJs)
// import XLoad from '#/components/XmlLoader'
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/',
components: {
maininfo: HomePage
}
},
{ path: '/chromatic-scales/c-chromatic-scale',
components: {
maininfo: Notation// ,
// xmlloader: XLoad
}
}
]
})
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})
I registered XmlJs as global because this is the only way out of 100 things that actually works. I then embed it in Notation.vue like so:
<template>
<div>
<div id="xml">
{{ notation.data }}
</div>
<xml-js />
</div>
</template>
<script>
import axios from 'axios'
export default ({
data () {
return {
notation: null,
}
},
mounted () {
axios
.get('http://localhost:3000/chromatic-scales/c-chromatic-scale')
.then(result => (this.notation = result))
}})
</script>
<style scoped></style>
The last file is the meat and potatoes of what I'm trying to do. The xml-loader.js slurps the data from <div id="xml"> and does whatever magic the program does in order to render the output I want. The issue is that there doesn't seem to be anyway to wait for the stuff in {{ notation.data }}.
I am new to using vuejs and front-end javascript frameworks in general. I do recognize the code is probably not optimal at this time.
There is race condition where DOM element is not available at the time when it's accessed. The solution is to not access DOM elements created by Vue outside of it. DOM element is ready for use only after asynchronous request:
<template>
<div>
<div ref="xml" id="xml">
{{ notation.data }}
</div>
<xml-js />
</div>
</template>
<script>
import axios from 'axios'
export default ({
data () {
return {
notation: null,
}
},
async mounted () {
const result = await axios
.get('http://localhost:3000/chromatic-scales/c-chromatic-scale')
this.notation = result;
this.$nextTick(); // wait for re-render
renderXml(this.$ref.xml); // pass DOM element to third-party renderer
}})
You can import xml-loader.js into the Notation.vue as a function. Then you can simply do something like this:
mounted () {
axios.get(PATH).then(result => {
this.notation = result
let xmlResult = loadXML(result)
doSomethingWithResult(xmlResult)
}
},
methods: {
doSomethingWithResult (result) {
// do something
}
}

use vuejs variable in pure javascript file

I'm practicing laravel with vuejs and I'm wondering if possible to use vuejs (component) variable in other file with pure javascript.
I created my.js and registered it in app.js.
require('./my.js');
const app = new Vue({
el: '#app'
});
In my.js I have following code.
alert(app.name)
name is variable used in vuejs component. As a result I received alert undefined. Please give me some guidelines.
You must run the code in the correct order:
function MyFunc(vm) {
alert(vm.name)
}
const app = new Vue({
data: {
name: 'FooBar'
}
});
MyFunc(app)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
Example 1
my.js:
export default function(vm) {
alert(vm.name);
}
main.js:
import Vue from "vue";
import MyFunc from './my';
const app = new Vue({
data: {
name: 'FooBar'
}
});
MyFunc(app)
Example 2
my.js:
export default (app) => alert(app.name);
vue.js:
import Vue from 'vue';
export default new Vue({
data: {
name: 'FooBar'
}
});
main.js:
import bar from './vue'
import foo from './my'
foo(bar)

Import .vue file

I have main.js and app.vue file
main js file inner look like this
var a = 1;
import App from './App.vue'
new Vue({
el: '#app',
render: h => h(App)
})
in App.vue file i want to console.log(a)
return error a is not defined why ? What is wrong ?
You need to export the variable, and then import it into another file where you want it. The best way to do that would be to put the variable a in its own module file. This allows you to avoid using global variables, which pretty much negate the purpose of modules!
a.js:
export const a = 'foo'
App.vue:
<script>
import { a } from './a.js'
console.log(a) // foo
console.log(1)
export function log3() {
console.log(3)
}
</script>
main.js:
import { log3, default as App } from './App.vue'
console.log(2)
log3()
new Vue({
el: '#app',
render: h => h(App)
})
import { a } from './a.js'
console.log(a) // foo
Here is what will be logged to the console:
'foo' (from App.vue)
1 (from App.vue)
2 (from main.js)
3 (from main.js calling the function log3 from App.vue)
'foo' (from main.js)
Now both App.vue and main.js have access to a, because they have explicitly imported it. The fact that App.vue has access to a has nothing to do with the fact that main.js also has access to a.
The simplest thing you can do I guess is define data properties insode root instance, and access them as this.$root.myProperty from components:
new Vue({
el: '#app',
data: {
myGlobal: 'Hi there'
},
components: {
'child' : {
template: `<p>{{ text }}</p>`,
data: function() {
return {
text: this.$root.myGlobal
}
}
}
}
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<child></child>
</div>
Another option - a simple plugin as a central storage: https://stackoverflow.com/a/44517332/7636961
a is not defined in your App component but directly in main.js.
You may want to use a global variable. (see also this thread for global variable in vuejs)

Categories