Vue 2 With CKEditor 4: Multiple editors are not binding to the right v-model - vuejs2

I'm m having a problem with CKEditor 4 which I use at my Vue 2. I have two CKEditor in a page which each has their own v-model: question for the first editor and answer for the second editor. Whenever I clicked a button to console both of the value, the value of question will always the same as answer. How can I fix this? Here's my code:
<template>
<div class="hello">
<form #submit.prevent="printData">
<h3>Insert Question</h3>
<ckeditor v-model="question" :config="editorConfig"></ckeditor>
<h3>Insert Answer</h3>
<ckeditor v-model="answer" :config="editorConfig"></ckeditor>
<button type="submit">Console Value</button>
</form>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
editorConfig: {
extraPlugins: 'mathjax',
mathJaxLib: '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-AMS_HTML'
},
answer: null,
question: null
}
},
methods: {
printData() {
console.log("This is question", this.question);
console.log("This is answer", this.answer);
}
},
}
</script>

Related

function not updating vue property

I have this component:
<template>
<div class="hello">
<div>
My prop: {{ myprop }}?
</div>
<div>
<button class="fas fa-lock-open lock" #click="changeText()">Click</button>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'StartPage',
props: {
myprop: {
type: String
}
},
model: {
prop: 'myprop',
event: 'click'
},
methods: {
changeText () {
this.$emit('click', 'sometext')
console.log('this.myprop', this.myprop)
}
}
})
</script>
Im using vue v3. Everytime I click on the button, I still see the text "My prop: ?" in the browser.
And in the console I can see: "this.myprop undefined" every time I click on the button.
What am I doing wrong?
As per my understanding, You are trying to update the prop text on click of button from the child component. If Yes, you can achieve it simply by emitting a new text and updating that in the parent component.
Live Demo :
const ShowPropText = {
template: `<div class="hello">
<div>
My prop: {{ myprop }}
</div>
<div>
<button class="fas fa-lock-open lock" #click="changeText()">Click</button>
</div>
</div>`,
props: ['myprop'],
methods: {
changeText() {
this.$emit('click-event', 'sometext')
}
}
}
const app = Vue.createApp({
components: {
'show-prop-text': ShowPropText
},
data() {
return {
text: 'This is default text'
}
},
methods: {
methodCall(e) {
this.text = e;
}
}
})
app.mount('#app')
<script src="https://cdn.jsdelivr.net/npm/vue#next"></script>
<div id="app">
<show-prop-text :myprop="text" #click-event="methodCall"></show-prop-text>
</div>

How can I emit from component and listen from another one?

I have in Layout.vue to components one TheSidebar second TheHeader, there is a button in TheHeader to open the sidebar in TheSidebarcomponent.
I need to when I click the button in header open the sidebar:
My try:
in TheHeader:
methods: {
openSidebar() {
this.$root.$emit("open-sidebar");
},
},
in TheSidebar
data() {
return {
sidebarOpen: false,
};
},
mounted() {
this.$root.$on("open-sidebar", (this.sidebarOpen = true));
},
I'm using VUE 3 so I got this error in console: TypeError: this.$root.$on is not a function so How can communicate ?
you can use something like tiny emitter it works fine and doesn't care about parent child relationship
var emitter = require('tiny-emitter/instance');
emitter.on('open-sidebar', ({isOpen}) => {
//
});
emitter.emit('open-sidebar', {isOpen : true} );
You can only pass props to a direct child component, and
you can only emit an event to a direct parent. But
you can provide and eject from anywhere to anywhere
Per another answer, provide and eject may be your best bet in Vue 3, but I created a simple example of how to implement with props/events. Built with Vue 2 as I haven't worked with 3 yet, but should be usable in Vue 3 as well.
Parent.vue
<template>
<div class="parent">
<div class="row">
<div class="col-md-6">
<h4>Parent</h4>
<hr>
<child-one #show-child-two-event="handleShowChildTwoEvent" />
<hr>
<child-two v-if="showChildTwo" />
</div>
</div>
</div>
</template>
<script>
import ChildOne from './ChildOne.vue'
import ChildTwo from './ChildTwo.vue'
export default {
components: {
ChildOne,
ChildTwo
},
data() {
return {
showChildTwo: false
}
},
methods: {
handleShowChildTwoEvent() {
this.showChildTwo = true;
}
}
}
</script>
ChildOne.vue
<template>
<div class="child-one">
<h4>Child One</h4>
<button class="btn btn-secondary" #click="showChildTwo">Show Child Two</button>
</div>
</template>
<script>
export default {
methods: {
showChildTwo() {
this.$emit('show-child-two-event');
}
}
}
</script>
ChildTwo.vue
<template>
<div class="child-two">
<h4>Child Two</h4>
</div>
</template>

Issues with data bind in vue.js and events

I am working on a basic notepad app, for now the functionality is simple, create a note, when done click on the note from a list of previous created notes to view its details. I am not able to click on the note and see the details, instead I see the details of the component ShowNote.vue on the bottom of the notepad template, and in order to see the details I have to make the v-if="noteIsOpen to false". I am also not able to see the data from the data bind in ShowNote.vue file. Also when you click on the plus button the details from the note populate the page the button generates when clicked. I will paste screen shots of my code below. Please help me figure this out. I have tried to fix the props, and when I did I was able to see the note details finally.
App.vue
<template>
<div class="body">
<div class="notepad-container h-75 w-75">
<header class="header d-flex justify-content-center align-items-center">
<h4>Light Notepad v1</h4>
</header>
<section class="notepad-content" v-if="editorIsOpen === false">
<note-list
v-for="note in notes"
:key="note.id"
:note="note"
></note-list>
<add-note-button #open-editor="openNewEditor"></add-note-button>
</section>
<section class="notepad-editor" v-if="editorIsOpen === true">
<save-button></save-button>
</section>
<section class="notepad-content" v-if="noteIsOpen === true">
<show-note
:note="notes"
#open-note="readNote"
/>
</section>
<section class="notepad-content" v-if="noteIsOpen === false">
<show-note
:note="notes"
#open-note="openNote"
/>
</section>
</div>
</div>
</template>
<script>
import AddNoteButton from "./components/AddNoteButton.vue";
import NoteList from "./components/NoteList.vue";
import SaveButton from "./components/SaveButton.vue";
import ShowNote from "./components/ShowNote.vue";
export default {
components: {
NoteList,
AddNoteButton,
SaveButton,
ShowNote,
},
data() {
return {
editorIsOpen: false,
noteIsOpen: false,
notes: [
{
id: 1,
title: "1st Note",
body: "This is a note",
date: "10/17/20",
},
{
id: 2,
title: "2nd Note",
body: "This is a note",
date: "11/17/20",
},
],
};
},
methods: {
openNewEditor() {
this.editorIsOpen = !this.editorIsOpen;
},
readNote() {
this.noteIsOpen = !this.noteIsOpen;
},
},
};
</script>
AddNoteButton.vue
<template>
<div class="add-note-container" #click="openEditor">
<b-icon-plus-circle></b-icon-plus-circle>
</div>
</template>
<script>
import {BIconPlusCircle} from 'bootstrap-vue';
export default {
emits: ['open-editor'],
components: {
BIconPlusCircle
},
methods: {
openEditor() {
console.log('hello');
this.$emit('open-editor');
}
}
}
</script>
NoteList.vue
<template>
<div>
<b-list-group>
<b-list-group-item button #click="openNote()"
>{{ note.title }} - {{ note.date }}</b-list-group-item
>
</b-list-group>
</div>
</template>
<script>
export default {
emits: ['open-note'],
props: {
note: {
required: true,
},
},
methods: {
openNote() {
this.$emit('open-note');
console.log("clicked from NoteList");
},
},
};
</script>
ShowNote.vue
<template>
<div>
note details:
Note ID: {{ note.id }}, Date: {{ note.date }},
Title: {{ note.title }}, Body: {{ note.body }}
</div>
</template>
<script>
export default {
name: 'showNote',
props: {
note: {
required: true,
}
},
};
</script>
In your NoteList.vue you are emitting the event "open-note". But this event is never catched in your parent component named App.vue. You have to bind this event in order to get notified when ever you clicked on a note entry. Something like #open-note="openNote".
I figured out how to get the details to show when clicking on the note, for now I created a button in the notepad-content section:
<button class="readNoteButton" #click="readNote">view note one</button>
and changed the section with the show note component to:
<section v-if="readingNote === true" class="">
<show-note
#open-note="openNote"
v-for="note in notes"
:key="note.id"
:note="note"
></show-note>
</section>
issue I have now is figuring out how to get the details to show separately pertaining to each individual button

Getting error: Error: _ctx.openNote is not a function when I attempt to click a note to view

I stared from scratch with my notepad app, found here: Issues with data bind in vue.js and events
The issue was I can not seem to click on the note from NoteList.vue to see the details, there is a disconnect somewhere with my bind, and the event handler doesn't seem to work it is throwing an unhandled error: [Vue warn]: Unhandled error during execution of native event handler at <NoteList key=1 note={id: 1, title: "Note one title", body: "This is note ones body content"} > at
Here is my code:
App.vue
<template>
<div class="body">
<div class="notepad-container h-75 w-75">
<header class="header d-flex justify-content-center align-items-center">
<h4>Light Notepad v1</h4>
</header>
<section class="notepad-content">
<note-list
v-for="note in notes"
:key="note.id"
:note="note"
></note-list>
<!-- <add-note-button></add-note-button> -->
</section>
<section class="notepad-editor">
<!-- <save-button></save-button> -->
</section>
<section class="show-note"
v-if="readingNote" === true">
<show-note
#open-note="readNote"
v-for="note in notes"
:key="note.id"
:note="note"
></show-note>
</section>
</div>
</div>
</template>
<script>
// import AddNoteButton from "./components/AddNoteButton.vue";
import NoteList from "./components/NoteList.vue";
// import SaveButton from "./components/SaveButton.vue";
import ShowNote from "./components/ShowNote.vue";
export default {
components: {
NoteList,
// AddNoteButton,
// SaveButton,
ShowNote
},
data() {
return {
readingNote: false,
notes: [
{
id: 1,
title: "Note one title",
body: "This is note ones body content"
},
{
id: 2,
title: "Note two title",
body: "This is the second notes body content"
}
],
methods: {
readNote() {
this.readingNote = !this.readingNote;
}
}
};
},
};
</script>
NoteList.vue
<template>
<div>
<p #click="openNote">{{ note.title }}</p>
<hr />
</div>
</template>
<script>
export default {
emits: ["open-note"],
props: {
note: {}
},
method: {
openNote() {
this.$emit("open-note");
console.log("note opened!");
}
}
};
</script>
ShowNote.vue
<template>
<div>note details: {{ note.body }}</div>
</template>
<script>
export default {
props: {
note: {}
}
};
</script>
I figured it out, I had method, not methods, I was missing the 's' from methods, now I am able to see the consol.log message, still working on seeing the note detail. One step closer!
Maybe adding one more: I just encountered this when I added Vuex's ...mapActions into computed property in Vue component. ...mapActions belongs to methods.
WRONG:
computed: {
...mapGetters('AppStore', ['navigation', 'isNavigationCollapsed']),
...mapActions('AppStore', ['toggleNavigation'])
}
CORRECT:
computed: {
...mapGetters('AppStore', ['navigation', 'isNavigationCollapsed'])
},
methods: {
...mapActions('AppStore', ['toggleNavigation'])
}

Vue Multiselect: How to send console.log once selection has been made

Using Vue Multiselect, I am trying to send a console.log once I have made a selection. I thought it would work by putting it in the watch but it does not work. Where should it be placed. Please see my component below.
Component
<template>
<div>
<label v-for="topic in topics" class="radio-inline radio-thumbnail" style="background-image: url('http://s3.hubsrv.com/trendsideas.com/profiles/74046767539/photo/3941785781469144249_690x460.jpg')">
<input type="radio" v-model="internalValue" name="topics_radio" :id="topic.id" :value="topic.name">
<span class="white-color lg-text font-regular text-center text-capitalize">{{ topic.name }}</span>
</label>
</div>
</template>
<script>
export default {
props: ['value'],
data () {
return {
internalValue: this.value,
topics: []
}
},
mounted(){
axios.get('/vuetopics').then(response => this.topics = response.data);
},
watch: {
internalValue(v){
this.$emit('input', v);
console.log('topic has been chosen!!!');
}
}
}
</script>
It fires events, so you may catch them.
<multiselect ... #select="doSomething" ...>
Then add your method
...
methods: {
doSomething(selectedOption, id) {
console.log(selectedOption);
}
}
Make sure you implemented vue-multiselect correctly, I don't see the component in your code.