2013-12-12 31 views
1

當我將控制器中與DOM有關的代碼移動到指令時,我有一個ng類初始化問題。 短,這裏是一些代碼:ng-repeat中的angularjs:指令和ng類初始化

view.html

<div ng-repeat="foo in foos" ng-click="rowClick($index)> 
    <div ng-class="changeOpacity($index)> 
     <span>{{foo.title}}</span> 
     <span>{{foo.name}}</span> 
     <span>{{foo.date}}</span> 
     ... 
     // some div with hidden content. Show when clicking on the div 
    </div> 
<div> 

controller.js

$scope.rowClick = function (idx) { 
    // unfold the clicked div to show content 
}; 
$scope.changeOpacity = function (idx) { 
    if (this is the div clicked) { 
     return {dark: true}; 
    } else { 
     return {light: true}; 
} 

所以當我有DIV的列表。當我點擊一個div時,除了這個之外,其他所有div都會變暗。

當$ scope.rowClick和$ scope.changeOpacity在我的控制器中時,一切正常。

當我移動rowClick和changeOpcaity的指令:

myBar.js

myApp.directive('myBar', function() { 
    ... 
    return { 
     restrict:'A', 
     link: function (scope, element) { 
      element.bind('click', function() { 
       ... 
       same code from rowClick 
       ... 
       scope.changeOpacity = function() { 
        ... 
        same code from changeOpacity 
       } 
       scope.$apply(); 
      } 
     }), 
     changeOpacity: function() { 
      ... 
      return {light: true} // for all divs 
     } 
    } 
}); 

現在我view.html是類似的東西:

<div ng-repeat="foo in foos" ng-click="rowClick($index) my-bar> 
    <div ng-class="changeOpacity($index)> 
     <span>{{foo.title}}</span> 
     <span>{{foo.name}}</span> 
     <span>{{foo.date}}</span> 
     ... 
     // some div with hidden content. Show when clicking on the div 
    </div> 
<div> 

但現在divs不會再用ng-class進行初始化了。我必須在每個div上單擊一次來初始化它,並使用監聽點擊的鏈接功能。

如何在指令內初始化ng-class?

Thanx。

回答

3

問題是,您只需在點擊後將changeOpacity函數放入您的範圍。在鏈接功能中這樣做:

link: function (scope, element) { 
    scope.changeOpacity = function() { 
     ... 
     same code from changeOpacity 
    } 
} 

使其成爲「指令對象」的字段不起作用。

但是,在我看來,使用模型屬性來指示元素是否處於活動狀態並在ng-click屬性中更改此屬性會更優雅。然後您可以參考ng-class指令中的該屬性。

事情是這樣的:

<div ng-repeat="foo in foos" ng-click="foo.active = true> 
    <div ng-class="{light: active, dark: !active }> 
     <span>{{foo.title}}</span> 
     <span>{{foo.name}}</span> 
     <span>{{foo.date}}</span> 
     <div ng-show="foo.active"> 
      // some div with hidden content. Show when clicking on the div 
     </div> 
</div> 

+0

肯定這一塊做的另一種方法。很容易嘗試和jQuery的一切,但在角度上,你應該只改變你的**模型**,讓角度改變你的UI。我可能提供的代碼中的一個改進是ng-click應該在範圍上調用一個方法,並將'foo'作爲參數,以便除了所點擊的那個之外,還可以使所有其他'foos'變暗。 – Hylianpuffball

2

ng-repeat創建陣列中的每個項目的子範圍。這意味着ng-repeat內的指令範圍將成爲子範圍。因此,你可以對孩子的範圍直接設置屬性,並使用ng-classng-show

下面是根據ng-click處理

HTML

<div ng-repeat="foo in foos" ng-click="rowClick($index)" my-directive parent-array="foos"> 
    <div ng-class="{activeClass: foo.isActive}" class="item"> 
     <span>{{foo.name}}</span> 
     <div ng-show="foo.isActive">Hidden content {{$index+1}}</div> 
    </div> 
</div> 

指令

指令切換狀態非常基本的例子
app.directive('myDirective',function(){ 
    return function(scope,elem,attrs){ 
     /* ng-repeat adds properties like `$first` , `$last` that can be helpful*/ 
     /* set default first element active*/ 
     if(scope.$first){ 
     scope.foo.isActive=true; 
     } 
     var parentArray=scope[attrs.parentArray]; 
     /* update active state across array*/ 
     scope.rowClick=function(idx){ 
     angular.forEach(parentArray,function(item, index){ 
      item.isActive = idx==index 
     }) 
     } 
    } 
    }) 

DEMO

下面是在父範圍存儲currSelected項目(控制器)

app.directive('myDirective',function(){ 
    return function(scope,elem,attrs){ 

     /* set default first element active*/ 
     if(scope.$first){ 
     scope.foo.isActive=true; 
     scope.$parent.currSelected=scope.foo 
     } 

     /* reset previous activeitem and make item clicked the active one*/ 
     scope.rowClick=function(item){ 
     scope.$parent.currSelected.isActive=false 
     scope.$parent.currSelected=item; 
     item.isActive=true 
     } 
    } 
    }) 

DEMO

+0

贊成第一種方法,但我會建議反對第二種方法;訪問$ parent幾乎總是做錯角度的錯誤方法。你給的第一個例子既清潔又簡單。 – Hylianpuffball

+0

@Hylianpuffball同意,服務更好...被放在這裏主要是爲了瞭解範圍。太多解釋包括一個服務店這個帖子以及。而且我也希望遠離分散的範圍 – charlietfl