Can't go to next step after going back using vee-validate - vue.js

I'm using vee-validate v3 to validate a multi step form then call axios. I use handleSubmit and added ValidationObserver with unique keys for each step. Now my issue is after moving to the next step and then going back to step 1, the next button is not firing even if there's no field errors found.
Here's the code structure: https://codesandbox.io/s/codesandbox-forked-6hrh4?file=/src/Demo.vue
Note:
the currentStep on my real project is from local storage.
The sample code is just the structure since the actual fields are too long.

A <button> placed inside a <form> element defaults to type="submit".
Which means in any <form> you need to call preventDefault() on a <button> click if you don't want the form submitted.
Changing #click into #click.prevent fixes the issue (because the form is no longer submitted when clicking Previous, therefore currentStep is no longer increased by 1 right after it is decreased by the #click expression - making it look like nothing happened. In fact, both the #click expression and the onSubmit get executed if you don't use .prevent modifier).
As an alternative, you can change the <button> into an anchor:
<a href class="btn" #click="currentStep--" v-text="Previous" />
although I'd personally go with preventing default.

Related

Vuejs #click event works wrong from time to time

Recenty, I noticed that the checkboxes that I wrote a click event worked incorrectly from time to time. Not everytime but sometimes their #click event works in reverse. Here is what I am trying to tell;
<label class="form-switch">
<input type="checkbox" #click="showElement = !showElement"/>
</label>
I have a simple form switch and there are some css on it which I didn't put here, it looks like a toggle switch. It toggles a data which is showElement. The default state of the data is false and when you click on the toggle it becomes true and false respectively.
<div v-show="showElement>
some content here
</div>
When the showElement is true I want to display the above div, and when it becomes false, I want it to be hidden. There is no problem with that. But here is my question;
If my observation is corret, usually when the project is started for the first time, in other words, when I type npm run serve and start the project, I immadiately go and check if it is working fine or not so I click on the checkbox very quickly over and over andsometimes the click event breaks down and starts working backwards. I mean, when the switch is off, the content is visible, when it is false, the div is showing, but it should be reversed. This happens sometimes when I browse the other pages of the project and return to this component. Is this a bug? Or am I doing something wrong? In the first version of the code it was like below;
<label class="form-switch" #click="showElement = !showElement>
<input type="checkbox"/>
</label>
I accidentally typed the click event to the label element instead of input. I thought that might be the problem. I am still thinking that is the problem but the bug that I explained above still happens sometimes. Do you know why? Can anyone explain?
Usually i find that with checkboxes in VueJS #Click is not the way to go. Try to use #Change event instead. This should make it more consistent.
The reason behind this is that the click event triggers before the value has been updated. Therefore creating the risk of it overwriting the old value instead of the newly updated one
EDIT:
I actually think in this case you might even be able to get around this by simply adding a v-model to the checkbox like so:
v-model="showElement" instead of having either #click or #change.
Verison 1:
<label class="form-switch">
<input type="checkbox" #change="showElement = !showElement"/>
</label>
Version 2:
<label class="form-switch">
<input type="checkbox" v-model="showElement"/>
</label>
Check this fiddle: https://jsfiddle.net/x4wykp2u/4/
Hope this makes sense

Access to a function\$refs in another component not in the same level as current one

I've a Vue 2 application, with different components nested.
Their structure is kinda (I'm skipping the not-relevant ones for my question):
<root>
<app>
<component1/>
...
<component3>
<billingAddress>
<customForm/>
</billingAddress>
<shippingAddress>
<customForm/>
</shippingAddress>
</component3>
...
<lastComponent/>
</app>
</root>
The customForm1 and 2 contain a form, validated via vee-validate - so there' a ValidationObserver component.
Those two forms are validated at the relative submit - the submit action is custom, when they are successfully validated, they are hidden - and there is no redirect.
On the "lastComponent" there's a "submit" button whichis disabled until both form are correctly submitted and which does some other logic.
Today I've been asked to change the behaviour of that button: now it may launch the validation and the submit of those two form, skipping so the "manual" submission of the users.
I'm not sure how can handle this, as the ValidationObserver and the custom actions are in components unrelated to the "lastComponent".
For now, I've managed traversing the tree of $refs starting from $root, but I don't really like an approach so fragile.
This is what I'm doing in my "submit" action:
let shippingAddressValid = await this.$root.$children[0].$refs.addresses.$refs.shippingAddress.$refs.addressForm.$refs.shippingAddressForm.validate();
if (shippingAddressValid) {
await this.$root.$children[0].$refs.addresses.$refs.shippingAddress.$refs.addressForm.updateAddress();
}
I'd like to know if there's a better approach.
I've found this anweser that is interesting. However, I haven't found a way to set up a custom event via "global bus" that returns me a value, asynchronously.
I mean, it's mandatory, to get the "valid" state of the form, before calling the submit method.
I can't just call the validation in the method, because I have to do some logic if the form is invalid.

Apex buttons in Interactive Reports break when built-in search filter used

In Apex 5.0.2. I have created a copy-to-clipboard function in my interactive report. The user can copy the value of a hidden column by clicking on this button that is set in a column and is repeating in every row (see image below).
The copy column is edited with an HTML Expression which does the following:
<button class="copytoclipboard
t-Button
t-Button--noLabel
t-Button--icon
t-Button--stretch" customid="#COPY#" type="button">
<span class="t-Icon fa fa-copy" aria-hidden="true">
</span>
</button>
My Dynamic Action with the event 'click', jQuery selector .copytoclipboard has 2 true actions. 1 sets the value of a page item (text_field) by getting the customid from that row with:
this.triggeringElement.getAttribute("customid")
The second one then copies this value to the clipboard.
This works fine and when I inspect the button element, I see the correct HTML output, with the correct value. However, as soon as I use the built-in search filter in the Interactive Report, my button breaks and clicking this button does not trigger my dynamic actions anymore, however, inspecting the element still returns the expected HTML output.
Can somebody please clarify why this is happening, and how this could be avoided?
Thank you in advance.
I found the solution. I had to put the Event Scope of the Dynamic Action to Dynamic, which is set to Static by default. Using the built-in page filter does a PPR of the report, thus when static, the event handler is longer bound to the triggering element.
Static (default) - Binds the event handler to the triggering elements
for the lifetime of the current page, but will no longer be bound if
the triggering elements are updated via Partial Page Refresh (PPR).
Dynamic - Binds the event handler to the triggering elements for the
lifetime of the current page, including any triggering elements that
are recreated via Partial Page Refresh (PPR).
Once - Binds the event
handler to the triggering elements for a once only event.

VueJs - Deleting a File-input component from a list

I'm still pretty new to vue.js.
I recently created some vue components to tidy up my html. The components are different inputs like text and checkbox. They update the parents data using $emit('input', val). And make sure that the components are up-to-date using props and watch() on those props.
Now there is a problem with using watch() on <input type="file />, since you cannot set the input value like you can on other input types.
Using this example:
https://jsfiddle.net/minde281/nyu73dz6/25/
I have a list of, in this case, items on a shoppinglist. You can add an image for each item.
The image is loaded and added to the list. This works fine.
To get my problem:
add an image to item1
delete that item by clicking the X-button
The result is now that item2 will have that image on the <input type="file" />. The preview works as expected since this can be set through script and therefore use watch(). But somehow vue removes the wrong part of the html markup causing the last one to be removed.
Is there a different way to solve this problem? Or is there a way to tell vue to remove the correct part of the html markup?
-Minde
Vue tries to reuse the component and thats why the selected file is in the second input after deleting the component.
To prevent that you should use the key binding like this:
<li v-for="(item, index) in items" :key="item.name">
Now the hole component gets removed and everything should work as expected.

disabling a submit button till validation

Is there a way using dojo/dijit to disable the submit button till all the fields in a form are valid. Kind of like having a dojo > method > onChange inside the form? So the submit button only becomes enabled when all the form elements have meet their criteria?
Are you using a dijit.form.Form widget as your form? If you are, I would suggest connecting to the Form's onValidStateChange event. The docs for this event specifically state your use case:
onValidStateChange
Defined by dijit.form._FormMixin
Stub function to connect to if you want to do something (like disable/enable a submit button) when the valid state changes on the form as a whole. Deprecated. Will be removed in 2.0. Use watch("state", ...) instead.
The best way to see what events are available for a given widget is to look at the API Documentation for the widget you are interested in under the "Event Summary" heading. The dojocampus reference documentation often leaves out examples for references to some of the more obscure features of the widgets.
I would suggest to have a hidden button which will submit the form. When you click visbile button run a javascript function that validates all the input and then clicks on the hidden button to submit the form. Please find the pseudo code below
<form action="register">
<input dojoType="dijit.validation.TextBox"/>
<button onClick="validateall()">submit</button>
<button id="submitForm" type="submit" hidden="true"/>
</form>
function validateAll(){
if(AllOk){
clearErrorMessage();
dojo.byId('submitForm').click();
}else{
showErrorMessage();
}