2013-07-24 81 views
42

我正在編寫一個指令,我需要觀察變更的父範圍。不知道如果我這樣做的首選方式,但它不是用下面的代碼工作:Angularjs監視父範圍的變化

scope.$watch(scope.$parent.data.overlaytype,function() { 
    console.log("Change Detected..."); 
    }) 

這是登錄窗口負載,但從來沒有一次,即使overlaytype改變。

如何查看overlaytype進行更改?

編輯:這裏是整個指令。不完全知道爲什麼我得到一個子範圍

/* Center overlays vertically directive */ 
aw.directive('center',function($window){ 
    return { 
    restrict : "A", 
    link : function(scope,elem,attrs){ 

     var resize = function() { 
     var winHeight = $window.innerHeight - 90, 
      overlayHeight = elem[0].offsetHeight, 
      diff = (winHeight - overlayHeight)/2; 
      elem.css('top',diff+"px"); 
     }; 

     var watchForChange = function() { 
     return scope.$parent.data.overlaytype; 
     } 
     scope.$watch(watchForChange,function() { 
     $window.setTimeout(function() { 
      resize(); 
     }, 1); 
     }) 

     angular.element($window).bind('resize',function(e){ 
     console.log(scope.$parent.data.overlaytype) 
     resize(); 
     }); 
    } 
    }; 
}); 
+0

很確定你不能看到任何超出當地$範圍的東西。但是,您可以將$ watch放在父$ scope和$ scope。$中,然後將更改廣播到子$ scope。 – Sharondio

+1

由於您的指令不會創建新的作用域,因此您應該能夠'scope。$ watch('data.overlaytype',...)'。這是一個[小提琴](http://jsfiddle.net/mrajcok/mHNws/),顯示這個工作。如果您認爲需要使用'$ parent',那麼我們需要查看更多HTML,以確定是否由HTML中的其他指令創建子或隔離範圍。 –

+0

@Sharondio但是我的子控制器通過擴展父控制器來運行。我不想在父級中寫入$ watch。我想擴展父代,以便父代不需要顯式地爲特定於子$ scope的情況定義$ watch。我想知道如何做到這一點。例如,子範圍取決於它在父範圍中所看到的變化,但並非總是如此,因爲其他子項並不一定依賴它,而且我不想將特定於兒童的行爲編碼爲父母。我想保持事物的模塊化,在孩子中特定孩子的行爲。 – trusktr

回答

7

你應該有你的孩子範圍數據性質,範圍使用父母和孩子之間的範圍原型繼承。

此外,第一個參數方法期望的是一個表達式或函數來評估,而不是一個變量的值,所以你應該發送它。

+0

Hrm,我根本沒有數據屬性。甚至不知道爲什麼我在這個指令中有一個子範圍,div在正常範圍內。有任何想法嗎? – wesbos

+0

哦,作爲第一個參數的功能就是它!我做了一個返回作用域的函數$ parent.data.overlaytype,它工作得很好。謝謝:) – wesbos

+0

@你不應該引用$父。您應該改爲創建一個可以通過父級範圍的模型或其某些屬性的變量。如果你顯示你的整個指令,這個答案可以被編輯來包含你應該如何通過這個對象。 – shaunhusain

19

我會建議你使用控制器之間的$廣播執行此,這似乎是更父/子控制器之間的通信的角度方式

這個概念很簡單,你在父腕錶的價值然後,控制器在修改時,您可以播放它,抓住它的子控制器

這裏有一個小提琴證明它:http://jsfiddle.net/DotDotDot/f733J/

父控制器的部分看起來像這樣:

$scope.$watch('overlaytype', function(newVal, oldVal){ 
    if(newVal!=oldVal) 
     $scope.$broadcast('overlaychange',{"val":newVal}) 
}); 

,並在子控制器:

$scope.$on('overlaychange', function(event, args){ 
    console.log("change detected") 
    //any other action can be perfomed here 
}); 

好點的這個解決方案,如果你想觀看其他孩子控制器的修改,你可以捕捉同一事件

玩得開心

編輯:我沒有看到你上次編輯,但我的解決方案也適用於該指令,我更新了以前的小提琴(http://jsfiddle.net/DotDotDot/f733J/1/

我修改你的指令,迫使它創建一個子範圍,創建一個控制器:

directive('center',function($window){ 
    return { 
    restrict : "A", 
    scope:true, 
    controller:function($scope){ 
     $scope.overlayChanged={"isChanged":"No","value":""}; 
     $scope.$on('overlaychange', function(event, args){ 
     console.log("change detected") 
     //whatever you need to do 

    }); 
    }, 
link : function(scope,elem,attrs){ 

    var resize = function() { 
    var winHeight = $window.innerHeight - 90, 
     overlayHeight = elem[0].offsetHeight, 
     diff = (winHeight - overlayHeight)/2; 
     elem.css('top',diff+"px"); 
    }; 
    angular.element($window).bind('resize',function(e){ 
    console.log(scope.$parent.data.overlaytype) 
    resize(); 
     }); 
    } 
    }; 
}); 
+0

工作得很好。謝謝! –

+0

@DotDotDot我們是否有任何使用BROADCAST而不是兒童級WATCHERS的性能改進? – Siva

2

好了,在這裏我花了一段是我的兩分錢,我喜歡的活動選項也不過:

更新小提琴 http://jsfiddle.net/enU5S/1/

的HTML

<div ng-app="myApp" ng-controller="MyCtrl"> 
    <input type="text" model="model.someProperty"/> 
    <div awesome-sauce some-data="model.someProperty"></div> 
</div> 

的JS

angular.module("myApp", []).directive('awesomeSauce',function($window){ 
    return { 
    restrict : "A", 
     template: "<div>Ch-ch-ch-changes: {{count}} {{someData}}</div>", 
     scope: {someData:"="}, 
     link : function(scope,elem,attrs){ 
     scope.count=0; 
     scope.$watch("someData",function() { 
      scope.count++; 
     }) 
    } 
    }; 
}).controller("MyCtrl", function($scope){ 
    $scope.model = {someProperty: "something here"); 
}); 

什麼,我在這裏展示的是你可以有兩個辦法從孩子和家長結合,但不要求孩子達到了它的變量是父母得到一個屬性。如果您在指令上添加新的父項,那麼達成事情的趨勢可能會變得瘋狂。

如果您在該框中鍵入,它將更新控制器上的模型,這反過來又被綁定到指令上的屬性,因此它將在指令中更新。在指令鏈接功能中,它有一個監視設置,所以無論何時,範圍變量改變它都會增加一個計數器。

查看更多關於分離範圍和使用= @或&這裏之間的區別:http://www.egghead.io/

+0

只是FYI,你不需要定義一個函數來觀察一個範圍屬性,並且你不需要'true'作爲第三個參數(這就是小提琴所具有的)。所以,你可以簡單地寫:'scope。$ watch('someData',function(){scope.count ++;});'。 –

+0

@MarkRajcok啊是的,我開始時使用了錯誤的屬性名稱,沒有看到更新,將修復我的小提琴。 Thx – shaunhusain

+1

偉大的解決方案+1使用'awesomeSauce' – dps

71

如果你想觀看父母範圍的屬性,你可以使用$watch方法從父範圍。

//intead of $scope.$watch(...) 
$scope.$parent.$watch('property', function(value){/* ... */}); 

編輯2016年 以上應該工作得很好,但它確實不是一個乾淨的設計。嘗試使用directivecomponent,並將其依賴關係聲明爲綁定。這應該會導致更好的性能和更清潔的設計。

+0

我正在嘗試這個,但我正在嘗試監視數組的變化,所以我使用'true'作爲深度監視的第三個參數,但仍然子範圍修改父範圍的數組並沒有任何反應。嗯.... – trusktr

+0

啊哈。對於一些尚未解釋的原因,這個應用程序神祕地在我的父母和孩子之間創造了一個額外的範圍,所以我必須做'$ scope。$ parent。$ parent。$ watch('property',function(值){/ * ... * /});'。當我找到原因時我會發表評論。 – trusktr

+1

好的,所以這是因爲'ngIf'等指令會創建子範圍,這與直觀相反。 – trusktr

5

如果您正在尋找在子範圍內觀察父範圍變量,則可以在$watch上添加true作爲第二個參數。這會觸發你的手錶每當你的對象被修改時

$scope.$watch("searchContext", function (ctx) { 
       ... 
      }, true); 
+0

不知道爲什麼這不是更多upvoted。這很簡單,完美的作品。 – ereOn