In Vue, how to get the content of a textarea? - vue.js

I want to keep the value of a variable identical with the content of a textarea.
I don't want to use v-bind or v-model, because I have already bound the textarea with another value.
This is a notebook app, and the textarea is used to display the content of a note, so it has been bound using v-bind with a note object, like
<textarea cols="30" rows="3" v-bind:value="note"></textarea>
Now, I want to add the "edit note" functionality. So when the content of the textarea changes, I want to store its value into a variable, and when the "submit" button is clicked, I pass the value of the variable, which contains the new content of the note, to backend to update the note.
My question is, how to store the textarea's content into the variable after each time the content changes?
I think I cannot use v-model because this way the note will be changed right after the content of the textarea is modified (though not sent to backend), but this is not what I want. What I want is the note to be changed only after the "submit" button is clicked. Thus, I cannot use v-model
Should I use v-on:change? If so, how to get the content of the textarea?
Like,
<textarea v-on:change="updateTheVariable(I need to get the content of the textarea here)"> ... </textarea>
methods: {
updateTheVariable(content of the textarea) {
this.variable = content of the textarea
}
}
Thanks

I'm assuming this thing only shows up when you click some kind of edit button which is why you don't want to alter note so try something like this instead
<button type="button" v-if="!editMode" #click="editNote">Edit</button>
<form v-if="editMode" #submit="handleSubmit">
<fieldset :disabled="saving">
<textarea v-model="editingNote"></textarea>
<button type="submit">Edit</button>
</fieldset>
</form>
export default {
data: () => ({
note: 'whatever', // maybe it's a prop, maybe assigned later, doesn't matter
editMode: false,
editingNote: null, // this will be used to bind the edited value
saving: false
}),
methods: {
editNote () {
this.editingNote = this.note
this.editMode = true
this.saving = false
},
async handleSubmit () {
this.saving = true // disables form inputs and buttons
await axios.post('/notes/update', { note: this.editingNote}) // just an example
this.note = this.editingNote // or maybe use data from the response ¯\_(ツ)_/¯
// or if it's a prop, this.$emit('updated', this.editingNote)
this.editMode = false
}
}
}

As #Phil indicated in a deleted post, the right way to do it is
<textarea #input="updateTheVariable($event.target.value)"></textarea>
.
.
.
methods:{
updateTheVariable(value){
this.variable = value
}
}

Related

How to prevent reactivity in form placeholder

I have an input field set up as
<input #input="e => machineCIDR = e.target.value" type="text" name="machine" class="form-control form-control-lg" :placeholder="machineCIDR">
The problem is, whenever someone fills out the form and then deletes it all, the placeholder is left with the last character that was filled out.
How can I setup :placeholder="machineCIDR" so that it shows the initial value, and then never gets updated again??
Assuming machineCIDR is set up already (as a prop or in data), you could create an object for storing all of your initial values:
data() {
return {
...
initial: {}
}
}
And set up the values in created:
created() {
this.initial['machineCIDR'] = this.machineCIDR;
}
Then bind to that instead in the placeholder:
:placeholder="initial['machineCIDR']"

set value of input programatically doesn't refresh component DOM

I have an input which is bidden to property message. I have a set button , which I use for changing of input value programmatically. When the button is pressed, value of input is correctly changed to 'xxxx'. when I press clean button after that , the input is correctly cleaned but when I repeat pressing set and clean again the input does not get cleared anymore.
Working example is here:
https://codepen.io/dan-ouek/pen/rNBjxRO
<div class="container">
<div id='root' class="box">
<input ref="templateFilter" type='text' id='input' v-model='message'>
{{ message }}
<button #click="set">set</button>
<button #click="clean">clean</button>
</div>
</div>
new Vue({
el: '#root',
data: {
message: 'Hello Vue'
},
methods: {
set: function () {
let element = this.$refs.templateFilter
Vue.set(element, 'value', 'xxxx')
}, clean: function () {
this.message = ""
}
}})
Questions:
1) Is it possible to change input programmatically without working with bidden property value? Something like direct DOM manipulation:
let element = document.getElementsByClassName("templateFilter")[0]
element.value = 'xxxxx'
but with proper component refresh?
2) Why is the {{ message }} not refreshed after calling set method?
Why is the message not refreshed after calling set method?
When you type something on your input the message data gets updated via an event handler BUT when you set it programmatically the event handler is NOT triggered and that's why message was not getting updated / refreshed....
Solution :
a short solution to your issue would be just to mutate the message value this.message = "xxxx" but if you insist on making that programmatically you have to trigger the input event :
set: function() {
let element = this.$refs.templateFilter
Vue.set(element, 'value', 'xxxx')
element.dispatchEvent(new Event('input'))
}
Here is a Demo : codepen

You may have an infinite update loop in a component render function using click event conditional rendering

I am rendering two texts based on a condition and be able to pass methods to the click event based on the condition. The default text is ADD TO COLLECTION because initially hasPaid property is false. Once payment has been made, I want to set that property to true
The function addToCollection first opens a modal, on the modal, the handlePayment function is implemented. I have been able to conditionally render the div to show either ADD TO COLLECTION or DOWNLOAD using v-on="". I also return hasPaid property from the handlePayment function.
<div class="float-right peexo-faded-text card-inner-text" :face="face" v-on="!hasPaid ? {click: addToCollection} : {click: handleDownload(face)}">
{{!hasPaid ? 'ADD TO COLLECTION': 'DOWNLOAD' }}
</div>
data: function () {
return {
hasPaid: false,
}
},
addToCollection(){
this.showcollectionModal = true;
},
handlePayment(){
this.showcollectionModal = false;
let accept = true;
this.showpaymentsuccessmodal = true;
//this.hasPaid = true;
return {
hasPaid: accept
}
},
I want to be able to set hasPaid property on the handlePayment function for the render function to pick it, so that the handleDownload function can then work.
The last section of this bit is going to be problematic:
v-on="!hasPaid ? {click: addToCollection} : {click: handleDownload(face)}"
When hasPaid is true it will invoke the method handleDownload immediately. That is, it will be called during render, not when the <div> is clicked.
You could fix it by 'wrapping' it in a function:
{click: () => handleDownload(face)}
I've used an arrow function in my example but you could use a normal function if you prefer.
Personally I wouldn't try to do this using the object form of v-on.
My first instinct is that you should consider just having two <div> elements and use v-if to decide which one is showing.
If you did want to use a single <div> I would put the click logic in a method. So:
<div class="..." :face="face" #click="onDivClick(face)">
Note that despite the apparent syntactic similarity to the way you defined your click listener this won't invoke the method immediately.
Then in the methods for the component:
methods: {
onDivClick (face) {
if (this.hasPaid) {
this.handleDownload(face)
} else {
this.addToCollection()
}
}
}

Render form after method completion in VueJS

I am facing a problem with my page with VueJS. It's a page for different translations of the website. It has a dropdown on the top for the language selection that once switched will update the fields with the current language.
The problem starts when it loads, because my form is like this:
<form id="trForm">
...
<input type="text" name="header_title" class="form-control" v-model="translations.header.header_title" />
...
</form>
It's trying to access these attributes before the method returns any data, but somehow it will still show the data once it is complete, but it becomes troublesome when I try to switch the language, it won't because of this problem and also, if I do the following:
<form id="trForm">
...
<input type="text" name="header_title" v-if="translations.header" class="form-control" v-model="translations.header.header_title" />
...
</form>
on each field, those that aren't populated will display no field at all for a new input value. I tried something like translations.features || '', but no success.
I also tried to put on the parent block a condition that if the loading is false will display the form, but since the page is loaded first than the method is executed, it will always be false for the first microsecond.
methods: {
fetchTranslations(e) {
let vm = this;
vm.loaded = false;
$.get('/ajax/admin/translations', { 'locale': e }).done((data) => {
if (data.success) {
vm.translations = JSON.parse(data.translations.translation);
vm.loaded = true;
} else {
toastr.error('Something went wrong');
}
});
},
Please, what do I do? It'd be good to show the form after there is data.
Introduce a new variable, e.g. loaded that defaults to false
Use this variable as a v-if condition on the form
In the callback of your data fetch, set loaded to true.

Set focus for paper-input via radio button

In Polymer (1.0), how can I set the focus of the iron-input when (as example) radiobutton 'radio1' is selected.
<div>
<div>Title:</div>
<paper-radio-group>
<paper-radio-button name="radio1">Radio1Label</paper-radio-button>
<paper-radio-button name="radio2">Radio2Label</paper-radio-button>
</paper-radio-group>
<paper-input-container>
<input is="iron-input">
</paper-input-container>
</div>
You will need to bind a click event to radio1:
<paper-radio-button name="radio1" on-click="_setInputFocus">Radio1Label</paper-radio-button>
Then define the function _setInputFocus so that it selects the input and sets the focus to it:
<script>
Polymer({
is: 'the-name-of-your-element',
_setInputFocus: function () {
this.$$("input").focus();
}
});
</script>
EDIT: Now we want the input disabled until the user selects the radio button. So we give the iron-input the disabled attribute:
<paper-input-container>
<input is="iron-input" disabled>
</paper-input-container>
Then we change our JavaScript function so that we remove the disabled attribute and sets the input focus:
<script>
Polymer({
is: "focus-test",
_setInputFocus: function () {
var inputElement = this.$$("input"); // grab the element
inputElement.toggleAttribute("disabled", false); // remove the disabled attribute
inputElement.focus(); // set the focus to this input
}
});
</script>
You could also use the <paper-input> instead of the <paper-input-container> element and then use
setTimeout(function() {
this.$.tabname.inputElement.focus()
}.bind(this), 200);
in your function. (The set timeout is sometimes necessary because if another element had focus and is about to close (e.g. an iron-dropdown) then you would have to wait for this to finish before giving focus to the input)