Event #change is fire but cant get it in Vue Component Verte - vue-component

can't catch the changed event
my template code:
<template>
<verte #change="changeColor(1)"></verte>
</template>
<script>
import Verte from 'verte';
export default {
components: { verte }
methods: {
changeColor(id) {
console.log(id)
},
}
</script>
in vue inspector event #change starts..
tried changing this line
from import Verte from 'verte';
to import VertePicker from 'verte';
...
but as a result, only the input event fires, but I just can’t catch the event on changed
maybe something else is needed to correctly trigger the event? and could this be a component bug?

Verte is not supporting change event.
You can call changeColor as below.
<template>
<verte v-model="colorVal"></verte>
</template>
<script>
import Verte from 'verte';
export default {
components: { Verte },
data: () => ({
colorVal: ''
}),
watch: {
// whenever colorVal changes, this function will run
colorVal(currentColor, previousColor) {
// you can call changeColor function here.
changeColor(currentColor);
}
},
methods: {
changeColor(id) {
console.log(id)
},
}
</script>

Related

Storybook Vue3 - Work with v-model in stories

I have a question regarding Storybook and Vue components with v-models. When writing a story for let's say an input component with a v-model i want a control reflecting the value of this v-model. Setting the modelValue from the control is no problem, but when using the component itself the control value stays the same. I am searching the web for a while now but i can't seem to find a solution for this.
A small example:
// InputComponent.vue
<template>
<input
type="text"
:value="modelValue"
#input="updateValue"
:class="`form-control${readonly ? '-plaintext' : ''}`"
:readonly="readonly"
/>
</template>
<script lang="ts">
export default {
name: "GcInputText"
}
</script>
<script lang="ts" setup>
defineProps({
modelValue: {
type: String,
default: null
},
readonly: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['update:modelValue']);
const updateValue = (event: Event) => {
const target = event.target as HTMLInputElement;
emit('update:modelValue', target.value);
}
</script>
In Storybook:
Does anyone have a solution to make this working?
Thanks in advance!
In my case, I have a custom select input that uses a modelValue prop.
I tried this and worked for me:
at my-component.stories.js:
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
export default {
title: 'Core/MyComponent',
component: MyComponent,
argTypes: { }
}
const Template = (args) => ({
components: { MyComponent },
setup() {
let model = ref('Javascript')
const updateModel = (event) => model.value = event
return { args, model, updateModel }
},
template: '<my-component v-bind="args" :modelValue="model" #update:modelValue="updateModel" />'
})
export const Default = Template.bind({})
Default.args = {
options: [
'Javascript',
'PHP',
'Java'
]
}

How to render an html string with vuejs inside in Nuxt3 / Vue3

I'm trying to write a component in Nuxt3 which will allow me to output a string of html (that contains vue elements).
Here is what I have so far for the component / plugin
plugins/RenderVueString.js
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.component('RenderVueString', {
props: ['html'],
render(h) {
return h({
template: `<div class="RenderVueString">${this.html}</div>`,
})
}
})
})
And then in pages/index.vue
<template>
<RenderVueString :html="vueHTML" />
</template>
<script>
export default {
data() {
return: {
vueHTML: `<div>This is some vue HTML {{testVar}} <a #click="testFunction()">Run Function</a></div>`,
testVar: 'Var Value Here'
}
},
methods: {
testFunction() {
console.log('test function ran');
}
}
}
</script>
I get this error: TypeError: h is not a function
So I tried adding this to the top of the plugins/RenderVueString:
import {h} from 'vue';
After that there is no console errors, but nothing renders.
I did try rendering something simple with h like this: h('div', 'Hello') and it did output that, but I can't figure out how to output complex html with embedded Vue.
Was able to figure this out by adding the following to nuxt.config.ts
hooks: {
'vite:extendConfig': (config, {isClient, isServer}) => {
if(isClient) {
config.resolve.alias.vue = 'vue/dist/vue.esm-bundler'
}
}
},
nitro: {
commonJS: {
dynamicRequireTargets: [
'./node_modules/#vue/compiler-core',
'./node_modules/#vue/compiler-dom',
'./node_modules/#vue/compiler-ssr',
'./node_modules/vue/server-renderer',
'./node_modules/vue'
]
},
},
alias: {
'#vue/compiler-core': '#vue/compiler-core',
'#vue/compiler-dom': '#vue/compiler-dom',
'#vue/compiler-ssr': '#vue/compiler-ssr',
'vue/server-renderer': 'vue/server-renderer',
'estree-walker': 'estree-walker',
'#babel/parser': '#babel/parser'
},
And then in the plugins/RenderVueString.js
import { h, compile } from 'vue';
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.component('RenderVueString', {
props: ['html'],
render() {
return h(compile(this.html), {$emit: this.$emit});
}
})
})
Allows this on the a template:
<template>
<RenderVueString :html="vueHTML" #runFunction="testFunction()" />
</template>
<script>
export default {
data() {
return: {
vueHTML: `<div>This is some vue HTML <a #click="$emit('runFunction')">Run Function</a></div>`,
}
},
methods: {
testFunction() {
console.log('test function ran');
}
}
}
</script>
I could also pass in variables as props into the RenderVueString component if needed.
This type of functionality is very useful if you're trying to allow some advanced coding from items being pulled from a database / CMS.

Writing a custom directive on Vuejs 3, composition API in order to detect outside click

my first time trying directive with vue js3.
My goal: To detect a click outside the component with the directive and Vuejs 3, composition API.
My expected result: To change a Boolean value in each click outside the component 'CustomeMultiSelect.vue'.
My actual result: In any click, the Boolean value is changed.
Here is my 'App.vue'
<script lang="ts">
import CustomeMultiSelect from "./components/CustomeMultiSelect.vue";
import { ref } from "vue";
export default {
components: {
CustomeMultiSelect,
},
directives: {
"click-outside": {
mounted: function (el, binding) {
console.log("in directive");
const ourClickEventHandler = (event) => {
if (!el.contains(event.target) && el !== event.target) {
binding.value(event);
}
};
el.__vueClickEventHandler__ = ourClickEventHandler;
document.addEventListener("click", ourClickEventHandler);
},
unmounted: function (el) {
document.removeEventListener("click", el.__vueClickEventHandler__);
},
},
},
setup() {
let bool = ref(true);
function test() {
bool.value = !bool.value;
console.log(bool.value);
}
return {
test,
};
},
};
</script>
<template>
<div v-click-outside="test">
<CustomeMultiSelect/>
</div>
</template>
I defined directive that on 'mounted' Hook will attached event 'click' to each element in the screen -> 'v-click-outside' on <'CustomeMultiSelect.vue'/>
Component 'CustomeMultiSelect.vue' is a child component of 'App.vue'.
('CustomeMultiSelect.vue' has 3 childs).

CodeMirror on Vue3 has a problem when setValue is kicked

I'm trying to use CodeMirror on Vue3 and the problem occurs when I call doc.setValue().
The Problem is following:
Cursor position is broken when doc.setValue() is called
CodeMirror throws an exception when continuing editing
The exception is here.
Uncaught TypeError: Cannot read property 'height' of undefined
at lineLength (codemirror.js:1653)
at codemirror.js:5459
at LeafChunk.iterN (codemirror.js:5623)
at Doc.iterN (codemirror.js:5725)
at Doc.iter (codemirror.js:6111)
at makeChangeSingleDocInEditor (codemirror.js:5458)
at makeChangeSingleDoc (codemirror.js:5428)
at makeChangeInner (codemirror.js:5297)
at makeChange (codemirror.js:5288)
at replaceRange (codemirror.js:5502)
How should I solve this?
~~~
Versions are CodeMirror: 5.61.1, Vue.js: 3.0.11
My code is following:
index.html
<div id="app"></div>
<script src="./index.js"></script>
index.js
import { createApp } from 'vue';
import App from './App';
const app = createApp(App);
app.mount('#app');
App.vue
<template>
<div>
<button #click="click">Push Me</button>
<textarea id="codemirror"></textarea>
</div>
</template>
<script>
import CodeMirror from 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
// import codemirror resources
import 'codemirror/addon/mode/overlay.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/gfm/gfm.js';
export default {
data () {
return {
cm: null
}
},
mounted () {
this.cm = CodeMirror.fromTextArea(document.getElementById('codemirror'), {
mode: 'gfm',
lineNumbers: true,
});
},
methods: {
click (event) {
this.cm.getDoc().setValue('foo\nbar');
}
}
}
</script>
Thanks.
UPDATES
First, this problem also occurs when I used replaceRange() with multiline.
Unfortunately, I couldn't find any solution. So I tried to find another way.
My solution is recreating Codemirror instance with a textarea that has new content.
It works well.
// Remove old editor
this.cm.toTextArea();
// Get textarea
const textarea = document.getElementById('codemirror');
// Set new content
textarea.value = 'foo\nbar';
// Create new editor
this.cm = CodeMirror.fromTextArea(textarea, { /** options */ });
I found a method, you can use toRaw to get the original Object from Proxy,and this method can be also used in monaco-editor
import { toRaw } from 'vue'
import CodeMirror from 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
// import codemirror resources
import 'codemirror/addon/mode/overlay.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/gfm/gfm.js';
export default {
data () {
return {
cm: null
}
},
mounted () {
this.cm = CodeMirror.fromTextArea(document.getElementById('codemirror'), {
mode: 'gfm',
lineNumbers: true,
});
},
methods: {
click (event) {
toRaw(this.cm).setValue('foo\nbar');
}
}
}
Another way,you don't have to define cm in data, just use this.cm
data () {
return {
//cm: null
}
},

Use injected variables (nuxt.firebase) in composition api

I'm using the composi api in my Vue project and the nuxt.js firebase module, I would like to call variables injected into modules, such as $ fireAuth, but I didn't find a solution.
Below is a small code training of how I would like it to work:
export default createComponent({
setup(_props, { root }) {
root.$fireAuth= ..
}
}
// or
export default createComponent({
setup(_props, { root , $fireAuth }) {
}
}
I have a work-around for this and it works! (For now.)
Create a dummy component (ex. AppFirebase.vue)
<template></template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
created() {
this.$emit("init", this.$fire);
},
});
</script>
Accessing NuxtFireInstance (ex. SomeComponent.vue)
<template>
<fire #init="initFB"></fire>
</template>
<script lang="ts">
import {
defineComponent,
reactive,
} from "#nuxtjs/composition-api";
import fire from "#/components/AppFirebase.vue";
export default defineComponent({
components: { fire },
setup() {
let _fire: any = reactive({});
const initFB = (fire: any) => {
_fire = fire;
};
const signout = async () => {
try {
await _fire.auth.signOut().then(() => {
// do something
});
} catch (error) {
console.log(error);
}
};
return {
initFB,
_fire,
signout,
};
},
});
</script>
Rickroll if you got it working!

Resources