2016-12-04 77 views
1

我正在使用ngRoute創建一個Angular單頁面應用程序。想要轉移到基於組件的版本。Angular 1.5組件通過ngRoute更新父控制器

問題是隔離範圍。我需要訪問主控制器的道具和方法。嘗試使用綁定但不起作用。我找不到這個問題。這個應用程序工作正常,不使用組件當我嘗試將主頁視圖更改爲組件時,它會崩潰。這些代碼的主要部分:

框架

<html ng-app="angularModule" > 
<body ng-controller="angularController as angCtrl" > 
    <div ng-show="angCtrl.user.isLoggedIn" >Sign Out</div> 
    <div ng-hide="angCtrl.user.isLoggedIn" cd-visible="angCtrl.showSignIn">Sign In</div> 
    <div id="contentLayer" class="contentLayer" ng-view ></div> 

網頁模板

<h1 class="pageLabel" >HomePage</h1> 
<blockquote>This can be anything. No bindings.</blockquote> 

angularController

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

app.directive ('cdVisible', 
    function() { 
     return function (scope, element, attr) { 
        scope.$watch (attr.cdVisible, 
         function (visible) { 
          element.css ('visibility', visible ? 'visible' : 'hidden'); 
         } 
        ); 
       }; 
    } 
); 

app.config ([ '$locationProvider', '$routeProvider', 
    function config ($locationProvider, $routeProvider) { 
     $locationProvider.hashPrefix ('!'); 
     $routeProvider 
     .when ('/sign-in', { 
      templateUrl: '/ng-sign-in', 
      controller:  signInController 
     }) 
     ... more routes 
     .when ('/home', { 
      template: '<home-page showSignIn="angCtrl.showSignIn" menuSelect="angCtrl.menuSelect" ></home-page>' 
     }) 
     .otherwise ('/home'); 
    } 
]); 

function homePageController() { 
    this.menuSelect ('Devices'); // this statement has no effect on angularController.menuSelection chrome shows it as an anonymous function 
    this.showSignIn = false; // this bombs: Expression 'undefined' in attribute 'showSignIn' used with directive 'homepage' is non-assignable! 
} 

app.component ('homePage', { 
    templateUrl: '/ng-homepage', 
    controller:  homePageController, 
    bindings: { 
     menuSelect: '&', 
     showSignIn: '=' 
    } 
}); 

app.controller ('angularController', [ '$http', '$window', '$location', 
    function ($http, $window, $location) { 
     var self = this; 
     this.user = { 
      "isLoggedIn":  false 
     }; 
     this.showSignIn = true; 
     this.menuSelection = ""; 
     this.errorMessage = ""; 
     this.menuSelect = 
      function (selection) { 
       self.menuSelection = selection; 
      }; 
     this.setUserData = 
      function (userData) { 
       self.user = userData; 
      }; 
     this.setShowSignIn = 
      function (show) { 
       self.showSignIn = show; 
      }; 
     this.menuSelect (''); 
     this.getUserData();  // I removed this for this post 
    } 
]); 

我添加了一個註釋來引發異常。主頁控制器嘗試更新angularController的模型。第一個沒有任何第二個拋出異常。我究竟做錯了什麼?

回答

2

首先showSignIn是一個原始的,因此角將處理它的方式與做showSignIn="7+2"完全相同。如果您需要在組件內修改該值,則應該使用具有showSignIn屬性的對象。

現在menuSelect是有點艱難,也許Chrome的控制檯顯示像

function (locals) { 
    return parentGet(scope, locals); 
} 

這是因爲你只是路過的參考angCtrl.menuSelect到組件。

爲了執行從內部homePageControllermenuSelect功能你必須做(在HTML):在組件控制器

<home-page menu-select="angCtrl.menuSelect(myMsg)"></home-page> 

然後調用它像這樣:

this.menuSelect({ myMsg:"Devices" }) 

HTML中的(myMsg)是對角度的調用以返回此引用,然後在執行過程中我們傳遞參數{ myMsg:"Devices" }以匹配我們剛剛做的引用中的參數。 您可以查看this answer,它解釋了更詳細的方法。

0

在閱讀您的答案的過程中,有一個錯誤跳到我身上:/ home路由的主頁組件應該使用kebab case show-sign-in menu-選擇屬性而不是lower-camelCase,如最初編碼。

你的建議都有效。謝謝。沒有組件,我使用原型繼承來訪問父範圍中的屬性和方法。由於JavaScript原型繼承的性質,修改父範圍中標量的唯一方法是在父範圍上調用setter方法。顯然這裏也有類似的情況。有關prototypal inheritance的更多信息。

這是一個概念驗證練習。我想測試自己從組件中更新父作用域中的屬性和對象的能力,以及在父作用域中執行方法。此示例更新標量在父範圍2不同的方式:

  1. 把它粘到一個對象,綁定到對象,並使用從所述組件對象引用它一樣與loginData.showSignIn布爾完成
  2. 在父範圍內構建一個setter方法並綁定到該方法,並使用menuSelect(實際上只是menuSelection的setter方法)從組件調用setter方法

並演示如何在調用函數時執行此操作。

最後的工作代碼爲:(網頁模板不改變)

框架

<html ng-app="angularModule" > 
<body ng-controller="angularController as angCtrl" > 
    <div ng-show="angCtrl.user.isLoggedIn" >Sign Out</div> 
    <div ng-hide="angCtrl.user.isLoggedIn" cd-visible="angCtrl.loginData.showSignIn">Sign In</div> 
    <div id="contentLayer" class="contentLayer" ng-view ></div> 

angularController

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

app.directive ('cdVisible', 
    function() { 
     return function (scope, element, attr) { 
        scope.$watch (attr.cdVisible, 
         function (visible) { 
          element.css ('visibility', visible ? 'visible' : 'hidden'); 
         } 
        ); 
       }; 
    } 
); 

app.config ([ '$locationProvider', '$routeProvider', 
    function config ($locationProvider, $routeProvider) { 
     $locationProvider.hashPrefix ('!'); 
     $routeProvider 
      .when ('/sign-in', { 
       templateUrl: '/ng-sign-in', 
       controller:  signInController 
      }) 
       ... more routes 
      .when ('/home', { 
       template: '<home-page login-data="angCtrl.loginData" menu-select="angCtrl.menuSelect(mySelection)" ></home-page>' 
      }) 
      .otherwise ('/home'); 
     } 
]); 

function homePageController() { 
    this.menuSelect ( { mySelection: 'Overview' }); 
    this.loginData.showSignIn = true; 
} 

app.component ('homePage', { 
    templateUrl: '/ng-homepage', 
    controller:  homePageController, 
    restrict:  'E', 
    bindings: { 
     menuSelect: '&', 
     loginData: '=' 
    } 
}); 

app.controller ('angularController', [ '$http', '$window', '$location', 
    function ($http, $window, $location) { 
     var self = this; 
     this.user = { 
      "isLoggedIn":  false 
     }; 
     this.loginData = { 
      "showSignIn":  false 
     }; 
     this.menuSelection = ""; 
     this.errorMessage = ""; 
     this.menuSelect = 
      function (selection) { 
       self.menuSelection = selection; 
      }; 
     this.setUserData = 
      function (userData) { 
       self.user = userData; 
      }; 
     this.setShowSignIn = 
      function (show) { 
       self.showSignIn = show; 
      }; 
     this.menuSelect (''); 
     this.getUserData();  // I removed this for this post 
    } 
]); 
相關問題