How can i have a rule to cancel a form?

I have a number of forms and would like to be able to cancel by saying “cancel”. I have tried a rule as below but it just keeps going back into the form. There is an example of doing this with a story but I really don’t want to create cancel stories for each form and each field in the form.

This is the rule I have tried along with numerous variations.

- rule: cancel
    steps:
      - intent: cancel
      - action: action_deactivate_loop
      - action: utter_cancel

Why don’t you just create a single form and enable the slots by custom action? This way you only need one rule

image

You need to add a condition that the loop is active :slight_smile:

Look at this example (more here):

- story: User fills form_log_in and stops
  steps:
  - intent: log_in
  - action: form_log_in
  - active_loop: form_log_in
  - or:
    - intent: stop
    - intent: deny
  - action: action_deactivate_loop
  - active_loop: null
  - action: utter_okay

Or, a method similar to the one Rodrigo mentioned above, you can use a FormValidationAction to return an empty list in the required_slot() method if the intent is ‘cancel’`:

def required_slots(self, dom_slots, dispatcher, tracker, domain):
    if tracker.latest_message['intent'] == 'cancel':
        return []
    else:
        return dom_slots # Or whatever your original required_slot() did

Thanks. The python solution is better as it could apply to all forms with a few lines of code rather than setting up stories for each form. However using “required_slots” it still continues to validate and submit.

Found solution below seems to work but perhaps there is a cleaner answer:

in formvalidationaction

def validate(self, dispatcher, tracker, domain):
   if tracker.latest_message["intent"]["name"] == "cancel":
       async def cancel():
           return [SlotSet("cancel", True)]
      return cancel()
  return super().validate(dispatcher, tracker, domain)

Then in submit:

def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict[Text, Any]]:
        if tracker.get_slot("cancel"):
             return [AllSlotsReset(), Restarted()]

        # do what you want     
        return [AllSlotsReset(), Restarted()]

Also, you can find relevant information in this tutorial about customizing forms. It goes over where the user want to cancel a form

Yeah that’s a solution as well :slight_smile: