Can ng-submit be overridden?

Is there a way to modify ng-submit in order to execute certain functions before running the expression it contains? For instance, I want to:

1) Mark all fields as dirty or touched so that validation is performed on all fields, even if the user skipped some.

2) Validate all fields and prevent submission if any fail validation.

3) Scroll to and focus on the first invalid field if there are any errors.

I've come across a few directives that partially achieve this, creating new element directives. However, none actually override or extend ngSubmit. Is it possible to accomplish this?

Answer №1

Validation in Angular can work even without physically interacting with an element, as demonstrated in point #1. For instance, setting $scope.test = "abcd"; would invalidate the input if it is limited to a maximum length of 3 characters:

<input ng-model="test" ng-maxlength="3">

To achieve point #2, one can simply utilize form.$valid:

<form name="form1" ng-submit="form1.$valid && onSubmit()">
  ...
</form>

If there's more complex pre-submit logic involved, it should be handled within the controller, such as in the onSubmit() function.

However, when the pre-submit logic pertains to the View rather than the ViewModel - like scrolling - creating a custom ngSubmit directive with higher priority can intercept the default submit event handling:

.directive("ngSubmit", function() {
  return {
    require: "?form",
    priority: 10,
    link: {
      pre: function(scope, element, attrs, form) {
        element.on("submit", function(event) {        
          if (form && !form.$valid) {
            event.stopImmediatePropagation();
            event.preventDefault();

            // implement necessary scrolling actions here
          }
        })
      }
    }
  }
});

View Demo

EDIT:

The use of pre-link is crucial in this context due to the order of link function executions. The sequence of execution follows:

1. pre-link of parent or higher priority directive
2. pre-link of child or lower priority directive
3. post-link of child or lower priority directive
4. post-link of parent or higher priority directive

By leveraging higher priority and pre-link, this directive can register element.on("submit", ...) before the built-in ngSubmit, ensuring precedence in event handling.

Answer №2

If you're looking to start coding and meet criteria numbers 1 and 2, this snippet should give you a good foundation and even touch on number 3.

Scrolling to invalid fields is something I haven't explored yet, but it does sound intriguing. You could potentially create a complete "form wrapper directive," although that might be considered excessive.

Personally, I would opt for using a service method called within my controller. Are you considering just scrolling to the first invalid field and focusing on it?

Template

<!-- Form Template -->
<form name="form" novalidate ng-submit="vm.submit(form.$valid, vm.data)">
    <input type="text"
           name="blah"
           ng-model="vm.data.blah"
           ng-model-options="{debounce: {'default': 300, blur: 0}}"
           required
           formnovalidate/>
     <div ng-messages="form.blah.$error"
          ng-messages-include="messages.html"
          ng-if="form.$submitted || form.blah.$touched">
     </div>
    <button type="submit">Submit</button>
</form>

<!-- messages.html -->
<div ng-message="required">This field is required</div>

Controller

vm.data = {};
vm.submit = function(isValid, data) {
    if (!isValid) { 
        // Scroll to bad field
        return; 
    }
    // Perform form submission via service
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Change the behavior of an onclick event on the second click

I'm trying to make a button on my website that not only plays music when clicked but also changes the text inside the button to "Go to SoundCloud" and redirects to SoundCloud. Currently, I have been able to achieve both functions separately - redirect ...

Adjusting color with the .on method in Event Listener

What's wrong with this code? html <!DOCTYPE html> <html> <head> <title>Ending Project</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> &l ...

Tips for incorporating external routes into the routes index file

I am currently dealing with a users.js and an index.js file. users.js const express = require('express'); const router = express.Router(); const {catchErrors} = require('../handlers/errorHandlers'); const authController = require(&ap ...

Looking for a quick guide on creating a basic RESTful service using Express.js, Node.js, and Mongoose?

As a newcomer to nodejs and mongoDB, I've been searching high and low on the internet for a tutorial that combines express with node and mongoose. What I'm specifically looking for is how to use express's route feature to handle requests and ...

The FormControlLabel radio button within the RadioGroup is experiencing difficulty in becoming selected

Utilizing a RadioGroup component to showcase a dynamic list of Radio options using FormControlLabel. The dynamic radio choices are appearing correctly on the screen and I can obtain the selected radio option through onChange in RadioGroup. However, after s ...

Changing the content of the initial post in a loop on WordPress

<?php $freeadvice=new WP_Query('category_name=freeadvice&showposts=10'); while($freeadvice->have_posts() ): $freeadvice->the_post(); ?> <li class="event"> <input type="radio" name="tl-group" /> ...

What is a reliable method to retrieve the text from the current LI if all LI elements in the list share the

I'm encountering an issue with retrieving the text from LI elements because I have 10 list items and they all have the same class name. When I attempt to fetch the text using the class name or id, I only get the text of the last item. Here is my code ...

Bring in a JavaScript file from Blogger without using a tag

Is there a way to retrieve blogger feeds code without using