2013-07-23 37 views
1

我試圖建立一個自定義的複選框指令(能夠像我喜歡的樣式)不使用<input type="checkbox">。它應該像人們期望的那樣工作;更新模型應該更新視圖,點擊框應該更新模型,它應該聽取required指令(驗證應該工作)。自定義複選框指令的angularJS方式?

目前,我有以下指令,正好發揮預期:

'use strict'; 

angular.module('directives.checkbox', []) 
    .directive('checkbox', [function() { 
    return { 
     restrict: 'A', 
     require: 'ngModel', 
     replace: true, 
     template: '<span class="checkbox"></span>', 
     link: function (scope, elem, attrs, ctrl) { 
     elem.bind('click', function() { 
      scope.$apply(function() { 
      elem.toggleClass('checked'); 
      ctrl.$setViewValue(elem.hasClass('checked')); 
      }); 
     }); 

     ctrl.$render = function() { 
      if (!elem.hasClass('checked') && ctrl.$viewValue) { 
      elem.addClass('checked'); 
      } else if (elem.hasClass('checked') && !ctrl.$viewValue) { 
      elem.removeClass('checked'); 
      } 
     }; 
     } 
    } 
    }]); 

這只是一個CSS類checkbox併爲選中狀態另一個CSS類checked一個<span>。然而,使用jQuery來切換類並像我一樣更新視圖似乎並不像角度(或最佳實踐)。我寧願使用ng-classng-click指令,但這意味着我需要使用隔離範圍(以避免在同一頁上使用多個複選框時發生範圍狀態衝突)。出於某種原因,隔離示波器在ctrl上使角度停止呼叫$render()

有誰知道這是否是正確的方法,或者如果有更像角度的方法,仍然可以解決我的要求?

回答

1

首先我相信如果造型是你的問題,你肯定可以通過css自定義輸入而不是創建一個必須模仿輸入複選框的指令。這就是說,添加和刪除類的角度方式實際上包含在模板中,然後作爲表達式或作爲ngClass的參數。 你也可以通過在模板中加入ngClick來避免綁定。

app.directive('myCheckbox', function() { 
    return { 
    restrict: 'E', 
    replace: true, 
    transclude: true, 
    template: '<span class="checkbox" ng-class="{checked: isChecked}" ng-click="toggleMe()"></span>', 
    scope: { isChecked: '=?'}, 
    link: function(scope, elem, attrs) { 
     scope.isChecked = true; 

    scope.toggleMe = function() { 
     scope.isChecked = !(scope.isChecked); 
    } 
} 
}); 

Here is a little plunk來解釋我的意思

+0

我真的不明白我爲什麼被拒絕投票。我用一個例子提供了一個工作解決方案,而不使用angular和jquery。在任何情況下都應該以評論爲由反對投票。 – masimplo

+0

我沒有讓你失望,但你的解決方案的問題是多個複選框不能在同一個頁面上,他們將共享'isChecked'範圍變量。 – joscarsson

+0

嗨,謝謝你的評論。我沒有使用隔離範圍以防止增加混淆。我只是想演示如何在不使用jQuery的情況下操作dom。我現在已經更新了我的答案(和蹲伏者)以展示一個獨立的範圍。如果您不想綁定到外部作用域中的某個東西,綁定也是可選的。它也可以通過依賴ngModel值來完成。 – masimplo

0

$渲染功能則不會調用的複選框。我們可以監視模型更改並檢查元素狀態並相應地更新UI,而不是提供渲染功能。

以下是指令代碼。

var app = angular.module('RadioOrCheck', []); 
 

 
app.controller('MainCtrl', function($scope) { 
 
    $scope.name = 'World'; 
 
}); 
 

 
app.directive('radioOrCheck', radioOrCheckDirective); 
 

 
function radioOrCheckDirective() { 
 
    return { 
 
    require: 'ngModel', 
 
    restrict: 'A', 
 
    scope: false, 
 
    link: link 
 
    }; 
 

 
    function link(scope, element, attrs) { 
 
    element.addClass('hidden-input').wrap('<label/>'); 
 
    element.parent().addClass(attrs.type).append('<span/>'); 
 

 
    scope.$watch(attrs.ngModel, function updateUI() { 
 
     element.parent().toggleClass('checked', jQuery(element).is(':checked')); 
 
    }); 
 

 
    attrs.$observe('label', function(newLabel) { 
 
     element.parent().find('span').text(newLabel); 
 
    }); 
 
    } 
 
}
.hidden-input { 
 
    border: 0; 
 
    clip: rect(0 0 0 0); 
 
    height: 0; 
 
    margin: 0; 
 
    overflow: hidden; 
 
    padding: 0; 
 
    position: absolute; 
 
    width: 0; 
 
} 
 
.radio { 
 
    display: block; 
 
    cursor: pointer; 
 
    color: red; 
 
} 
 
.radio.checked { 
 
    color: green; 
 
} 
 
.checkbox { 
 
    display: block; 
 
    cursor: pointer; 
 
    color: red; 
 
} 
 
.checkbox.checked { 
 
    color: green; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
 
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" /> 
 
<br/> 
 
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" /> 
 
<br/> 
 
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" /> 
 
<br/> 
 
<br/> 
 
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="1" /> 
 
<br/> 
 
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="2" /> 
 
<br/> 
 
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="3" /> 
 
<br/>

Here is the working plunker。這裏的輸入字段是模擬默認的,CSS可以根據需要調整。

0

$複選框不會調用$ render函數。我們可以監視模型更改並檢查元素狀態並相應地更新UI,而不是提供渲染功能。

以下是指令代碼。

var app = angular.module('RadioOrCheck', []); 
 

 
app.controller('MainCtrl', function($scope) { 
 
    $scope.name = 'World'; 
 
}); 
 

 
app.directive('radioOrCheck', radioOrCheckDirective); 
 

 
function radioOrCheckDirective() { 
 
    return { 
 
    require: 'ngModel', 
 
    restrict: 'A', 
 
    scope: false, 
 
    link: link 
 
    }; 
 

 
    function link(scope, element, attrs) { 
 
    element.addClass('hidden-input').wrap('<label/>'); 
 
    element.parent().addClass(attrs.type).append('<span/>'); 
 

 
    scope.$watch(attrs.ngModel, function updateUI() { 
 
     element.parent().toggleClass('checked', jQuery(element).is(':checked')); 
 
    }); 
 

 
    attrs.$observe('label', function(newLabel) { 
 
     element.parent().find('span').text(newLabel); 
 
    }); 
 
    } 
 
}
.hidden-input { 
 
    border: 0; 
 
    clip: rect(0 0 0 0); 
 
    height: 0; 
 
    margin: 0; 
 
    overflow: hidden; 
 
    padding: 0; 
 
    position: absolute; 
 
    width: 0; 
 
} 
 
.radio { 
 
    display: block; 
 
    cursor: pointer; 
 
    color: red; 
 
} 
 
.radio.checked { 
 
    color: green; 
 
} 
 
.checkbox { 
 
    display: block; 
 
    cursor: pointer; 
 
    color: red; 
 
} 
 
.checkbox.checked { 
 
    color: green; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<div ng-app="RadioOrCheck"> 
 
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" /> 
 
<br/> 
 
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" /> 
 
<br/> 
 
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" /> 
 
<br/> 
 
<br/> 
 
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="1" /> 
 
<br/> 
 
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="2" /> 
 
<br/> 
 
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="3" /> 
 
<br/> 
 
</div>

Here is the working plunker。這裏的輸入字段是模擬默認的,CSS可以根據需要調整。