AngularJS多步骤表单-按enter键应该会移动到下一步,并在最后一步提交



我的多步和提交进入有问题。我已经按照本教程创建了一个多步骤表单。

现在的问题是,当你在第一步中按enter键时,它会提交表单,而这不是目的。

我有一个通用的form。html,像这样:
<form id="appointment-form" name="appointmentform" ng-submit="processForm(appointmentform.$valid)">
    <!-- our nested state views will be injected here -->
    <div id="form-views" ui-view></div>
</form>

我还有

form-license.html (step 1)

<!-- form-license.html -->
<label>Nummerplaat ingeven</label>
<div class="form-group">
    <div class="col-xs-8 col-xs-offset-2">
        <input required type="text" class="form-control" name="license" ng-model="formData.license">
    </div>
</div>

<div class="form-group row">
    <div class="col-xs-4 col-xs-offset-4">
        <a ng-click="next(1)" ng-disabled="!licenseValidated" class="btn btn-next btn-block">
            Volgende
        </a>
    </div>
</div>

form-profile.html (step 2)

<div class="profile">
    <div class="form-group">
        <label class="col-sm-3 control-label" for="name">Name</label>
        <div class="col-sm-9">
            <input type="text" class="form-control" name="name" ng-model="formData.profile.name">
        </div>
    </div>
    <div class="form-group row">
        <div class="col-xs-8 col-xs-offset-2">
            <a ng-click="next(1)" ui-sref="form.license" class="btn btn-block btn-previous col-xs-3">
                VORIGE
            </a>
            <a ng-click="next(2)" ng-disabled="!infoValidated" class="btn btn-block btn-next col-xs-3">
                Volgende
            </a>
        </div>
    </div>
</div>

form-appointment.html(步骤3)

<div class="appointment">
    <!-- form-payment.html -->
    <div class="text-center">
        <div id="calendar" class="span8 calendar" ui-calendar="uiConfig.calendar" full-calendar  ng-model="eventSources"></div>
        <div id="appointment_hours">
            <div ng-repeat="(key, value) in formData.appointments">
                <input id='<% key %>' type='radio' ng-model='formData.appointment_hour' ng-change="change('<% key %>')" name='appointment' value='<% key %>'>
                <!-- change int to string -->
                <label for='<% key %>'><% key | format_time %></label><br>
            </div>
        </div>

        <div class="form-group row">
            <div class="col-xs-8 col-xs-offset-2">
                <a ng-click="next(2)" ui-sref="form.profile" class="btn btn-block btn-previous col-xs-3">
                    VORIGE
                </a>
                <button type="button" class="btn btn-block btn-next col-xs-3">VOLGENDE</button>
            </div>
        </div>
    </div>
</div>

我的配置和控制器是这样的:

// app.js
// create our angular app and inject ngAnimate and ui-router
// =============================================================================
angular.module('formApp', ['ngAnimate', 'ui.router', 'ui.calendar'])
// configuring our routes
// =============================================================================
.config(function($stateProvider, $urlRouterProvider, $interpolateProvider) {
    $interpolateProvider.startSymbol('<%');
    $interpolateProvider.endSymbol('%>');
    $stateProvider
        // route to show our basic form (/form)
        .state('form', {
            url: '/form',
            templateUrl: 'views/form.html',
            controller: 'formController'
        })
        // nested states
        // each of these sections will have their own view
        // url will be /form/interests
        .state('form.license', {
            url: '/license',
            templateUrl: 'views/form-license.html'
        })
        // url will be nested (/form/profile)
        .state('form.profile', {
            url: '/profile',
            templateUrl: 'views/form-profile.html'
        })
        // url will be /form/payment
        .state('form.appointment', {
            url: '/appointment',
            templateUrl: 'views/form-appointment.html'
        })
        // url will be /form/success
        .state('form.success', {
            url: '/success',
            templateUrl: 'views/form-success.html'
        });
    // catch all route
    // send users to the form page
    $urlRouterProvider.otherwise('/form/license');
})
// our controller for the form
// =============================================================================
.controller('formController', function($scope, $http, $compile, $state, uiCalendarConfig) {
    console.log($scope.agendaValidated);
    $scope.change = function(key){
        // get number of available spots
        var n_appointments = $scope.formData.appointments[key];
        var first_available = n_appointments[0];
        // set column id
        $scope.formData.column_id = first_available.column_id;
    };
    $scope.obj = {
        licenseplate: true
    };
    $scope.calendarData = [];
    $scope.appointments = [];
    var date = new Date();
    var d = date.getDate();
    var m = date.getMonth();
    var y = date.getFullYear();
    // we will store all of our form data in this object
    $scope.formData = {};
    $scope.formData.profile = {};
    $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
        $('.loader').hide();
    });

    $scope.next = function(step){
        $('.loader').show();
        if(step == 1) // licensePlate
        {
            // receive customer data
            $http.post('/api/licenseplate', { license: $scope.formData.license })
                .success(function(data, status, headers, config){
                    var item = data.item;
                    console.log(item);
                    if(item) // fill in the name, address, email and telephone number
                    {
                         $scope.formData.profile.name = item.driver_name;
                         $scope.formData.profile.street = item.driver_street;
                         $scope.formData.profile.zipcode = item.driver_zipcode;
                         $scope.formData.profile.city = item.driver_city;
                         $scope.formData.profile.email = item.driver_email;
                         $scope.formData.profile.telephone = item.driver_tel_no;
                    }
                    $state.go('form.profile');
                })
                .error(function(data, status, headers, config) {
                    console.log("Data: " + data +
                        "<hr />status: " + status +
                        "<hr />headers: " + headers +
                        "<hr />config: " + config);
                });
        }
        else if(step == 2)
        {
            // save customer data
            // get calendar appointments
            var current_date = (m+1) + '/' + d + '/' + y;
            $http.post('/api/calendar', { date: current_date })
                .success(function(data, status, headers, config){
                    console.log(data);
                    var item = data.items.item;
                    item.sort(function(a, b) {
                        return a.column_id - b.column_id;
                    });
                    $scope.calendarData.pop();
                    $scope.calendarData.push(item);
                    $state.go('form.appointment');
                })
                .error(function(data, status, headers, config) {
                    console.log("Data: " + data +
                        "<hr />status: " + status +
                        "<hr />headers: " + headers +
                        "<hr />config: " + config);
                });
        }
    };
    // function to process the form
    $scope.processForm = function(isValid) {
        $('.loader').show();
        var appointment_date    = $scope.formData.appointment_date;
        var appointment_hour    = $scope.formData.appointment_hour;
        var column_id           = $scope.formData.column_id;
        var profile             = $scope.formData.profile;
        var license             = $scope.formData.license;
        $http.post('/api/agendainsert', { appointment_datetime: appointment_date + appointment_hour, profile: profile, column_id: column_id, license: license })
            .success(function(data, status, headers, config){
                $state.go('form.success');
            })
            .error(function(data, status, headers, config) {
                console.log("Data: " + data +
                    "<hr />status: " + status +
                    "<hr />headers: " + headers +
                    "<hr />config: " + config);
        });
    };
        ///////////////////////////
        // validation functions //
        /////////////////////////
        $scope.error = {};
        // STEP 1
        $scope.$watch('formData.license', function (newVal) {
            $scope.licenseValidated = validateLicense(newVal);
        });
        var validateLicense = function (newVal) {
            // check if valid license
            /*$http.post('/api/licensevalidate', { license: newVal })
                .success(function(data, status, headers, config){
                    if(data == 1)
                    {
                        $scope.licenseValidated = true;
                    }
                })
                .error(function(data, status, headers, config) {
                    console.log("Data: " + data +
                        "<hr />status: " + status +
                        "<hr />headers: " + headers +
                        "<hr />config: " + config);
                });*/
            // If you are only checking for content to be entered
            return (newVal !== '' && newVal !== undefined);
        };
        // STEP 2
        $scope.$watchGroup(['formData.profile.name', 'formData.profile.street', 'formData.profile.zipcode', 'formData.profile.city', 'formData.profile.email', 'formData.profile.telephone'], function (newVal) {
            $scope.infoValidated = validateInfo(newVal);
        });
        var validateInfo = function (newVal) {
            if (newVal.length > 0) {
                for (var i = 0, l = newVal.length; i < l; i++) {
                    if (newVal[i] === undefined || newVal[i] === '') {
                        return false;
                    }
                }
                return true;
            }
            return false;
        };
    });

问题是当你在第一步或第二步点击enter时,它提交了表单,数据没有正确发布。它调用函数processForm。但是我只想在最后一步调用processForm函数。

当你在第一步点击回车键的时候,我怎么才能让它在第二步运行呢?我已经尝试禁用输入按钮,但它不工作与指令。

您需要创建一个指令来监听表单上的keydown事件,并防止按下的键为enter keyCode == 13时的默认动作

这是一个DEMO

包括jquery

创建一个指令disable-enter-submit并将其附加到表单

<form id="appointment-form" name="appointmentform" ng-submit="processForm()" disable-enter-submit>
实现指令

app.directive('disableEnterSubmit', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            // listen to the keydown event on the form and if the pressed ..
            //..key is enter then prevent the default action/s which is submitting the form
            element.bind("keydown", function(event) {
                if(event.keyCode == 13) {
                  event.preventDefault();
                  return false;
                }
             });
        }
     }
});

这里是一个稍微改进的DEMO

-------------------------- --------------------------

如果按下enter键需要进入下一步

创建控制器变量

var total_steps = 2; // total steps of the form
var current_step = 1; // active step
$scope.next = function(step) {
    // if current step is equals to total steps then submit the form
    if(current_step == total_steps) {
      $scope.processForm();
      return;
    }
    // if step is defined then assign the current_step to step
    // else increment the current_step by 1
    if (!angular.isUndefined(step)) {
      current_step = step;
    } else {
      current_step++;
    }
    // load the proper template based on step
    $scope.form_fields = 'step' + current_step + '.html';
};
指令 中的

element.bind("keydown", function(event) {
    if (event.keyCode == 13) {
      // if press enter then call the next() function on the scope
      // we need to trigger the digest cycle manually
      // because `element.bind("keydown"..` happens out of angular knowledge.
      // so i wrapped it in a `$timeout` or you can use `scope.$apply();` after the `scope.next();`
      $timeout(function() {
        scope.next();
      });
      event.preventDefault();
      return false;
    }
 });

这里是DEMO

最新更新