In a vue app using quasar, I have three file picker fields, and when one of those fields change, I want to call a specific function. I want to be able to pass the v-model as a variable into the function so I can update the v-model using the function.
See more problem description in the onSelected function description.
For example, I may want to bind the v-model of whatever field was changed to a new variable. So how would I tell the function what v-model was passed at the #change event?
<q-file
v-model="fieldOne"
#change="onSelected()"
></q-file>
<q-file
v-model="fieldTwo"
#change="onSelected()"
></q-file>
<q-file
v-model="fieldThree"
#change="onSelected()"
></q-file>
function onSelected(event) {
// I would like to update the v-model of the field that was
// subject to the #change event. event.target.value doesn't
// work. How to I work with the specific v-model that
// triggered
//the #change event?
}
Related
I want to understand below issue which i am facing . I have a form with formgroup in it . I have a multiselect tag in the html which consists of (select) = onSelect(event)
Now in ts file i am using value changes to the template refernce of the multiselect tag ! And also onSelect method
My html
<ds-multi-select>
#costcenter
[items] = “listofitems”
[label] = “labelkey”
[value] = “valuekey”
(Select) = “onselect($event)”
</ds-multi-select>
Inside a method in my ts file i have
this.form.get(“costCenter”).valuechanges.pipe().subsribe (costcheck
=> {
…..
});
Also have separate function
OnSelect(selectedItem:any)
{
IsSelected = SelectedItem.IsselectedItem
}
Now whenever i hit the dropdown list, the valuechanges is getting called first and then onSelect method. I want to use Isselected value from onSeelect function inside valuechanges. I want onSelect to be called first and use the valuechanges later.
I also tried to check in the valuechanges event if I could catch the checkbox is selected or not attribute but couldn't find anything !
Please help with the correct solution !
I faced an strange issue with Vue3 $emit. I was refactoring my own Vue2 "form-input" -component, which is basically an wrapper for rendering either text-input, (multi)select-option, textarea or any other basic input field.
This component used to bind value against v-model, so it was emitting input via "this.$emit('input', this.value)".
Since Vue 3 changed input to update:modelValue, I made this modification and additionally presented "Emits" -property-list to component. Everything was seemingly working...
But then I recognized that Vue-multiselect 3 (NPM package "vue-multiselect": "^3.0.0-alpha.2") was emitting primitive value, an integer number, which didn't trigger #input on parent-component.
form-input.vue
<input v-if="resolveType === 'text' || resolveType === 'number' || resolveType === 'tel' || resolveType === 'email'"
v-model="localValue"
#input="$emit('update:modelValue', $event.target.value)"
/>
<multiselect v-model="localValue"
class="full-width-tags"
#update:model-value="$emit('update:modelValue', $event)"
/>
// Please note that multiselects $event is an integer, I have checked this multiple times from console.log
... and when I'm listening for #input on parent component it seems "text"-type field triggers event-listener but multiselect doesn't. Only difference on these components is that multiselect is emitting primitive value (integer), while input is sending an event-object.
Could someone explain why event-object and primitive value are handled differently for #input , and how could I fix my multiselects emit so that it's emitting input? Currently I'm emitting both "update:modelValue" AND "input" -events one after another for multiselect, but I'm just wondering if there is easier way?
From your question it seems you have read the Vue 3 Migration Guide - particularly the part about change of v-model on custom components and changed your form-input to emit update:modelValue event instead of input event
So why are you listening for updates on your form-input component with #input instead of #update:modelValue ?
The only reason why the #input placed on your form-input component in the parent works, is because of this change
In short - because your component declares that it emits update:modelValue event (using emits option), every other event listener placed on it is directly bound to the root element of the component - native <input> in this case
This is not what you want. Just change <form-input #input="..." /> to <form-input #update:modelValue="..." />
So the image above is my code inside a comp.js (Vue component) when the user clicks 'Update' button, it will grab the updated input and push it to firestore.
I put v-on:emit on every single input and I tried to reference it on the 'Update' button.
This is my modal inside the HTML file, I tried to connect the function from comp.js to function.js.
However, the methods above didn't work and it gave me the error below.
I'm not really sure how to grab the value from each input and connect
UPDATED CODE BASED ON ITTUS'S SUGGESTION:
So based on the Ittuss suggestion below, I tried to pass over to items through the emit inside the Update button, I did this because I want to pass all the input values above the button to update the Firestore database.
I changed the cuisedit to this:
And I updated the function in the .js to this:
However, I received an error saying that I didn't reference correctly.
Do you know why it isn't grabbing the value emitted from the button?
In your cuiseedit component, $emit should contain only 1 additional parameter:
<button #click="$emit('some-change', obj2.id)"></button>
and in component:
<transition name="fade">
<cuisedit v-if="showModal" :obj2="cuisinemodal" #some-change="updateData">
</cuisedit>
</transition>
updateData: function (id) {
firestore.collection("koreanbap-cuisines").doc(id).update()....
}
Note
If you want to pass more data, you should wrap them to an object
<button #click="$emit('some-change', {id: obj2.id, event: $event})"></button>
I'm using the 'react-md' library and I am trying to use the SelectField component, but when I send a function for onChange the select field no longer updates as it's supposed to.
handleSelection = (value, index, event, details) => {
// "details.id" is the id of the field which I am using to keep track of state
this.setState({[details.id]: value});
}
render() {
const STRING_SELECTORS = ['At most', 'At least'];
return(
<div>
<SelectField
id="calories-selector"
className="md-cell selector md-cell--5"
menuItems={STRING_SELECTORS}
defaultValue="At most"
onChange={this.handleSelection)
/>
)
}
When I don't call this.setState() in the handleSelection function, the menu changes as expected when clicking an item, however when I do call setState, it updates the selection on a delay. If the menu says "At most" and I click "At least" it will stay at "At most" then if I click "At most" it will then change the "At least".
I've had a similar issue with input fields, and to solve this I used onBlur instead of onChange, but the react-md library's onBlur doesn't get triggered in the way that I need.
You can use the value prop of SelectField component. Create a state and bind it to the SelectField value prop and update the state at onChange event to the selected value.
See edit at the bottom.
My company has a huge code base and we want to start using knockout more effectively. However, we have validation code in place already that takes care of all aspects of client-side validation. It uses jQuery to show validation error messages and to sanitize user input.
For example, if I add the class "validate-range" to an input, it will use jQuery change/focusout events to track changes and then if a value is out of the range, it will replace it with the min/max value using $(input).val(). Since this validation code makes changes this way programmatically, my knockout view model won't be updated when these kind of changes are made.
This validation code is used everywhere in the system, and can't be replaced at the moment, so in order to use knockout, I have to make it work along side this code. What i've tried so far is creating a custom value binding that adds an additional change event handler which is used to update the view model whenever the validation code changes an input's value.
This works surprisingly well in all cases except inside a foreach binding (which is the same as using the template/with binding I would imagine). My change event handler isn't being fired on any inputs inside the foreach that use the custom value binding, even though the custom binding is being reapplied to all inputs inside the foreach every time the observable array changes.
I was hoping someone has dealt with this problem before, having to make knockout work with existing javascript code that changes DOM values, and thus doesn't update the view model. Any help is greatly appreciated.
Javascript code for custom binding, creating view model, and old validation code:
// custom value binding for amounts
ko.bindingHandlers.amountValue = {
init: function (element, valueAccessor) {
var underlyingObservable = valueAccessor(),
interceptor = ko.computed({
read: function () {
var value = underlyingObservable();
return formatAmount(value);
},
write: function (newValue) {
var current = underlyingObservable(),
valueToWrite = parseAmount(newValue);
if (valueToWrite !== current)
underlyingObservable(valueToWrite);
else if (newValue !== current.toString())
underlyingObservable.valueHasMutated();
}
});
// i apply a change event handler when applying the bindings which calls the write function of the interceptor.
// the intention is to have the change handler be called anytime the old validation code changes an input box's value via
// $(input).val("new value"); In the case of the foreach binding, whenever the observable array changes, and the table rows
// are re-rendered, this code does get ran when re-applying the bindings, however the change handler doesn't get called when values are changed.
ko.applyBindingsToNode(element, { value: interceptor, event: { change: function () { interceptor($(element).val()); } } });
}
};
// view model creation
// auto create ko view model from json sent from server
$(function () {
viewModel = ko.mapping.fromJS(jsonModel);
ko.applyBindings(viewModel);
});
// old validation code
$(document).on("focusout", ".validate-range", function () {
var $element = $(this),
val = $element.val(),
min = $element.attr("data-val-range-min"),
max = $element.attr("data-val-range-max");
if (val < min)
// my change handler from custom binding doesn't fire after this to update view model
$element.val(min);
if (val > max)
// my change handler from custom binding doesn't fire after this to update view model
$element.val(max);
// more code to show error message
});
HTML code that uses the custom binding inside of a foreach binding:
<table>
<thead>
<tr>
<td>Payment Amount</td>
</tr>
</thead>
<tbody data-bind="foreach: Payments">
<tr>
<td><input type="text" class="validate-range" data-val-range-min="0" data-val-range-max="9999999" data-bind="amountValue: Amount" /></td>
</tr>
</tbody>
</table>
So in the above example, if I enter "-155" in an amount text box, my custom binding runs and sets the view model Amount to -155. Then the old validation runs and re-sets the value of the textbox to "0" with $(input).val(0). My view model doesn't get updated at this point, and still reflects the -155 value. My change event handler from the custom binding is supposed to be ran to update the view model to 0, but it doesn't.
Edit:
As pointed out in the answer, .val() does not trigger any change events. The change event handler I added didn't do anything. The reason the view model was being updated when the validation code changed a value outside of the foreach binding was because we had logic somewhere else in our javascript code that was manually triggering the change event using the blur event, which in turn triggered my custom binding to run and update the view model. This blur event handler was directly bound to the text boxes, instead of being delegated, so it worked for text boxes that were there when the page is first rendered, but not for the ones dynamically inserted by the foreach binding.
For now, I just changed this logic to delegate the events within the document, so it would include dynamically inserted text boxes, and it seems to be working fine. I'm hoping to come up with a better solution in the future.
Calling $(element).val("some value"); does not trigger the change event.
You would need to do: $(element).val("some value").change();