Chỉ thị AngularJS với các tùy chọn mặc định


145

Tôi mới bắt đầu với angularjs và đang nghiên cứu chuyển đổi một vài bổ trợ JQuery cũ thành các chỉ thị Angular. Tôi muốn xác định một tập hợp các tùy chọn mặc định cho chỉ thị (phần tử) của tôi, có thể được ghi đè bằng cách chỉ định giá trị tùy chọn trong một thuộc tính.

Tôi đã có một cái nhìn xung quanh về cách người khác đã làm điều này, và trong thư viện góc cạnh, ui.bootstrap.pagination dường như làm điều gì đó tương tự.

Đầu tiên tất cả các tùy chọn mặc định được xác định trong một đối tượng không đổi:

.constant('paginationConfig', {
  itemsPerPage: 10,
  boundaryLinks: false,
  ...
})

Sau đó, một getAttributeValuechức năng tiện ích được gắn vào bộ điều khiển chỉ thị:

this.getAttributeValue = function(attribute, defaultValue, interpolate) {
    return (angular.isDefined(attribute) ?
            (interpolate ? $interpolate(attribute)($scope.$parent) :
                           $scope.$parent.$eval(attribute)) : defaultValue);
};

Cuối cùng, điều này được sử dụng trong chức năng liên kết để đọc các thuộc tính như

.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
    ...
    controller: 'PaginationController',
    link: function(scope, element, attrs, paginationCtrl) {
        var boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks,  config.boundaryLinks);
        var firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true);
        ...
    }
});

Đây có vẻ như là một thiết lập khá phức tạp đối với một cái gì đó tiêu chuẩn như muốn thay thế một tập hợp các giá trị mặc định. Có cách nào khác để làm điều này là phổ biến không? Hoặc là bình thường khi luôn xác định một chức năng tiện ích như getAttributeValuevà phân tích các tùy chọn theo cách này? Tôi quan tâm để tìm hiểu những chiến lược khác nhau mà mọi người có cho nhiệm vụ chung này.

Ngoài ra, như một phần thưởng, tôi không rõ tại sao interpolatetham số được yêu cầu.

Câu trả lời:


108

Bạn có thể sử dụng compilechức năng - đọc thuộc tính nếu chúng không được đặt - điền chúng với các giá trị mặc định.

.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
    ...
    controller: 'PaginationController',
    compile: function(element, attrs){
       if (!attrs.attrOne) { attrs.attrOne = 'default value'; }
       if (!attrs.attrTwo) { attrs.attrTwo = 42; }
    },
        ...
  }
});

1
Cảm ơn! Vì vậy, bất kỳ suy nghĩ về lý do tại sao ui.bootstrap.paginationmọi thứ theo một cách phức tạp hơn? Đã nghĩ rằng nếu sử dụng hàm biên dịch thì mọi thay đổi thuộc tính được thực hiện sau đó sẽ không được phản ánh, nhưng điều này dường như không đúng vì chỉ có các mặc định được đặt ở giai đoạn này. Đoán phải có một số đánh đổi được thực hiện ở đây.
Ken Chatfield

3
@KenChatfield trong compilebạn không thể đọc các thuộc tính, cần được nội suy để nhận giá trị (có chứa biểu thức). Nhưng nếu bạn chỉ muốn kiểm tra nếu thuộc tính trống - nó sẽ hoạt động mà không có sự đánh đổi nào cho bạn (trước khi thuộc tính nội suy sẽ chứa chuỗi có biểu thức).
OZ_

1
Tuyệt diệu! Cảm ơn rất nhiều cho lời giải thích rõ ràng của bạn. Đối với những người đọc trong tương lai, mặc dù tiếp xúc với câu hỏi ban đầu, để giải thích về tham số 'nội suy' trong ui.bootstrap.paginationví dụ tôi đã tìm thấy ví dụ rất hữu ích này: jsfiddle.net/EGfgH
Ken Chatfield

Cảm ơn rất nhiều cho giải pháp đó. Lưu ý rằng nếu bạn cần linktùy chọn, bạn vẫn có thể trả về một chức năng trong compiletùy chọn của mình . doc ở đây
mneute 16/1/2015

4
Hãy nhớ rằng các thuộc tính đó cần các giá trị như chúng sẽ được truyền từ mẫu. Nếu bạn đang vượt qua một mảng, nó nên attributes.foo = '["one", "two", "three"]'thay vìattributes.foo = ["one", "two", "three"]
Dominik Ehrenberg

263

Sử dụng =?cờ cho thuộc tính trong khối phạm vi của lệnh.

angular.module('myApp',[])
  .directive('myDirective', function(){
    return {
      template: 'hello {{name}}',
      scope: {
        // use the =? to denote the property as optional
        name: '=?'
      },
      controller: function($scope){
        // check if it was defined.  If not - set a default
        $scope.name = angular.isDefined($scope.name) ? $scope.name : 'default name';
      }
    }
  });

4
=?có sẵn từ 1.1.x
Michael Radionov

34
Nếu thuộc tính của bạn có thể chấp nhận truehoặc falselàm giá trị, bạn sẽ (tôi nghĩ) muốn sử dụng ví dụ $scope.hasName = angular.isDefined($scope.hasName) ? $scope.hasName : false;thay thế.
Paul D. Chờ đợi

22
Lưu ý: nó chỉ hoạt động với ràng buộc hai chiều, ví dụ =?, nhưng không hoạt động với ràng buộc một chiều , @?.
Justus Romijn

20
cũng chỉ có thể được thực hiện trong mẫu: template: 'hello {{name || \ 'tên mặc định \'}}'
Vil

4
Giá trị mặc định nên được đặt trong bộ điều khiển hoặc trong linkhàm? Dựa trên sự hiểu biết của tôi, việc phân công trong thời gian linknên tránh một $scope.$apply()chu kỳ, không nên sao?
Augustin Riedinger

1

Tôi đang sử dụng AngularJS v1.5.10 và thấy preLinkhàm biên dịch hoạt động khá tốt để thiết lập các giá trị thuộc tính mặc định.

Chỉ là một lời nhắc nhở:

  • attrsgiữ các giá trị thuộc tính DOM thô luôn luôn là undefinedhoặc chuỗi.
  • scopegiữ (trong số những thứ khác) các giá trị thuộc tính DOM được phân tích cú pháp theo đặc tả phạm vi cách ly được cung cấp ( =/ </ @/ v.v.).

Đoạn trích rút gọn:

.directive('myCustomToggle', function () {
  return {
    restrict: 'E',
    replace: true,
    require: 'ngModel',
    transclude: true,
    scope: {
      ngModel: '=',
      ngModelOptions: '<?',
      ngTrueValue: '<?',
      ngFalseValue: '<?',
    },
    link: {
      pre: function preLink(scope, element, attrs, ctrl) {
        // defaults for optional attributes
        scope.ngTrueValue = attrs.ngTrueValue !== undefined
          ? scope.ngTrueValue
          : true;
        scope.ngFalseValue = attrs.ngFalseValue !== undefined
          ? scope.ngFalseValue
          : false;
        scope.ngModelOptions = attrs.ngModelOptions !== undefined
          ? scope.ngModelOptions
          : {};
      },
      post: function postLink(scope, element, attrs, ctrl) {
        ...
        function updateModel(disable) {
          // flip model value
          var newValue = disable
            ? scope.ngFalseValue
            : scope.ngTrueValue;
          // assign it to the view
          ctrl.$setViewValue(newValue);
          ctrl.$render();
        }
        ...
    },
    template: ...
  }
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.