I am trying to emit result number of quotes where I add plus one and also push result of the text from textarea to array. The string text is pushed to array successfully but the number of quotes is always zero. I have tried it in one method or separed and I always get same result.
<template>
<div>
<p>Quotes</p>
<b-form-textarea
id="textarea-rows"
v-model="value"
placeholder="Enter something..."
rows="5"
></b-form-textarea>
<b-button variant="primary" #click='plusOneQuote(); addQuote();'>Add Quote</b-button>
</div>
</template>
<script>
import {EventBus} from '../main.js'
export default {
props: ['numberOfQuotes', 'quotes'],
data (){
return {
value: '',
}
},
methods: {
plusOneQuote() {
this.numberOfQuotes++;
EventBus.$emit('addedQuote', this.numberOfQuotes);
},
addQuote() {
this.quotes.push(this.value);
}
}
}
</script>
When I delete the addQuote from click and the method, then numberOfQuotes get bigger by one and I show that in another component by no problem.
Is a good practice to call a single method on the click directive, so instead of:
<b-button variant="primary" #click='plusOneQuote(); addQuote();'>Add Quote</b-button>here
you could implement
<b-button variant="primary" #click='updateQuotes'>Add Quote</b-button> here
And the methods section
methods: {
plusOneQuote() {
this.numberOfQuotes++;
EventBus.$emit('addedQuote', this.numberOfQuotes);
},
addQuote() {
this.quotes.push(this.value);
},
updateQuotes(){
this.plusOneQuote();
this.addQuote();
}
I had this problem before and hope this solution helps.
EDIT:
Sorry, missed some context, since you are trying push to this.quotes which is a prop, you cannot directly mutate it, you should use a getter and a setter to do it or even better, use a v-model. Quoting the docs:
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "visible" (found in component )
Related
CodeSandbox
Reference Video
I'm trying to retrieve a value that was dynamically created and passed to a prop.
After clicking "add card" and clicking on one of the created cards, the goal is to pass the value(prop: randomNum) into a variable(num1).
In the Sandbox, I'm able to get the value of the Id which was also created dynamically.
methods: {
//"emits" or Allows value of the id prop in Array to be reached from parent?
select() {
this.$emit("select", this.id);
}
Above Code from nested /component/card.vue
<card
v-for="cards in cardArray"
:key="cards.id"
:id="cards.id"
:randomNum="cards.randomNum"
#select="selectCard"
:selectedCard="selectedCard"
:playable="cards.playable"
:visable="cards.visable"
></card>
<h1>{{num1}}</h1>
<h1> {{ selectedCard }} </h1>
----------
data() {
return {
cardArray: [],
selectedCard: null,
num1: null,
----------
methods: {
selectCard(cards) {
this.selectedCard = cards;
}
Above code from the main /component/hand.vue
From my understanding, in this case, cards evaluates to this.id?
How can I set num1 to equal cards.randomNum(second item in payload)
The same way that selectedCard evaluates to cards(cards.id)
I've tried variations of "item.Array" and using $emit on this.randomNum the same way it was used to $emit this.Id which doesn't work, how can I properly do this?
//in card hand componenet
select() {
this.$emit("select", this.id);
this.$emit("select", this.randomNum);
}
//in card hand componenet
selectNum(cards.randomNum) {
this.num1 = randomNum;
You can either use two separate events or just pass an object with multiple values.
two events:
select() {
this.$emit("selectId", this.id);
this.$emit("selectNum", this.randomNum);
}
or pass object with multiple values
this.$emit("select", {id:this.id, randomNum:this.randomNum});
This issue hasn't been touched in a while but i'm running into something confusing on my end when using a computed property for a textarea value.
I have a textarea where you give input text and on input it updates the input text in vuex:
<textarea
ref="inputText"
:value="getInputText"
#input="setInputText"
class="textarea"
placeholder="Your message goes in here"
></textarea>
On the click of a button to translate the text I call a handleInput method.
handleInput() {
this.$store.dispatch("translateEnglishToRussian");
},
In my store I have my translateEnglishToRussian action:
translateEnglishToRussian({ commit }) {
const TRANSLATE_API = "https://XXXXXXXX.us-east-1.amazonaws.com/prod/YYYY/";
const data = JSON.stringify({ english: this.state.inputText });
this.$axios
.$post(TRANSLATE_API, data)
.then(data => {
commit("setOutputText", data.translatedText);
commit("setMP3Track", data.mp3Path);
})
.catch(err => {
console.log(err);
});
}
I see it call setOutputText mutation with the payload of translated text, in my vue dev tools I see the correct state with the translated text. However, my second text area that's being used purely to display the translated text never updates!
Output textarea:
<textarea
disabled
ref="outputText"
:value="getOutputText"
class="textarea"
></textarea>
Its value is bound to a computed property called getOutputText:
getOutputText() {
return this.$store.state.outputText;
}
What am i doing wrong here! Any advice is appreciated. I thought this should be fine since i'm using commit in my vuex action in a synchronous way (inside the then() block).
Edit: I have the same result if I also try using v-model. The initial output text from vuex state is rendered there on page load. When I translate, I see the update in Vue Dev Tools correctly, but the text in the text area never re-renders.
Edit #2: Here is my setOutputText mutation:
setOutputText(state, payload) {
console.log(`state - set output - ${payload}`);
state.outputText = payload;
},
After looking at the vue docs for Multiline text, you should replace :value="getOutputText" with v-model="getOutputText".
Because it's computed property, to use it in v-model you need to add get and set to your computed property
<textarea
disabled
ref="outputText"
v-model="getOutputText"
class="textarea"
></textarea>
EDIT: Per #Stephen Tetreault comment, v-model didn't work for him, but :value did solve the problem at the end.
computed: {
getOutputText: {
// getter
get: function () {
return this.$store.state.outputText;
},
// setter
set: function (newValue) {
// there is no need to set anything here
}
}
}
I'm writing a function to update a custom checkbox when clicked (and I don't want to use native checkbox for some reasons).
The code for checkbox is
<div class="tick-box" :class="{ tick: isTicked }" #click="() => isTicked = !isTicked"></div>
which works find.
However, there are so many checkboxes, so I use object to keep track for each item. It looks like this
<!-- (inside v-for) -->
<div class="tick-box" :class="{ tick: isTicked['lyr'+layer.lyr_id] }" #click="() => {
isTicked['lyr'+layer.lyr_id] = !isTicked['lyr'+layer.lyr_id]
}"></div>
Now nothing happens, no error at all.
When I want to see isTicked value with {{ isTicked }}, it's just shows {}.
This is what I define in the <script></script> part.
export default {
data() {
return {
isTicked: {},
...
};
},
...
}
Could you help me where I get it wrong?
Thanks!
Edit:
I know that declaring as isTicked: {}, the first few clicks won't do anything because its proerty is undefined. However, it should be defined by the first/second click not something like this.
Objects does not reflect the changes when updated like this.
You should use $set to set object properties in order to make them reactive.
Try as below
<div class="tick-box" :class="{ tick: isTicked['lyr'+layer.lyr_id] }" #click="onChecked"></div>
Add below method:
onChecked() {
this.$set(this.isTicked,'lyr'+this.layer.lyr_id, !this.isTicked['lyr'+this.layer.lyr_id])
}
VueJS watches data by reference so to update object in state you need create new one.
onChecked(lyr_id) {
const key = 'lyr'+lyr_id;
this.isTicked = {...this.isTicked, [key]: !this.isTicked[key]};
}
Is there any way to get computed data from child component to parent component? Because I'm sending the data from parent to child first and then I want to use the comuted property (data) in the parent component. I want to do that because I want to reuse that important component (child) in other components too.
I have a search input field for filtering my items, and when i wrote something down i wanna get back that list from the child component.
Parent component
<input class="form-control form-control-search m-input" autocomplete="off" type="text" v-on:input='testFunc()' v-model="search" placeholder="Search...">
<paginate-links v-if="items.length > 0" :models="items">
<div class="m-list-timeline__item no-timeline" v-for="item in filterItems" v-bind:key="item.id">
{{ item.title }}
</div>
</paginate-links>
Child component
props: ['item']
computed: {
filterItems () {
return filter // here goes my code
}
}
So can i get the filterItems in the parent component?
There are a couple ways you can send data back to the parent, but probably the easiest way I'd say is using an emit within the computed.
in child:
computed:{
myVal() {
let temp = this.num + 1;
this.$emit('onNumChange', temp);
return temp;
}
}
in parent template:
<my-child-component #onNumChange="changeHandler"/>
in parent script
methods: {
changeHandler(value) {
console.log('Value changed to: ', value);
}
}
You could do a similar thing with watch, or pass a function from parent as a prop that notifies the parent, but my recommended way would be to use vuex
https://vuex.vuejs.org/en/
This is my Creatable component:
function optionsForSelect(field) {
return field
.values
.map((fieldOption) => {
return {value: fieldOption, label: fieldOption};
});
}
function PatientSelectInput({field, options, value, onChange, disabled}) {
const className = field.id + '-select';
return (
<label className={cx('input-label', className)}>
<div className="label-text">{field.displayName}</div>
<Creatable
value={value}
onChange={(selectedValue) => onChange(selectedValue ? selectedValue.value : null)}
disabled={disabled}
onBlurResetsInput={false}
onCloseResetsInput={false}
options={options} />
</label>
);
}
It is a functional component. When it renders, I can create a new option but when I hit tab or enter or click on the automatically generated "Create Option..." the newly created option disappears. I just want the default behavior.
What am I missing?
Unfortunately this version of react-select mutates it's options prop.
This is very bad coding and is fixed in version 2: https://github.com/JedWatson/react-select/issues/2484
The issue you're experiencing is coming from the way you construct the options. Your function creates a new object on each render, replacing the array containing the option you just created.
If you can't update your version I suggest you save the output of optionsForSelect to this.state.options, then pass the state variable into react-select. The upshot of doing this is you still have the ability to mutate the state of your element and limits the impact of the mutate.