2015-04-20 125 views
0

我已經設置了一個指令,如下所示,它控制Flyout面板的打開和關閉,我希望可以公開地訪問彈出窗口的狀態(是否打開/關閉)父範圍,我看到一些使用這個服務,但它似乎冗長的使用服務,我的問題是我想知道是否有一個優雅的方式來設置變量附加到關閉事件的屬性?還是必須訪問父範圍?小提琴這裏http://jsfiddle.net/sjmcpherso/EbDRR/AngularJS從內部指令中更改屬性模型

<div class="page"> 
<button ng-click="openFlyout()">Bhttp://jsfiddle.net/sjmcpherso/EbDRR/#baseutton {{fly.flyoutOpen}}</button> 
<flyout foopen={{fly.flyoutOpen}}> 
    <button ng-click="close()">X</button> 
</flyout> 
</div> 



angular.module('myApp', []) 
.controller('MyController', function($scope) { 
     $scope.fly = {flyoutOpen:false}; 
     $scope.openFlyout = function(){ 
      $scope.fly.flyoutOpen = !$scope.fly.flyoutOpen; 
     } 
    }).directive('flyout', function() { 

    return { 
     restrict: 'AE', 
     link: function(scope, el, attr) { 

      close.bind('click', function() { 
       //Set fly.flyoutOpen via attr.foopen to false 
      }); 
      attr.$observe('foopen', function(value) {   
       console.log(typeof value); 
       if (value == "true") {      
        el.css('right', '0'); 
        console.log("left:"+value); 
       } else {         
        el.css('right', '-150px'); 
        console.log("right:"+value); 
       }  
      }); 
     } 
    }; 
}); 
+0

您是否在尋找這個http://jsfiddle.net/EbDRR/13/? –

+0

這真的是我想要避免的,我想保持指令和控制器儘可能獨立。即所以如果我將$ scope.fly.flyout的名稱更改爲$ scope.fly.isOpen我不需要更改指令中的任何內容 – sjm

回答

0

在我看來,這不是角的方式來改變指令父範圍。 儘管我也遇到了無法找到其他解決方案的情況,但我認爲我們應該儘可能避免這種方式。 在你的情況下,我相信你可以避免改變你的指令中的父範圍。

所以我的建議,你是...

  1. 在你的指令刪除close.bind('click'...

  2. 添加控制器的close功能,你可以改變的範圍值。(你也知道這樣會不會打破角原則可言。)

jsfiddle is here.

我希望這會幫助你。

+0

我的示例是真正指令的非常簡化版本,即指令中的其他功能需要改變彈出窗口打開狀態,並且儘可能地將指令封裝在指令內而不是控制器中,儘管彈出窗口也需要由獨立指令 – sjm

+0

來觸發。我可以建議另一種解決方案,如果你想實現只是如下, 1.封裝功能內的指令。 2.不要與父控制器共享範圍值。 3.不要使用服務。 還有什麼? – yazaki

+0

這聽起來像我後 – sjm

0

這很簡單。 您可以使用可用於雙向綁定的指令作用域。

<http://jsfiddle.net/EbDRR/14/> 

我在代碼中添加了「openclose」屬性。

+0

你會遇到問題;用布爾值(或其他標量),你的子範圍將會破壞原始值,並將其與父範圍斷開連接。如果要保持雙向綁定,您需要在子面上至少有一個點。 ' {{view.isOpen}} ' – Norguard

+0

提供的提琴可能在正確的軌道上,但我將如何關閉('click',function(){// close}) – sjm

0

看看這兩個例子;對不起他們都是一個尋呼機...
我試圖保持代碼的自包含的,這樣就可以在一個地方看到的所有的作品。通常,會有構建過程保持代碼和模板以及頁面的分離;不是很多,在這裏。

的好消息是,這些網頁應該沒有這麼多的服務器工作(作爲唯一的外部文件是角),這樣可以節省每一個作爲一個.html頁面,並從驅動器中打開它。


共享配置父母與孩子

<!doctype html> 


<html ng-app="myApp" ng-controller="MyController"> 
    <head> 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script> 
    <style> 
     page-flyout { display: block; } 
     page-flyout.expanded { background-color : grey; } 
    </style> 
    </head> 
    <body> 
    <main ng-controller="page-controller as page"> 
     <button ng-click="page.toggle()" 
     >{{ page.flyout.expanded ? "Hide":"Show" }} Flyout</button> 
     <page-flyout 
     view="page.flyout" 
     class="ng-class: {'expanded':page.flyout.expanded,'contracted':!page.flyout.expanded }" 
     ></page-flyout> 
    </main> 
    <script type="text/ng-template" id="components/page-flyout/page-flyout.html"> 
     <h4>I am {{ view.expanded ? "OPEN" : "CLOSED" }}</h4> 
     <button ng-click="flyout.close()" ng-hide="!view.expanded">&times;</button> 
    </script> 
    <script > 
    var app = initApp(); 
    initAngular(app); 


    function initAngular (MyApp) { 
     angular.module("myApp", ["pageFlyout"]); 
     angular.module("pageFlyout", []); 

     angular.module("myApp") 
     .controller("MyController", [MyApp.MyController]) 
     .controller("page-controller", [MyApp.PageController]); 

     angular.module("pageFlyout") 
     .controller("page-flyout-controller", ["$scope", MyApp.PageFlyoutController]) 
     .directive("pageFlyout", [function() { 
     return { 
      scope: { view: "=" }, 
      restrict: "AE", 
      replace: false, 
      controller: "page-flyout-controller", 
      controllerAs: "flyout", 
      templateUrl: "components/page-flyout/page-flyout.html" 
     }; 
     }]); 
    }; 

    function initApp() { 
     var MyApp = { 
     MyController: function MyController() { 

     }, 

     PageController: function PageController() { 
      var page = extend(this, { toggle: toggle, flyout: { expanded: false } }); 
      function toggle() { 
      var currentState = page.flyout.expanded; 
      page.flyout.expanded = !currentState; 
      } 
     }, 

     PageFlyoutController: function PageFlyoutController ($scope) { 
      var flyout = extend(this, { close: close }); 
      function close() { $scope.view.expanded = false; } 
     } 
     }; 
     function extend() { 
     var args = [].slice.call(arguments); 
     return angular.extend.apply(angular, args); 
     } 

     return MyApp; 
    } 
    </script> 
    </body> 
</html> 

我使用 「的PageController」 作爲外控制器之間;這個外部元素有一個toggle方法和一個flyout對象。
flyout對象有一個expanded屬性,僅此而已。
這是一個將在父和子之間共享的配置/狀態對象。父母不會知道任何關於孩子的事情,孩子不會知道父母的任何事情......
但是兩者都需要知道這個對象的結構;基本上,父母必須同意給孩子一個符合孩子需求的配置對象,如果它要使用孩子的服務。

在我的子範圍內,我將此對象稱爲view,它在我的指令聲明<page-flyout view="page.flyout">中提供。

的彈出按鈕有一個控制器,具有close方法,這臺view.expanded = false; 因爲父母和兩個份額孩子配置對象,因爲UI事件觸發的摘要進行檢查,這個工程和每個人的快樂......

嘗試一下,看看會發生什麼:彈出式html在一個完全不同的世界中,但按鈕仍然按照它應該做的事情操作,而且彈出式範圍內部和外部的所有文本都保持最新狀態...

...除了這不是那麼幹淨。分享某種可讀狀態將是一回事,但直接寫信給它並且從中讀取的兩個人可能會有點不同。


父控件國家,兒童定義事件,母公司實現事件處理

<!doctype html> 


<html ng-app="myApp" ng-controller="MyController"> 
    <head> 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script> 
    <style> 
     page-flyout { display: block; } 
     page-flyout.expanded { background-color : grey; } 
    </style> 
    </head> 
    <body> 
    <main ng-controller="page-controller as page"> 
     <button ng-click="page.toggle()" 
     >{{ page.flyout.expanded ? "Hide":"Show" }} Flyout</button> 
     <page-flyout 
     onclose="page.close()" 
     class="ng-class: {'expanded':page.flyout.expanded,'contracted':!page.flyout.expanded }" 
     ></page-flyout> 
    </main> 
    <script type="text/ng-template" id="components/page-flyout/page-flyout.html"> 
     <h4>I am {{ view.expanded ? "OPEN" : "CLOSED" }}</h4> 
     <button ng-click="flyout.close()">&times;</button> 
    </script> 
    <script > 
    var app = initApp(); 
    initAngular(app); 


    function initAngular (MyApp) { 
     angular.module("myApp", ["pageFlyout"]); 
     angular.module("pageFlyout", []); 

     angular.module("myApp") 
     .controller("MyController", [MyApp.MyController]) 
     .controller("page-controller", [MyApp.PageController]); 

     angular.module("pageFlyout") 
     .controller("page-flyout-controller", ["$scope", MyApp.PageFlyoutController]) 
     .directive("pageFlyout", [function() { 
     return { 
      scope: { onclose: "&" }, 
      restrict: "AE", 
      replace: false, 
      controller: "page-flyout-controller", 
      controllerAs: "flyout", 
      templateUrl: "components/page-flyout/page-flyout.html" 
     }; 
     }]); 
    }; 

    function initApp() { 
     var MyApp = { 
     MyController: function MyController() { 

     }, 

     PageController: function PageController() { 
      var page = extend(this, { 
      toggle: toggle, 
      close: close, 
      flyout: { expanded: false } 
      }); 

      function toggle() { 
      var currentState = page.flyout.expanded; 
      page.flyout.expanded = !currentState; 
      } 
      function close() { 
      page.flyout.expanded = false; 
      } 
     }, 

     PageFlyoutController: function PageFlyoutController ($scope) { 
      var flyout = extend(this, { close: close }); 
      function close() { $scope.onclose(); } 
     } 
     }; 
     function extend() { 
     var args = [].slice.call(arguments); 
     return angular.extend.apply(angular, args); 
     } 

     return MyApp; 
    } 
    </script> 
    </body> 
</html> 

我會救你一些狩獵;幾乎每條線都是100%。
其中重要的是在該指令:

return { 
    scope: { onclose: "&" } 
} 

...的符號意味着該屬性$scope.onclose是一種方法,這是對指令的聲明中定義。

果然,當你看看page-flyout聲明,你會發現<page-flyout onclose="page.close()">

現在$ scope.onclose不等於page.close();這麼多,因爲它等於function() { page.close(); }
這可能,而不是一個簡單的表達,父的範圍內:

<page-flyout onclose="page.flyout.expanded = false"> 
$scope.onclose = function() { page.flyout.expanded = false; }; 

,你甚至可以在這裏通過一個名爲PARAMS回你的父母表達/法(不必要的;閱讀了關於它的教程,但基本上你叫$scope.method(paramsObj),其中對象的鍵是一樣的,在執行的參數名。真的很方便的東西。

在我的情況

所以,我的彈出按鈕調用flyout.close(),我的控制器上的一個方法。我的控制器方法調用$scope.onclose();(我的viewmodel的東西和特定角度的粘合劑之間的分隔),$scope.onclose然後在母公司中調用page.close(),其設置page.flyout.expanded = false;

不錯。整齊。清潔。

孩子對父母一無所知,但是,我創建了一個父母可以訂閱的事件;在HTML中,不下。

其中一個問題,雖然。
如果您加載此頁面,您會注意到彈出窗口的文本不會更改,並且彈出窗口的關閉按鈕從不隱藏自身,這取決於彈出窗口是「打開」還是「關閉」。
原因很簡單。
孩子對父母或父母的數據一無所知。

這很好,但在這種情況下,這意味着儘管能夠關閉它本身就好,它永遠不會知道它是否在第一位打開(如果我在父範圍中使用ng-hide,這將解決問題,如果你不想讓它半開放)。

的解決方案,當然,是爲了給孩子一個共享對象,代表一個彈出的狀態...
我們以前去過那裏...... ......除了這一次,它是一個只讀對象(不保證,只是通過練習),並且您正在使用事件進行對話,並使用屬性進行談話。

真正的解決方案包括兩方面:在視圖中使用子視圖的只讀屬性,並創建父級可以掛鉤的事件,更新其模型(以及它返回給孩子在下一個美元摘要)。

然後,除了孩子定義的合同和父母保持的合同之外,任何人都不瞭解另一方。

+0

是的,這看起來好像會起作用,儘管指令的功能現在在呈現指令的控制器/頁面中幾乎毫無意義,除了允許你重用模板,這不是我之後的 – sjm

+0

或者,如果整個指令只做控制CSS定位,那麼可以用一個布爾值和一個'ng-樣式「屬性。這裏獲得的分離允許外部世界控制定位和配置,同時允許內部世界封裝其內部工作。只是碰巧你沒有內部。您可以選擇關閉菜單的項目列表,或打開子列表。你可以有一打擴展事件或只有一個。但容器上的CSS適用於位置唯一要求 – Norguard

0

我假設你想達到如下。

  1. 封裝指令中的特徵。
  2. 不與父控制器共享範圍值。
  3. 不使用服務。

我的想法是這樣的。

  1. 準備其是用於更新彈出面板元件封套的功能。(該功能完全僅在該指令包封。
  2. 實例化包裝並在指令代碼使用它獨立
  3. 實例化包裝後,指令通過oninit函數將其發送給父控制器。
  4. 收到包裝後,控制器可以使用它而不共享範圍

jsfiddle is here.

+0

我還沒有看到過像這樣的指令(用新的操作符而不是在鏈接中實例化)我會做一些研究並返回到此,Thanx – sjm

+0

I我很期待。請享用! :) – yazaki

相關問題