How to hide content when clicked checkbox from different components in vuejs? - javascript

//inputtwo.vue
<template>
<div><input type="checkbox" v-model="checked" />one</div>
</template>
<script>
export default {
name: "inputtwo",
components: {},
data() {
return {};
},
};
</script>
//maincontent.vue
<template>
<div>
<div class="container" id="app-container" v-if="!checked">
<p>Text is visible</p>
</div>
<common />
</div>
</template>
<script>
export default {
name: "maincontent",
components: {},
data() {
return {
checked: false,
};
},
methods: {
hidecont() {
this.checked = !this.checked;
},
},
};
</script>
//inputone.vue
<template>
<div><input type="checkbox" v-model="checked" />one</div>
</template>
<script>
export default {
name: "inputone",
components: {},
data() {
return {};
},
};
</script>
How to hide content of checkbox from different components in Vuejs
I have three components called inputone(contains checkbox with v-model),inputtwo (contains checkbox with v-model),maincontent.(having some content and logic), So when user click on checkboxes from either one checckbox(one,two). i schould hide the content.
Codesanfdbox link https://codesandbox.io/s/crimson-fog-wx9uo?file=/src/components/maincontent/maincontent.vue
reference code:- https://codepen.io/dhanunjayt/pen/mdBeVMK

You are actually not syncing the data between components. The main content checked never changes. You have to communicate data between parent and child components or this won't work. And try using reusable components like instead of creating inputone and inputtwo for same checkbox create a generic checkbox component and pass props to it. It is a good practice and keeps the codebase more manageable in the longer run.
App.vue
<template>
<div id="app">
<maincontent :showContent="showContent" />
<inputcheckbox text="one" v-model="checkedOne" />
<inputcheckbox text="two" v-model="checkedTwo" />
</div>
</template>
<script>
import maincontent from "./components/maincontent/maincontent.vue";
import inputcheckbox from "./components/a/inputcheckbox.vue";
export default {
name: "App",
components: {
maincontent,
inputcheckbox,
},
computed: {
showContent() {
return !(this.checkedOne || this.checkedTwo);
},
},
data() {
return {
checkedOne: false,
checkedTwo: false,
};
},
};
</script>
checkbox component:
<template>
<div>
<input
type="checkbox"
:checked="value"
#change="$emit('input', $event.target.checked)"
/>
{{ text }}
</div>
</template>
<script>
export default {
name: "inputcheckbox",
props: ["value", "text"],
};
</script>
Content:
<template>
<div class="container" id="app-container" v-if="showContent">
<p>Text is visible</p>
</div>
</template>
<script>
export default {
name: "maincontent",
props: ["showContent"]
}
</script>
https://codesandbox.io/embed/confident-buck-kith5?fontsize=14&hidenavigation=1&theme=dark
Hope this helps and you can learn about passing data between parent and child components in Vue documentation: https://v2.vuejs.org/v2/guide/components.html

Consider using Vuex to store and maintain the state of the checkbox. If you're not familiar with Vuex, it's a reactive datastore. The information in the datastore is accessible across your entire application.

Related

VueJS warning when using dynamic components and custom-events

So, I get this warning:
" Extraneous non-emits event listeners (addNewResource) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option."
And I don't understand why. I am using dynamic components with 2 custom events. I've tried adding both of the emitted events to the emits object of both components.
App.vue
<template>
<AppHeader />
<NavigationBar #select-component="selectComponent" />
<keep-alive>
<component
:is="selectedComponent"
v-bind="componentProps"
#delete-resource="deleteResource"
#add-new-resource="addNewResource"
></component>
</keep-alive>
</template>
<script>
import AppHeader from "./components/SingleFile/AppHeader.vue";
import NavigationBar from "./components/NavigationBar.vue";
import LearningResources from "./components/LearningResources.vue";
import AddResource from "./components/AddResource.vue";
export default {
components: {
AppHeader,
NavigationBar,
LearningResources,
AddResource,
},
data() {
return {
selectedComponent: "learning-resources",
learningResources: [
{
name: "Official Guide",
description: "The official Vue.js documentation",
link: "https://v3.vuejs.org",
},
{
name: "Google",
description: "Learn to google...",
link: "https://www.google.com/",
},
],
};
},
methods: {
selectComponent(component) {
this.selectedComponent = component;
},
deleteResource(name) {
this.learningResources = this.learningResources.filter(
(resource) => resource.name !== name
);
},
addNewResource(newResourceObject) {
const newResource = {
name: newResourceObject.title,
description: newResourceObject.description,
link: newResourceObject.link,
};
this.learningResources.push(newResource);
},
},
computed: {
componentProps() {
if (this.selectedComponent === "learning-resources") {
return {
learningResources: this.learningResources,
};
}
return null;
},
},
};
</script>
AddResource.vue
<template>
<base-card>
<template #default>
<form #submit.prevent>
<div>
<label for="title">Title</label>
<input type="text" v-model="newResource.title" />
</div>
<br />
<div>
<label for="description">Description</label>
<textarea rows="3" v-model="newResource.description" />
</div>
<br />
<div>
<label for="link">Link</label>
<input type="text" v-model="newResource.link" />
</div>
<button #click="$emit('add-new-resource', newResource)">
Add Resource
</button>
</form>
</template>
</base-card>
</template>
<script>
import BaseCard from "./Base/BaseCard.vue";
export default {
components: {
BaseCard,
},
emits: ["add-new-resource"],
data() {
return {
newResource: {
title: "",
description: "",
link: "",
},
};
},
};
</script>
LearningResources.vue
<template>
<base-card v-for="resource in learningResources" :key="resource.name">
<template #header>
<h3>{{ resource.name }}</h3>
<button #click="$emit('delete-resource', resource.name)">Delete</button>
</template>
<template #default>
<p>{{ resource.description }}</p>
<p><a :href="resource.link">View Resource</a></p>
</template>
</base-card>
</template>
<script>
import BaseCard from "./Base/BaseCard.vue";
export default {
components: {
BaseCard,
},
props: {
learningResources: Array,
},
emits: ["deleteResource"],
};
</script>
Seems to be because <component> is being used for two separate components, neither of which emit the same event as the other.
One thing you can try is disabling each components' attribute inheritance:
export default {
...
inheritAttrs: false
...
}
If this doesn't suit your needs, you could refactor the logic to handle both emitted events, i.e. rename the events to a shared name like "addOrDeleteResource", then determine which event is being emitted in App.vue and handle it accordingly.

How to store a value from another component's data?

I have two components, is there a way to store value from another component's data?
Here is Create.vue
<template>
<div id="main">
<Editor />
//some codes here
</div>
</template>
<script>
import Editor from './_Create_Editor.vue'
export default {
components: { Editor },
data: () => ({
text: ''
}),
}
</script>
And here is the _Create_Editor.vue.
<template>
//sample input for demonstration purposes
<input type="text" class="form-control" v-model="text"/>
</template>
The code above returns an error:
Property or method "text" is not defined on the instance but referenced during render
I want everytime I type the data: text from Create.vue has the value of it.
How can I possibly make this? Please help.
You can do this by using $emit.
Create.vue
<template>
<div id="main">
<Editor
#edit={onChangeText}
/>
//some codes here
</div>
</template>
<script>
import Editor from './_Create_Editor.vue'
export default {
components: { Editor },
data: () => ({
text: ''
}),
methods: {
onChangeText: function (value) {
this.text = value
}
}
}
</script>
_Create_Editor.vue
<template>
//sample input for demonstration purposes
<input
type="text"
class="form-control"
#change="onChange"
/>
</template>
<script>
export default {
methods: {
onChange: function (event) {
this.$emit('edit', event.target.value)
}
}
}
</script>

How do I pass data to a component using Props in Vue2?

I have created a .Vue file to feature information on a cafe (Cafe Details Page). However, I would like to take parts of this details page and make it its own component, in order to manage any template updates more efficiently.
Therefore, I have created a Component (CafeHeader.vue) inside a components folder. I am trying to pass down the data from my array (Which is being used on my Cafe Details page) to this component using Props. However, I can't seem to get it to work.
The template for my Cafe Details Page is as below:
<template>
<div>
<div v-for="cafe in activeCafe">
<CafeHeader v-bind:cafes="cafes" />
<div class="content">
<p>{{ cafe.cafeDescription }}</p>
</div>
</div>
</div>
</template>
<script>
import CafeHeader from "./../../components/CafeHeader";
import cafes from "./../../data/cafes"; // THIS IS THE ARRAY
export default {
data() {
return {
cafes: cafes
};
},
components: {
CafeHeader,
},
computed: {
activeCafe: function() {
var activeCards = [];
var cafeTitle = 'Apollo Cafe';
this.cafes.forEach(function(cafe) {
if(cafe.cafeName == cafeTitle){
activeCards.push(cafe);
}
});
return activeCards;
}
}
};
</script>
Then, in a components folder I have a component called CafeHeader where I am wanting to use the data from the array which is previously imported to the Cafe Details page;
<template>
<div>
<div v-for="cafe in cafes">
<h1>Visit: {{cafe.cafeName}} </h1>
</div>
</div>
</template>
<script>
export default {
name: "test",
props: {
cafes: {
type: Array,
required: true
}
},
data() {
return {
isActive: false,
active: false
};
},
methods: {}
};
</script>
If in the CafeHeader component I have cafe in cafes, it does render data from the cafes.js However, it is every cafe in the list and I want just a single cafe.
<template>
<div>
<div v-for="cafe in cafes">
<h1>Visit: {{cafe.cafeName}} </h1>
</div>
</div>
</template>
The component also needed activeCafes on the v-for
<template>
<div>
<div v-for="cafe in activeCafes">
<h1>Visit: {{cafe.cafeName}} </h1>
</div>
</div>
</template>

Vue Js should I be using Vuex for this?

I am working through mini workshops for learning Vuejs. I have 2 components; PersonCard and ColorPick and a set of data. I can create a new person card for each person inside the person data, and in each person card I can create a colour picker (radio buttons) but I am stumped how to get the 'Picked Color' back to where the Person Card is rendered to be used as a style binding? I have been trying to use $emit but it doesn't work. Any advice would be welcomed.
I am pretty sure that I cannot grab and set updatedPlayers.color because updatedPlayers is an array that is iterated over in the template, but how do I target the specific 'player' in updatedPlayers to update their color based on the $emit?
App.vue
<template>
<div>
<PersonCard :players="players"></PersonCard>
</div>
</template>
<script>
import PersonCard from './components/PersonCard.vue'
export default {
components: {
PersonCard
},
data () {
return {
players: [
{
id: 1,
name: "Daniel",
age: 33,
color:"red"
},
{
id: 2,
name: "Sam",
age: 21,
color: "green"
}
]
}
}
};
</script>
<style scoped>
</style>
PersonCard.vue
<template>
<div>
<li v-for="player in updatedPlayers" :key="player.id">
<h4 :style="{backgroundColor: player.color}">{{player.name}}</h4>
<ColorPick #colorChosen="newColor"></ColorPick>
</li>
</div>
</template>
<script>
import ColorPick from './ColorPick.vue'
export default {
data () {
return {
pickedColor: '',
updatedPlayers : this.Players
}
},
props: ['Players'],
components: {
ColorPick
},
methods: {
newColor (newColor) {
this.updatedPlayers.color = newColor;
}
}
};
</script>
<style scoped>
li {
list-style: none !important;
}
</style>
ColorPick.vue
<template>
<div>
<form action>
<input type="radio" name="nameColor" value="yellow" v-model="pickedColor" #change="colorChosen" /> Yellow
<br />
<input type="radio" name="nameColor" value="red" v-model="pickedColor" #change="colorChosen" /> Red
<br />
<input type="radio" name="nameColor" value="blue" v-model="pickedColor" #change="colorChosen" /> Blue
</form>
</div>
</template>
<script>
export default {
data() {
return {
pickedColor: "",
};
},
methods: {
colorChosen(pickedColor) {
this.$emit ('newColor', pickedColor);
}
}
};
</script>
<style>
</style>
To be honest, if you have two components in a hierarchy then this doesn’t really need Vuex. You just need to think about your components and how they interact.
If a PlayerCard component has a child ColorPicker component, then you’re right that the ColorPicker component should emit an event with the picked colour. The PlayerCard component can just listen on that event and set whatever binding it needs to:
<!-- /components/PlayerCard.vue -->
<template>
<div v-bind:style="{ 'background-color': this.backgroundColor }">
<color-picker v-bind:value="backgroundColor" v-on:input="updateBackgroundColor" />
</div>
</template>
<script>
export default {
components: {
ColorPicker
},
data() {
return {
backgroundColor: '#000' // default
};
},
methods: {
updateBackgroundColor(event) {
this.backgroundColor = event.target.value;
}
}
}
</script>
<!-- /components/ColorPicker.vue -->
<template>
<div>
<input type="color" v-on:input="onInput" v-bind:value="value" />
</div>
</template>
<script>
export default {
methods: {
onInput(event) {
this.$emit('input', event);
}
},
props: {
value: {
required: true,
type: String
}
}
}
</script>
Here we have two components. When the input in the ColorPicker changes its value, it passes the input event up to the PlayerCard component, that then sets the background colour in response.
The ColorPicker component also remains “dumb”, in that it doesn’t know anything about the components it’s being used in—it literally just allows a user to pick a colour. The parent component listens on the input event and does something in response. So this makes the ColorPicker component re-usable for picking other colours you may need to for your PlayerCard component, i.e. text colour.
There’s nothing here really that Vuex will solve that properly-written Vue components can’t accomplish. Vuex will just make it easier to code around problems, rather than solve any. But Vuex does have a place in larger applications.
I noticed that your event listener is #colorChosen (in your PersonCard.vue), but you are emiting "newColor", change that to #newColor (in your PersonCard.vue). See if that helps.
<ColorPick #newColor="newColor"></ColorPick>
And yes Vuex can make passing bits of state from component to component a breeze. As your app grows and expands, it can get a little tricky to keep track of all your emits.

Pass range input value on change in Vue 2

In Vue 2: I have an App component, which has a Slider component:
App.vue
<template>
<div>
<Slider :foo="store.foo"></Slider>
</div>
</template>
<script>
import store from './components/store.js';
import Slider from './components/Slider.vue';
export default {
name: 'app',
components: { Slider },
data() {
return {
store: store
}
},
methods: {
changeFoo(foo) {
console.log('change!', foo);
},
},
}
</script>
Slider.vue
<template>
<div>
<input type="range" min="1" max="100" step="1" #change="changeFoo" />
</div>
</template>
<script>
export default {
props: ['foo'],
methods: {
changeFoo() {
this.$emit('changeFoo', foo);
}
}
}
</script>
The problem is that the value of the slider is not being passed in the emit statement in Slider.vue. I can see why - but I'm not sure how to fix it. I tried doing:
v-model="foo"
in the input element, but Vue gives a warning that I'm not allowed to mutate props.
Instead of using prop create a new data variable for slider and pass this variable in the emit, like this:
<template>
<div>
<input v-model="sliderVal" type="range" min="1" max="100" step="1" #change="changeFoo" />
</div>
</template>
<script>
export default {
props: ['foo'],
data: function() {
return {
sliderVal: ""
}
}
methods: {
changeFoo() {
this.$emit('changeFoo', this.sliderVal);
}
}
}
</script>
Also in App.vue you will have to listed to this emitted event like this:
<template>
<div>
<Slider :foo="store.foo" #change-foo="changeFoo"></Slider>
</div>
</template>

Categories

Resources