Vue multiple aplication instance does not render data - vuejs3

I have 2 vue3 instance in my application and it is early app. When i try to render data from those 2 instance it give the result [Vue warn]: Property "message" was accessed during render but is not defined on instance from one of my instance.
How i can render data from those instances?
first instance
const { createApp } = Vue
const app = createApp({
el: '#app',
delimiters: ['[[', ']]'],
data () {
return {
message_base: "Halo!",
}
},
})
app.mount('#app')
another instance that give the error result
const navbarapp = createApp({
el: '#navbarapp',
delimiters: ['[[', ']]'],
data () {
return {
message: "Halo, another instance!",
}
},
})
navbarapp.mount('#navbarapp')
simple.html
<html>
...
<body>
<div id="app">
<p>[[ message_base ]]</p>
<div id="navbarapp">
<p> [[ message ]] </p>
</div>
</div>
</body>
</html>

you are nesting navbarapp inside app
change this:
<div id="app">
<p>[[ message_base ]]</p>
<div id="navbarapp">
<p> [[ message ]] </p>
</div>
</div>
to this:
<div id="app">
<p>[[ message_base ]]</p>
</div>
<div id="navbarapp">
<p> [[ message ]] </p>
</div>
here's the DEMO https://jsfiddle.net/duddee/Lu1a8tsd/1/

Related

VUE3.JS - Modal in a loop

I have a GET request in my home.vue component.
This query allows me to get an array of objects.
To display all the objects, I do a v-for loop and everything works fine.
<div class="commentaires" v-for="(com, index) of coms" :key="index">
My concern is that I want to display an image by clicking on it (coms[index].imageUrl), in a modal (popup).
The modal is displayed fine but not with the correct image, i.e. the modal displays the last image obtained in the loop, which is not correct.
Here is the full code of my home.vue component
<template>
<div class="container">
<div class="commentaires" v-for="(com, index) of coms" :key="index">
<modale :imageUrl="com.imageUrl_$this.index" :revele="revele" :toggleModale="toggleModale"></modale>
<img class="photo" :src=""" alt="image du commentaire" #click="toggleModale">
</div>
</div>
</template>
<script>
//import axios from "axios";
import axios from "axios";
import Modale from "./Modale";
export default {
name: 'HoMe',
data() {
return {
coms: [],
revele: false
}
},
components: {
modale: Modale
},
methods: {
toggleModale: function () {
this.revele = !this.revele;
},
</script>
Here is my modale.vue component
<template>
<div class="bloc-modale" v-if="revele">
<div class="overlay" #click="toggleModale"></div>
<div class="modale card">
<div v-on:click="toggleModale" class="btn-modale btn btn-danger">X</div>
<img :src=""" alt="image du commentaire" id="modal">
</div>
</div>
</template>
<script>
export default {
name: "Modale",
props: ["revele", "toggleModale", "imageUrl"],
};
</script>
I've been working on it for 1 week but I can't, so thank you very much for your help...
in your v-for loop you're binding the same revele and toggleModale to every modal. When there is only one revele then any time it's true, all modals will be displayed. It's therefore likely you're actually opening all modals and simply seeing the last one in the stack. You should modify coms so that each item has it's own revele, e.g.:
coms = [
{
imageUrl: 'asdf',
revele: false
},
{
imageUrl: 'zxcv',
revele: false
},
{
imageUrl: 'ghjk',
revele: false
}
];
then inside your v-for:
<modale
:image-url="com.imageUrl"
:revele="com.revele"
#toggle-modale="com.revele = false"
></modale>
<img class="photo" :src=""" alt="image du commentaire" #click="com.revele = true">
passing the same function as a prop to each modal to control the value of revele is also a bad idea. Anytime a prop value needs to be modified in a child component, the child should emit an event telling the parent to modify the value. Notice in my code snippet above I replaced the prop with an event handler that turns the revele value specific to that modal to false. Inside each modal you should fire that event:
modale.vue
<div class="btn-modale btn btn-danger" #click="$emit('toggle-modale')">
X
</div>
This way you don't need any function at all to control the display of the modals.

VueJs calling :key in method

im new to Vue and trying myself in Vue3 and Vuetify.
Similar to this Post im trying to :key or ref a vue-signature-pad in a for loop.
I initialize an empty Array and push a new element, which adds a new signature.
<template>
<div>
<v-container>
<div class="row" v-for="(input, index) in inputs">
<v-container>
<VueSignaturePad
id="signature"
width="100%"
height="300px"
ref="signaturePad"
/>
</v-container>
<div class="buttons">
<button #click="undo">Undo</button>
<button #click="save">Save</button>
</div>
</div>
<v-row justify="center">
<v-btn #click="addRow"
class="ma-2"
color="blue-grey"
icon="mdi-plus-circle-outline"
></v-btn>
</v-row>
</v-container>
</div>
</template>
<script>
export default {
data: () => ({
inputs: [],
}),
methods: {
addRow() {
this.inputs.push({
name: ''
})
},
undo() {
this.$refs.signaturePad.undoSignature();
},
save() {
const { isEmpty, data } = this.$refs.signaturePad.saveSignature();
alert("Open DevTools see the save data.");
console.log(isEmpty);
console.log(data);
}
}
}
</script>
<style scope>
</style>
In the Post i already mentioned, i tried the Solution from Mathieu Janio.
So if i understand everything right, ref is not working and i have to use :key on the div itself.
So i tried his Solution
<template>
<div
class="row"
v-for="(applicants, index) in applicant_details"
:key="index"
>
<div class="col-sm-4">
<div class="form-group">
<p>Signature for {{ applicants.first_name }}</p>
</div>
</div>
<div class="col-sm-4">
<div class="form-group">
<VueSignaturePad ref="" />
<button type="button" #click="undo" class="btn btn-warning">
Undo
</button>
</div>
</div>
</div>
</template>
<script setup>
const applicant_details = [
{ first_name: 'john', signature: '' },
];
const undo = () => {
//will undo the signature
};
const save_signature = () => {
//Save the signature
};
</script>
But now im stuck at calling the right "undo"
The signatepad github example uses ref: at the single signaturepad, which is ok.
but not working at the forloop
How do i call now the right function in "undo" for the solution above?
I tried using "this.$.vnode.key" but this gives me an error.
"Uncaught TypeError: Cannot read properties of undefined (reading '$')".
I figured my first way out.
Heres what i have done.
The Signaturepad got an index on the ref.
<VueSignaturePad
:id="'signaturePad' + index"
width="100%"
height="300px"
:ref="'signaturePad' + index"
:options="options"
/>
The "undo" button is giving it "ref" with
<button #click="undo(`signaturePad${index}`)">Undo</button>
And the undo function itself has the first item in its ref array
undo(ref) {
this.$refs[ref][0].undoSignature();
}
Maybe someone has some more efficient way. Feel free :)

Pushing data to object in different component using POST

TL;DR I want to show submitted posts instantly instead of having to refresh my page
Using the Wordpress REST API I am able to create a new post without any issue. The post is being displayed as soon as the page refreshes, so what I want to do is update the posts object in my Hello.vue file as soon as I create that post so I don't need to refresh to show my newest posts.
I'm not really sure where to start - I've removed all of the experiments I've done so far (importing Post in Create, defining props, pushing to an array, reading about object reactivity on the official Vue documentation, nothing helped).
My App.js consists of the <router> object which shows Hello.vue and a component called Create which displays the Create.vue component. This is how my app currently looks like:
My App.vue file:
<template>
<div id="app">
<section class="posts">
<router-view></router-view>
<create></create>
</section>
</div>
</template>
<script>
import Create from '#/components/Create.vue'
export default {
name: 'app',
components: {
Create
}
}
</script>
<style lang="scss">
#import '../src/assets/styles/style.scss'
</style>
My Hello.vue which displays all the posts:
<template>
<div>
<section class="posts__Feed">
<ul class="posts__List">
<post v-for="item in posts" :item="item" :key="item.id"></post>
</ul>
</section>
</div>
</template>
<script>
var postsUrl = '/wp-json/wp/v2/posts/'
import Post from '#/components/Post.vue'
export default {
name: 'hello',
props: ['responseData'],
components: {
Post
},
data () {
return {
posts: []
}
},
beforeCreate () {
this.$http.get(postsUrl).then((response) => {
this.posts = response.data
})
}
}
</script>
And finally, the Create.vue file which creates the post:
<template>
<div>
<section class="posts__Create">
<form class="posts__CreateForm" v-on:submit="createPosts">
<div class="posts__CreateFormWrapper" v-bind:class="{ 'is-Loading': loading }">
<p>
<input v-model="formInfo.title" type="text" name="title" id="title" placeholder="Name" :disabled="formSent">
</p>
<p>
<textarea v-model="formInfo.content" name="content" id="content" cols="20" rows="10" maxlength="140" placeholder="Message" :disabled="formSent"></textarea>
</p>
<p>
<button :disabled="formSent">Send</button>
</p>
</div>
</form>
</section>
</div>
</template>
<script>
var postsUrl = '/wp-json/wp/v2/posts/'
export default {
name: 'create',
data () {
return {
formInfo: [],
responseData: [],
loading: false,
formSent: false
}
},
methods: {
createPosts (e) {
e.preventDefault()
var info = this.formInfo
// Check if fields are empty
if (this.formInfo.title && this.formInfo.content) {
this.loading = true
// POST
this.$http.post(postsUrl, info).then((response) => {
this.formSent = true
this.loading = false
// get body data
this.responseData = response.data
})
}
} // EOF createPosts
}
}
</script>
Any help would be much appreciated!
I ended up using an event bus as suggested by wotex. First, I've createad a file called bus.js with the below code:
import Vue from 'vue'
export const EventBus = new Vue()
Next, import bus.js to both .vue layouts using:
import { EventBus } from '#/bus.js'
Now emit the event as soon as a new post is created (this is sitting in my axios POST request inside the Create.vue file):
EventBus.$emit('newPost', this.responseData)
And finally, check if the event has happened on the other end (my Hello.vue file):
EventBus.$on('newPost', function (postData) {
Thanks for pointing me in the right direction!

Meteor, Flow Router, and React: How to get FlowRouter.subsReady() function to be reactive in render

I am trying to create a pattern so that all the subscriptions are ready before I load the main page. Similar to Iron Router waitOn.
Take a look at this react component:
export const PageContainer = React.createClass({
render() {
return (
<div id="content-box">
<div className="banner banner-primary">
<div className="page_title pull-left">
{this.props.pageName}
</div>
</div>
<div>
{ FlowRouter.subsReady() ? this.props.page : (
<div> Loading .... </div>
)
}
</div>
</div>
);
}
});
as you can see I am using the FlowRouter.subsReady() helper to render the page or the loading text.
The problem is that this is not reactive. It just renders once but does not update and show the page once the subscription is ready.
How can I get this to be reactive?
What is the best way to use Flow Router's subscription management with React. I have a base layout and want to show loading sign before loading the page main. If I could get this function to be reactive it should work just fine.
UPDATE:
It seems like I have to attach the helper, FlowRouter.subsReady() to the get Meteor data function
export const PageContainer = React.createClass({
mixins: [ ReactMeteorData ],
getMeteorData() {
return {
isLoading: FlowRouter.subsReady()
}
},
render() {
return (
<div id="content-box">
<div className="banner banner-primary">
<div className="page_title pull-left">
{this.props.pageName}
</div>
<i className="fa fa-question-circle help-icon pull-right"></i>
</div>
<div>
{ this.data.isLoading ? this.props.page : (
<div> Loading ... </div>
)
}
</div>
</div>
);
}
});
It seems to be working now. Is this the way to do it?
You accessed the problem in the wrong direction. You don't really need to check the subsReady of FlowRouter when using meteor with react. Just install the mixin ReactMeteorData and set the this.data properly, it will reactively render the Dom. More details here
React render is not reactive. The Dom is only re-rendered when the props or state of the component is changed

getting this npm react component to work with meteor

Using react-typeahead-component
I used browserify to change it from npm into a meteor local package. Nothing is showing on the screen when i run meteor.
OptionTemplate.jsx
module.exports = React.createClass({
render: function() {
return (
<div>
<p>HELLO</p>
</div>
);
},
handleChange: function(event) {
console.log('HELLO');
}
});
main.jsx
var OptionTemplate = require('./OptionTemplate.jsx');
SearchBox = React.createClass({render() {
return (
<div className="col-xs-12 col-lg-12">
<OptionTemplate />
</div>
)}
});
You aren't using components properly. You might want to re-read the react documentation.
In your main.jsx, you are importing the component 'OptionTemplate' but you are trying to render the component 'Typeahead' and passing in 'OptionTemplate' as a prop. The 'Typeahead' component now lives in 'OptionTemplate'. Your main.jsx should like like:
var OptionTemplate = require('./OptionTemplate.jsx');
SearchBox = React.createClass({render() {
return (
<div className="col-xs-12 col-lg-12">
<OptionTemplate />
</div>
)}
});

Resources