2013-03-23 36 views
7

Tôi đang cố triển khai xác thực biểu mẫu cho trường email. Validation nên làm như sau:Xác thực mẫu email cùng một lúc

  • Kiểm tra xem email đã được nhập qua thuộc tính cần thiết và hiển thị một thông báo nếu không có email đã được nhập
  • Kiểm tra nếu email có định dạng hợp lệ (dường như được thực hiện tự động mà không chỉ định một thuộc tính) và hiển thị một thông báo nếu định dạng là sai
  • Kiểm tra xem email là duy nhất trong một $ http.get gọi và hiển thị một tin nhắn trong trường hợp các email đã được tìm thấy và do đó không thể được sử dụng

Tôi muốn tin nhắn đầu tiên xuất hiện, nếu fie ld rỗng, thông điệp thứ hai xuất hiện nếu email không hợp lệ và thông báo thứ ba xuất hiện, nếu địa chỉ email được tìm thấy và do đó không phải là duy nhất tại một thời điểm.

Điều này có tác dụng nếu tôi chỉ thử thuộc tính "bắt buộc" nhưng ngay sau khi thêm thuộc tính chỉ thị có sẵn của email, nó không kiểm tra định dạng của email nữa và chỉ thị có sẵn qua email được thực thi cùng với thuộc tính bắt buộc. Cả hai thông báo đều bật lên nhưng tôi chỉ muốn người dùng nhìn thấy một thông báo tại một thời điểm.

Tôi đang sử dụng angularjs 1.1.3.

Ai đó có thể cho tôi biết tôi có thể làm gì sai không?

HTML

<div id="user_mod" class="mod_form" ng-show="userModScreenIsVisible"> 
<form name="mod_user" novalidate> 
    <input type="email" name="email" ng-model="user.email" placeholder="E-Mail" 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.emailAvailable">This email address is already taken.</span> 
    </div> 
</form> 

Chỉ

directive('emailAvailable', function($http) { // available 
    return { 
     require: 'ngModel', 
     link: function(scope, elem, attr, ctrl) { 
      ctrl.$parsers.unshift(function(viewValue) { 
       ctrl.$setValidity('emailAvailable', false); 
       if(viewValue !== "" && typeof viewValue !== "undefined") { 
        console.log("variable is defined"); 

        $http.get('/api/user/email/' + viewValue + '/available') 
         .success(function(data, status, headers, config) { 
          console.log(status); 
          ctrl.$setValidity('emailAvailable', true); 
          return viewValue; 
         }) 
         .error(function(data, status, headers, config) { 
          console.log("error"); 
          ctrl.$setValidity('emailAvailable', false); 
          return undefined; 
         }); 
       } else { 
        console.log("variable is undefined"); 
        ctrl.setValidity('emailAvailable', false); 
        return undefined; 
       } 
      }); 
     } 
    }; 
}); 

Trả lời

19

tôi thấy bạn đã giải quyết vấn đề của riêng mình, nhưng tôi nghĩ rằng tôi có thể cung cấp cho bạn một số lời khuyên/lời khuyên ở đây (Tôi hy vọng):

1) Tất cả những gì bạn cần làm để đảm bảo rằng trình xác thực của bạn đã được chạy af ter trình xác thực góc tích hợp sẵn là push() trên ctrl.$parsers, thay vì unshift().

2) Để trình xác thực của bạn chạy do trình xác thực chạy trước đó cho thấy trình duyệt không hợp lệ (ví dụ: Nếu bạn không muốn thực hiện cuộc gọi Ajax nếu trường này đã bị vô hiệu). Bạn chỉ cần kiểm tra ctrl.$invalid trong tuyên bố if bên trong trình xác thực của bạn.

3) Bạn sẽ muốn vô hiệu biểu mẫu của mình bằng một cuộc gọi riêng tới $setValidity() trước khi bắt đầu cuộc gọi ajax và sau khi nhận được cuộc gọi. Bằng cách này, biểu mẫu của bạn không hợp lệ cho đến khi AJAX trả về và cho biết nó có hợp lệ hay không.

4) Đây có thể là nhỏ, nhưng trừ khi bạn thêm ctrl.$formatter, giá trị ban đầu được gán cho đối tượng của bạn trong phạm vi $ sẽ không được xác thực trước khi chúng được ghi lên màn hình. Đây có thể là vấn đề nếu biểu mẫu của bạn được thêm động vào màn hình thông qua định tuyến, ng-lặp lại hoặc ng-kèm với dữ liệu được điền trước. Nói chung tất cả các trình xác nhận hợp lệ phải có một thành phần $ parser (xem -> mô hình) và một thành phần $ formatter (model -> view).

5) Một lời cảnh cáo. Hầu hết các trình xác nhận hợp lệ sẽ loại bỏ hoàn toàn giá trị từ mô hình nếu nó không hợp lệ. Vì bạn đang thực hiện cuộc gọi không đồng bộ, bạn sẽ phải trả lại viewValue ngay lập tức trong hàm phân tích cú pháp của mình. Thông thường, chức năng phân tích cú pháp sẽ trả về undefined nếu trường không hợp lệ, ngăn không cho dữ liệu không hợp lệ trong mô hình của bạn.

6) Vì trình xác nhận có trạng thái được duy trì trong đối tượng lỗi $ của bạn, bạn sẽ muốn xóa nó khi trình xác thực async ban đầu được nhấn. Xem bên dưới.

7) Lưu ý bên: Trong câu trả lời của bạn, tôi nhận thấy bạn đã trả về giá trị trong trình xử lý phản hồi ajax của bạn ... điều đó sẽ không làm gì cho bạn. Vì cuộc gọi không đồng bộ, bạn luôn quay trở lại không xác định từ trình phân tích cú pháp đó. Nó có cập nhật mô hình của bạn không? Tôi sẽ ngạc nhiên nếu điều đó xảy ra.

Sau đây là cách tôi muốn đã thay đổi chỉ thị ban đầu của bạn để làm cho nó làm việc như bạn có lẽ sẽ thích:

app.directive('emailAvailable', function($http, $timeout) { // available 
    return { 
     require: 'ngModel', 
     link: function(scope, elem, attr, ctrl) { 
      console.log(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); 

        // now do your thing, chicken wing. 
        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; 
      }); 

     } 
    }; 
}); 

And... of course, here is a plunker demonstrating it all

+0

Ahhhaaaaa, điều đó giải thích rất nhiều thứ. Vì vậy, các phương thức validator mặc định nằm trong phân tích cú pháp $ và nếu tôi unshift các phương thức xác nhận của tôi để bắt đầu mảng thay vì đẩy đến cuối mảng, các phương thức xác nhận mặc định sẽ bị overruled bởi phương thức của tôi. Ngoài ra, bạn đã mở một số nút trong tâm trí của tôi như thế nào xác nhận góc thực sự làm việc. Bạn có thực sự khám phá điều này bằng cách đọc tài liệu hướng dẫn góc không? Hay bạn có các nguồn khác? :) Cảm ơn anyway, giải thích chi tiết của bạn và ví dụ plunker làm cho tôi một người sử dụng angularjs hạnh phúc hơn. –

+0

Tôi đọc qua [nguồn của họ trên GitHub] (https://github.com/angular/angular.js/tree/master/src). ;) Sau đó, nó đã được một số thử nghiệm và lỗi. Tôi cũng đã viết một [bài blog trên đó] (http://www.benlesh.com/2012/12/angular-js-custom-validation-via.html). –

+0

Câu trả lời thứ hai mà tôi thấy, lần thứ hai tôi đã rất ấn tượng! – darethas

2

tôi đã giải quyết nó bằng cách loại bỏ các thuộc tính cần thiết và thêm một chỉ thị thứ hai gọi là email hợp lệ. Ngoài ra tôi đã gỡ bỏ phương thức setValidity trong mệnh đề khác của emailChỉ thị có sẵn.

HTML

<form name="mod_user" novalidate> 
    <input type="email" name="email" ng-model="user.email" placeholder="E-Mail" email-valid email-available/> 
    <div class="user-help" ng-show="mod_user.email.$dirty && mod_user.email.$invalid">Invalid: 
     <span ng-show="mod_user.email.$error.emailValid">Please enter a valid email address.</span> 
     <span ng-show="mod_user.email.$error.emailAvailable">This email address is already taken.</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> 

Chỉ

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

directive('emailAvailable', function($http) { // available 
    return { 
     require: 'ngModel', 
     link: function(scope, elem, attr, ctrl) { 
      ctrl.$parsers.unshift(function(viewValue) { 
       if(viewValue && viewValue.match(/[a-z0-9\-_][email protected][a-z0-9\-_]+\.[a-z0-9\-_]{2,}/)) { 
        console.log("variable is defined"); 

        $http.get('/api/user/email/' + viewValue + '/available') 
         .success(function(data, status, headers, config) { 
          console.log(status); 
          ctrl.$setValidity('emailAvailable', true); 
          return viewValue; 
         }) 
         .error(function(data, status, headers, config) { 
          console.log("error"); 
          ctrl.$setValidity('emailAvailable', false); 
          return undefined; 
         }); 
       } else { 
        console.log("variable is undefined"); 
        return undefined; 
       } 
      }); 
     } 
    }; 
}). 

directive('emailValid', function() { 
    return { 
     require: 'ngModel', 
     link: function(scope, elm, attrs, ctrl) { 
      ctrl.$parsers.unshift(function(viewValue) { 
       if (viewValue && viewValue.match(/[a-z0-9\-_][email protected][a-z0-9\-_]+\.[a-z0-9\-_]{2,}/)) { 
        // it is valid 
        ctrl.$setValidity('emailValid', true); 
        return viewValue; 
       } else { 
        // it is invalid, return undefined (no model update) 
        ctrl.$setValidity('emailValid', false); 
        return undefined; 
       } 
      }); 
     } 
    }; 
}); 
+0

+1 để cung cấp câu trả lời. Tại sao không chấp nhận nó là tốt. – Stewie

+0

Nó nói rằng tôi phải chờ 2 ngày trước khi tôi có thể chấp nhận nó :) –

+0

Tôi đã thêm một câu trả lời anyway. Bởi vì trong khi câu trả lời của bạn hoạt động (có thể, hãy xem câu trả lời của tôi). Tôi đã thấy một số sai sót. –

0

tôi mở rộng Bến Lesh trả lời một chút, bằng cách thêm một thời gian chờ quá rằng nó không kiểm tra mọi phím tắt

app.directive "uniqueEmail", ($http, $timeout) -> 
    restrict: "A" 
    require: "ngModel" 
    link: (scope, elem, attrs, ctrl) -> 
     return unless ctrl 
     q = null 
     ctrl.$parsers.push (viewValue) -> 
      ctrl.$setValidity 'unique-email', true 
      if ctrl.$valid 
       if viewValue? 
        $timeout.cancel(q) if q? 
        q = $timeout (-> 
         ctrl.$setValidity 'checking-unique-email', false 
         $http.get("#{endpoint}/emails/#{viewValue}/exists").success (exists) -> 
          ctrl.$setValidity 'checking-unique-email', true 
          ctrl.$setValidity 'unique-email', exists is 'false' 
         q = null 
         ) , attrs.checkDelay ? 1000 

      viewValue 
+0

Bạn nên trả lời bằng javascript nếu câu hỏi nằm trong javascript! – Endless

Các vấn đề liên quan