How to pass input value data to root element in Vue? - javascript

I want to achieve data transfer from component to root element in Vue.
I am trying to access the 'title' value from root element with method.
When the code is executed, the console throws me 'undefined' instead of 'title' value.
Is it even possible with my idea?
var app = Vue.createApp({
props: ['handle'],
components: ['custom-form'],
methods: {
showData: function() {
console.log (this.handle)
return this.handle
}
},
created() {
console.log (this.showData())
}
})
app.component ('custom-form', {
props: ['value'],
template: `
<h1>{{title}}</h1>
<input type="text" v-model="inputValue" />
`,
data(){
return {
title: 'login'
}
},
computed:{
inputValue:{
get(){ this.title },
set(v){ this.$emit('update:inputValue',v) }
}
},
methods: {
handle(){
return this.inputValue
}
}
})
app.mount('#app')

Related

Issue when trying to interact with an API in Vuejs?

datalist.js
import axios from "axios";
export const datalist = () => {
return axios.get("myapiurl/name...").then((response) => response);
};
HelloWorld.vue
<template>
<div>
<div v-for="item in items" :key="item.DttID">
<router-link
:to="{
name: 'UserWithID',
params: { id: item.DepaD },
query: { DepaD: item.DepaID },
}"
>
<div class="bt-color">{{ item.DepaName }}</div>
</router-link>
</div>
<br /><br /><br />
<User />
</div>
</template>
<script>
import User from "./User.vue";
import { datalist } from "./datalist";
export default {
name: "HelloWorld",
components: {
User,
},
data() {
return {
items: datalist,
};
},
mounted() {
datalist().then((r) => {
this.items = r.data;
});
},
};
</script>
User.vue
<template>
<div>
<div v-for="(item, key) in user" :key="key">
{{ item.Accv }}
</div>
</div>
</template>
<script>
import { datalist } from "./datalist";
export default {
name: "User",
data() {
return {
lists: datalist,
};
},
computed: {
user: function () {
return this.lists.filter((item) => {
if (item.DepaD === this.$route.params.id) {
return item;
}
});
},
},
};
</script>
Error with the code is,
[Vue warn]: Error in render: "TypeError: this.lists.filter is not a function"
TypeError: this.lists.filter is not a function
The above error i am getting in User.vue component in the line number '20'
From the api which is in, datalist.js file, i think i am not fetching data correctly. or in the list filter there is problem in User.vue?
Try to change the following
HelloWorld.vue
data() {
return {
items: [],
};
},
mounted() {
datalist().then((r) => {
this.items = r.data;
});
},
User.vue
data() {
return {
lists: []
};
},
mounted() {
datalist().then((r) => {
this.lists = r.data;
});
},
At least this suppress the error, but i cant tell more based on your snippet since there are network issues :)
Since your datalist function returns a Promise, you need to wait for it to complete. To do this, simply modify your component code as follows:
import { datalist } from "./datalist";
export default {
name: "User",
data() {
return {
// empty array on initialization
lists: [],
};
},
computed: {
user: function() {
return this.lists.filter((item) => {
if (item.DeploymentID === this.$route.params.id) {
return item;
}
});
},
},
// asynchronous function - because internally we are waiting for datalist() to complete
async-mounted() {
this.users = await datalist() // or datalist().then(res => this.users = res) - then async is not needed
}
};
now there will be no errors when initializing the component, since initially lists is an empty array but after executing the request it will turn into what you need.
You may define any functions and import them, but they wont affect until you call them, in this case we have datalist function imported in both HelloWorld and User component, but it did not been called in User component. so your code:
data() {
return {
lists: datalist,
};
},
cause lists to be equal to datalist that is a function, no an array! where .filter() should be used after an array, not a function! that is the reason of error.
thus you should call function datalist and put it's response in lists instead of putting datalist itself in lists
Extra:
it is better to call axios inside the component, in mounted, created or ...
it is not good idea to call an axios command twice, can call it in HelloWorl component and pass it to User component via props

Try to pass $ref data to prop data of component

Hello I have a component Carousel, and I have method:
carousel () {
return this.$refs.carousel
}
When I try pass to prop of other component, I get undefined in prop data, why?
<Dots :carousel="carousel()" />
In child component I have:
export default {
name: 'Dots',
props: ['carousel']
}
In mounted when I try call console.log(this.carousel), I get undifined. But I need get a component data of Carousel. How I can do it?
Sandbox: https://codesandbox.io/s/flamboyant-monad-5bhjz?file=/src/components/Test.vue
You can set a function in carousel to return the data you want to send to dots. Then, in the parent component, set its return value to an attribute in data which will be passed as a prop:
const dotsComponent = Vue.component('dotsComponent', {
template: '#dotsComponent',
props: ['carousel']
});
const carouselComponent = Vue.component('carouselComponent', {
template: '#carouselComponent',
data() { return { id:1 } },
methods: {
getData() { return { id: this.id } }
}
});
new Vue({
el: "#app",
components: { dotsComponent, carouselComponent },
data() { return { carousel:null } },
mounted() { this.carousel = this.$refs.carousel.getData(); }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div><carousel-component ref="carousel"/></div>
<div><dots-component :carousel="carousel"/></div>
</div>
<template id="dotsComponent"><p>Dots: {{carousel}}</p></template>
<template id="carouselComponent"><p>Carousel</p></template>
You could pass the ref directly without using a method any other property :
<Dots :carousel="$refs.carousel" />

Make a reactive component with vuejs

I need a Vue component to show some HTML content in v-data-table from Vuetify. I have seen this post Vue 2 contentEditable with v-model, and I created a similar code shown below.
My problem is the component is not reactive. When I click the "Test button", no content is updated in HtmlTextArea.
<template>
<div>
<v-btn #click="doTest()">Test Button</v-btn>
<HtmlTextArea
v-model="content"
style="max-height:50px;overflow-y: scroll;"
></HtmlTextArea>
</div>
<template>
export default {
name: "ModelosAtestados",
components: { HtmlTextArea },
data: () => ({
content: "",
}),
methods: {
doTest() {
this.content = "kjsadlkjkasfdkjdsjkl";
},
},
};
//component
<template>
<div ref="editable" contenteditable="false" v-on="listeners"></div>
</template>
<script>
export default {
name: "HtmlTextArea",
props: {
value: {
type: String,
default: "",
},
},
computed: {
listeners() {
return { ...this.$listeners, input: this.onInput };
},
},
mounted() {
this.$refs.editable.innerHTML = this.value;
},
methods: {
onInput(e) {
this.$emit("input", e.target.innerHTML);
},
},
};
</script>
This occurs because HtmlTextArea sets the div contents to its value prop only in the mounted lifecycle hook, which is not reactive.
The fix is to setup a watcher on value, so that the div contents are updated to match whenever a change occurs:
// HtmlTextArea.vue
export default {
watch: {
value: {
handler(value) {
this.$refs.editable.innerHTML = value;
}
}
}
}
demo
In the #click event binder, you have to pass a function. You passed the result of an executed function.
To make it work: #click="doTest" or #click="() => doTest()".
How to debug such problems:
Display the value you want to update on your template to check if its updated: {{content}}
Use the vue devtool extension to check the current state of your components

Computed property was assigned to but it has no setter - a toggle component

I am creating a simple switch toggle component in Vue where it has a v-model and #updated. But I can't seem to change the model when the user toggles the switch. First I was getting the error to avoid mutating a prop directly. But now I am getting another error.
[Vue warn]: Computed property "isSwitchOn" was assigned to but it has
no setter.
The component is meant to be used like this
<iswitch v-model="switchGender" #updated="handleUpdatedGender" />
Here is the component itself
export default {
template: `
<span
#click="toggleSwitch"
:class="{ active: isSwitchOn }">
<span class="toggle-knob"></span>
</span>
`,
props: ['value'],
methods:
{
toggleSwitch()
{
this.isSwitchOn = !this.isSwitchOn
this.$emit('input', this.isSwitchOn)
this.$emit('updated')
}
},
computed:
{
isSwitchOn()
{
return this.value
}
},
};
The error is triggered by this statement: this.isSwitchOn = !this.isSwitchOn. You are trying to assign a value to a computed property but you didn't provide a setter.
You need to define your computed property as follow for it to work as a getter and a setter:
computed:
{
isSwitchOn:
{
get()
{
return this.value
},
set(value)
{
this.value = value
}
}
}
Also, it is not advised to mutate a prop directly. What you could do is to add a new data property and sync it with the value prop using a watcher.
I think something like this will work:
props: ['value'],
data()
{
return {
val: null
}
},
computed:
{
isSwitchOn:
{
get()
{
return this.val
},
set(value)
{
this.val = value
}
}
},
watch: {
value(newVal) {
this.val = newVal
}
}
Computed properties are by default getter-only, but you can also provide a setter when you need it. Check official documentation
computed:
{
isSwitchOn() {
get() { return this.value }
set(val) { this.value = val }
}
}
Alternative way:
In your parent component:
<iswitch ref="switcher" #input="methodForInput" v-model="switchGender" #updated="handleUpdatedGender" />
methods: {
methodForInput(event){
this.$refs.switcher.isSwitchOn = event;
}
}
In your child component:
export default {
template: `
<span
#click="toggleSwitch"
:class="{ active: isSwitchOn }">
<span class="toggle-knob"></span>
</span>
`,
data() {
return {
isSwitchOn: false
};
},
methods:
{
toggleSwitch()
{
this.isSwitchOn = !this.isSwitchOn
this.$emit('input', this.isSwitchOn)
this.$emit('updated')
}
}
};
Updates 3: Sorry, didn't include parent component at first.

Vue.js pass function as prop and make child call it with data

I have a posts list component and a post component.
I pass a method to call from the posts list to the post component, so when a button is click it will be called.
But I want to pass the post id when this function is clicked
Code:
let PostsFeed = Vue.extend({
data: function () {
return {
posts: [....]
}
},
template: `
<div>
<post v-for="post in posts" :clicked="clicked" />
</div>
`,
methods: {
clicked: function(id) {
alert(id);
}
}
}
let Post = Vue.extend({
props: ['clicked'],
data: function () {
return {}
},
template: `
<div>
<button #click="clicked" />
</div>
`
}
as you can see in Post component you have a click that runs a method he got from a prop, I want to add a variable to that method.
How do you do that?
Normally, the click event handler will receive the event as its first argument, but you can use bind to tell the function what to use for its this and first argument(s):
:clicked="clicked.bind(null, post)
Updated answer: However, it might be more straightforward (and it is more Vue-standard) to have the child emit an event and have the parent handle it.
let Post = Vue.extend({
template: `
<div>
<button #click="clicked">Click me</button>
</div>
`,
methods: {
clicked() {
this.$emit('clicked');
}
}
});
let PostsFeed = Vue.extend({
data: function() {
return {
posts: [1, 2, 3]
}
},
template: `
<div>
<post v-for="post in posts" #clicked="clicked(post)" />
</div>
`,
methods: {
clicked(id) {
alert(id);
}
},
components: {
post: Post
}
});
new Vue({
el: 'body',
components: {
'post-feed': PostsFeed
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<post-feed></post-feed>
Using Vue 2 and expanding on #Roy J's code above, I created a method in the child component (Post) that calls the prop function and sends back a data object as part of the callback. I also passed in the post as a prop and used its ID value in the callback.
Back in the Posts component (parent), I modified the clicked function by referencing the event and getting the ID property that way.
Check out the working Fiddle here
And this is the code:
let Post = Vue.extend({
props: {
onClicked: Function,
post: Object
},
template: `
<div>
<button #click="clicked">Click me</button>
</div>
`,
methods: {
clicked() {
this.onClicked({
id: this.post.id
});
}
}
});
let PostsFeed = Vue.extend({
data: function() {
return {
posts: [
{id: 1, title: 'Roadtrip', content: 'Awesome content goes here'},
{id: 2, title: 'Cool post', content: 'Awesome content goes here'},
{id: 3, title: 'Motorcycle', content: 'Awesome content goes here'},
]
}
},
template: `
<div>
<post v-for="post in posts" :post="post" :onClicked="clicked" />
</div>
`,
methods: {
clicked(event) {
alert(event.id);
}
},
components: {
post: Post
}
});
new Vue({
el: '#app',
components: {
'post-feed': PostsFeed
}
});
And this is the HTML
<div id="app">
<post-feed></post-feed>
</div>
this is the service:
export const getBuilding = () => {
console.log("service");
return 0;
};
in the parent component:
<Update-Theme :method="parentMethod"/>
import { getBuilding } from "./service";
methods: {
parentMethod() {
console.log("Parent");
getBuilding();
},
}
and in the child component
<v-btn color="green darken-1" text #click="closeDialog()">
props: [ "method"],
methods: {
closeDialog() {
this.method();
//this.$emit("update:dialog", false);
},
}

Categories

Resources