6

更新

由于问题不清楚,我创建了 jsfiddles 来说明我的问题。

首先,我认为我无法停用表单字段的验证,但我了解到这可以通过 ng-required 指令来完成。

http://jsfiddle.net/charms/YhVfN/23/

我的实际问题是密码字段未设置为原始状态。所有其他表单字段均已清除,但密码字段未清除。

要测试此行为,您可以:

  • 单击“添加用户”按钮
  • 添加电子邮件地址、名字、姓氏、密码和错误密码以进行确认
  • 点击关闭按钮而不保存
  • 点击编辑按钮

然后你会看到密码仍然设置。$setPristine 方法不会清除它。所有其他表单域都被清除。

http://jsfiddle.net/charms/eP7T8/61/

上一个(过时的问题)

有人知道我如何停用禁用字段的验证吗?我正在使用 angularjs 1.1.3。

当我创建一个新用户时,我想验证所有字段,包括密码字段。但是,当我编辑用户时,我希望密码字段保持非活动状态且未经验证,除非用户通过复选框激活字段。

我目前的问题是,如果我将密码字段设置为 ng-disabled=true 验证仍在启动。我认为 ng-required=false 可能会有所帮助,但它没有。

我将密码字段设置为 ng-disabled=true 和 ng-required=false。

<input type="password" name="password" ng-model="password" placeholder="Password" ng-disabled="true" ng-required="false" required/>

我将密码确认字段设置为 ng-disabled=true 和 ng-required=false。

<input type="password" name="passwordConfirm" ng-model="passwordConfirm" placeholder="Confirm Password" ng-disabled="true" ng-required="false" required field-equal="password"/>

但仍在验证 required 和 field-equal 指令。如何防止对那些停用的字段进行验证?

在我的完整代码下方。

HTML:

<div id="user_list" class="listview_list">
<div id="user_row" class="listview_row" ng-repeat="u in users">
    <div id="user_username" class="listview_column"><span class="listview_mainfield">{{u.email}}</span></div>
    <div id="user_firstname" class="listview_column">{{u.firstName}}</div>
    <div id="user_lastname" class="listview_column">{{u.lastName}}</div>
    <button class="listview_row_button" ng-click="deleteUser(u.id, $index)">Delete</button>
    <button class="listview_row_button" ng-click="showEditScreen(u.id, $index)">Edit</button>
</div>
</div>
<div id="user_new" class="new_user">
<button class="new_user_button" ng-click="showAddScreen()">Add user</button>
</div>

<div id="user_mod" class="user_form" ng-show="userModScreenIsVisible">
<form name="mod_user" novalidate>
    <input type="email" name="email" ng-model="user.email" placeholder="E-Mail" ng-disabled="emailFieldDisabled" required email-available/>
    <div class="user-help" ng-show="mod_user.email.$dirty && mod_user.email.$invalid">Invalid:
        <span ng-show="mod_user.email.$error.required">Please enter your email.</span>
        <span ng-show="mod_user.email.$error.email">This is not a valid email.</span>
        <span ng-show="mod_user.email.$error.checkingEmail">Checking email...</span>
        <span ng-show="mod_user.email.$error.emailAvailable">Email not available</span>
    </div>
    <br/>
    <input name="firstName" ng-model="user.firstName" placeholder="Firstname" required/>
    <div class="user-help" ng-show="mod_user.firstName.$dirty && mod_user.firstName.$invalid">Invalid:
        <span ng-show="mod_user.firstName.$error.required">Please enter your firstname.</span>
    </div>
    <br/>
    <input name="lastName" ng-model="user.lastName" placeholder="Lastname" required/>
    <div class="user-help" ng-show="mod_user.lastName.$dirty && mod_user.lastName.$invalid">Invalid:
        <span ng-show="mod_user.lastName.$error.required">Please enter your lastname.</span>
    </div>
    <br/>
    <input type="checkbox" name="setPassword" ng-disabled="passwordCheckboxDisabled" ng-show="passwordCheckboxVisible"/>
    <span class="password_checkbox" ng-show="passwordCheckboxVisible">Change password</span>
    <br ng-show="passwordCheckboxVisible"/>
    <input type="password" name="password" ng-model="password" placeholder="Password" ng-disabled="passwordFieldDisabled" ng-required="passwordFieldRequired" required/>
    <div class="user-help" ng-show="mod_user.password.$dirty && mod_user.password.$invalid">Invalid:
        <span ng-show="mod_user.password.$error.required">Please enter a password.</span>
    </div>
    <br/>
    <input type="password" name="passwordConfirm" ng-model="passwordConfirm" placeholder="Confirm Password" ng-disabled="passwordFieldDisabled" ng-required="passwordFieldRequired" required field-equal="password"/>
    <div class="user-help" ng-show="mod_user.passwordConfirm.$dirty && mod_user.passwordConfirm.$invalid">Invalid:
        <span ng-show="mod_user.passwordConfirm.$error.required">Please enter a password.</span>
        <span ng-show="mod_user.passwordConfirm.$error.fieldEqual">Passwords do not match.</span>
    </div>
    <br/>
    <button class="button" ng-click="hideUserModScreen()">Close</button>
    <button class="button" ng-click="updateUserDetails()" ng-disabled="mod_user.$invalid" ng-show="updateUserDetailsButtonIsVisible">Update</button>
    <button class="button" ng-click="saveUserDetails()" ng-disabled="mod_user.$invalid" ng-show="saveUserDetailsButtonIsVisible">Save</button>
</form>
</div>

控制器:

'use strict';

/*
* Controller to display and manipulate users.
*/
function UserCtrl($scope, User) {
// initialize as invisible
$scope.userModScreenIsVisible = false;
$scope.updateUserDetailsButtonIsVisible = false;
$scope.saveUserDetailsButtonIsVisible = false;
$scope.passwordCheckboxVisible = false;

// initialize as disabled or enabled
$scope.emailFieldDisabled = false;
$scope.passwordCheckboxDisabled = false;
$scope.passwordFieldDisabled = false;

// initialize required or not required
$scope.passwordFieldRequired = false;

// gather array index before opening edit
// screen (used in updateUserDetails method)
$scope.editIndex = null;

// display list with users
$scope.getList = function() {
    User.query(
        {}, //params
        function (data) { //success
            $scope.users = data.data;
        },
        function (data) { //failure
            console.log("Error occurred while getting list of users");
        });
}

// execute getList() when partial is loaded
$scope.getList();

// show edit screen if edit button is clicked
$scope.showEditScreen = function(id, index) {
    $scope.user = User.get({userId: id});
    $scope.editIndex = index;
    $scope.updateUserDetailsButtonIsVisible = true;
    $scope.userModScreenIsVisible = true;
    $scope.emailFieldDisabled = true;
    $scope.passwordCheckboxVisible = true;
    $scope.passwordFieldDisabled = true;
    $scope.passwordFieldRequired = false;
    $scope.passwordCheckboxDisabled = false;
    //console.log($scope.mod_user);
}

// show add screen if the add button is clicked
$scope.showAddScreen = function() {
    $scope.user = new User();
    $scope.saveUserDetailsButtonIsVisible = true;
    $scope.passwordCheckboxDisabled = true;
    $scope.passwordFieldRequired = true;
    $scope.userModScreenIsVisible = true;
    console.log($scope.mod_user);
}

// hide edit screen if close button is clicked
$scope.hideUserModScreen = function() {
    $scope.updateUserDetailsButtonIsVisible = false;
    $scope.saveUserDetailsButtonIsVisible = false;
    $scope.userModScreenIsVisible = false;
    $scope.emailFieldDisabled = false;
    $scope.passwordFieldDisabled = false;
    $scope.passwordFieldRequired = false;
    $scope.passwordCheckboxVisible = false;
    $scope.passwordConfirm = '';
    $scope.password = '';
    $scope.mod_user.$setPristine();
}

// update a user
$scope.updateUserDetails = function() {
    $scope.user.$update();
    angular.extend($scope.users[$scope.editIndex], $scope.user);
    $scope.editIndex = null;
    $scope.updateUserDetailsButtonIsVisible = false;
    $scope.userModScreenIsVisible = false;
    //console.log($scope.mod_user);
}

// save a new user
$scope.saveUserDetails = function() {
    $scope.user.$create();
    $scope.users.push($scope.user);
    $scope.saveUserDetailsButtonIsVisible = false;
    $scope.userModScreenIsVisible = false;
}

// delete a user
$scope.deleteUser = function(id, index) {
    User.delete({userId: id});
    $scope.users.splice(index, 1);
    $scope.userModScreenIsVisible = false;
}
}

指令:

'use strict';

/* Directives */


angular.module('myApp.directives', []).
directive('appVersion', ['version', function (version) {
    return function (scope, elm, attrs) {
        elm.text(version);
    };
}]).

/*
 * Validate if the email address is available.
 */
directive('emailAvailable', function($http) { // available
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, ctrl) {
            // push the validator on so it runs last.
            ctrl.$parsers.push(function(viewValue) {
                // set it to true here, otherwise it will not
                // clear out when previous validators fail.
                ctrl.$setValidity('emailAvailable', true);
                if(ctrl.$valid) {
                    // set it to false here, because if we need to check
                    // the validity of the email, it's invalid until the
                    // AJAX responds.
                    ctrl.$setValidity('checkingEmail', false);

                    // check if email is available or used
                    if(viewValue !== "" && typeof viewValue !== "undefined") {
                        $http.get('/api/user/email/' + viewValue + '/available')
                            .success(function(data, status, headers, config) {
                                ctrl.$setValidity('emailAvailable', true);
                                ctrl.$setValidity('checkingEmail', true);
                            })
                            .error(function(data, status, headers, config) {
                                ctrl.$setValidity('emailAvailable', false);
                                ctrl.$setValidity('checkingEmail', true);
                            });
                    } else {
                        ctrl.$setValidity('emailAvailable', false);
                        ctrl.$setValidity('checkingEmail', true);
                    }
                }
                return viewValue;
            });
        }
    };
}).

/*
 * Validate if two fields are equal (such as passwords match for example
 */
directive('fieldEqual', [function() {
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, ctrl) {
            ctrl.$parsers.push(function(viewValue) {
                ctrl.$setValidity('fieldEqual', true);
                if(ctrl.$valid) {
                    scope.$watch(attr.fieldEqual, function() {
                        var compareValue = this.last;
                        if (viewValue !== compareValue) {
                            ctrl.$setValidity('fieldEqual', false);
                            return undefined;
                        } else {
                            ctrl.$setValidity('fieldEqual', true);
                            return viewValue;
                        }
                    });
                }
            });
        }
    };
}]);
4

1 回答 1

3

似乎我对 $setPristine 所做的事情感到困惑。

我预计 $setPristine 不仅会将 $pristine 状态设置为 true,而且还会递归地清除我的表单字段。情况似乎并非如此。$setPristine 仅在全局和所有控件中将 $pristine 的状态设置为 true。

我一直在查看 Angularjs 页面上的 advancedForm 示例,并看到他们创建了一个 master 来预填充字段:

http://docs.angularjs.org/cookbook/advancedform

因此,作为解决方案,我刚刚创建了一个空主人:

http://jsfiddle.net/charms/AhGDC/24/

控制器

var $scope;
var app = angular.module('myapp', []);

function UserCtrl($scope) {
$scope.showField = true;
$scope.reset = function() {
    var master = { name: '' };
    $scope.temp = angular.copy(master);
    $scope.user_form.$setPristine();
}  
}

HTML

<div ng-app="myapp">
<div ng-controller="UserCtrl">
    <form name="user_form" novalidate>
        <input name="name" ng-model="temp.name" ng-show="showField" placeholder="Name" required/>
        <button class="button" ng-click="reset()">Reset</button>     
    </form>
    <p>
        Pristine: {{user_form.$pristine}}
    </p>
    <p>
    <pre>Errors: {{user_form.$error | json}}</pre>
    </p>
</div>
</div>

所以我想这是要走的路。如果有人有更好的解决方案来重置表单字段,那么很高兴听到它。

我认为 Angularjs 可能有一个更优雅的解决方案。还查看 setPristine 源并没有透露任何其他信息。

于 2013-04-02T22:57:50.257 回答