Angular 1.5组件通过ngRoute更新父控制器

时间:2016-12-04 06:36:34

标签: angularjs controller components ngroute angularjs-bindings

我正在使用ngRoute创建一个Angular单页面应用。想要转移到基于组件的版本。

问题是孤立的范围。我需要访问主控制器道具和方法。尝试使用绑定但不起作用。我找不到这个问题。此应用程序工作正常,不使用组件。当我尝试将主页视图更改为组件时,它会崩溃。这些是代码的主要部分:

框架

<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 个答案:

答案 0 :(得分:2)

首先showSignIn是一个基元,因此angular将以与showSignIn="7+2"完全相同的方式处理它。如果需要在组件内修改该值,则应使用具有showSignIn属性的对象。

现在menuSelect有点困难,可能是Chrome控制台显示类似

的内容
function (locals) {
    return parentGet(scope, locals);
} 

这是因为您只是将对angCtrl.menuSelect的引用传递给组件。

要从menuSelect内部执行homePageController函数,您必须执行(在HTML中):

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

然后在组件的控制器中调用它:

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

HTML中的(myMsg)是对angular的调用以返回此引用,然后在执行中我们传递参数{ myMsg:"Devices" }以匹配我们刚刚执行的引用中的参数。 您可以查看更详细解释的this answer

答案 1 :(得分:0)

在阅读你的答案的过程中,一个错误突然袭来我:/ home路线的主页组件应该使用烤肉串案例show-sign-in menu-select for attributes not came-camelCase,这是最初编码的。

你的建议都奏效了。谢谢。没有组件,我使用原型继承来访问父作用域中的属性和方法。由于javascript原型继承的性质,修改父作用域中的标量的唯一方法是在父作用域上调用setter方法。显然类似的东西在这里适用。有关javascript中prototypal inheritance的更多信息。

这是一个概念验证练习。我想测试我从组件更新父作用域中的属性和对象的能力,以及在父作用域中执行方法。此示例以不同的方式更新父作用域中的标量:

  1. 将其粘贴到一个对象中,绑定到该对象并使用该组件中的该对象引用它,就像使用loginData.showSignIn boolean
  2. 一样
  3. 在父作用域中构建一个setter方法并绑定到该作用域并从组件中调用setter,就像使用menuSelect一样(实际上只是menuSelection的setter)
  4. 并演示在执行此操作时调用函数。

    最终的工作代码是:(主页模板不会改变)

    <强> 框架

    <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
        }
    ]);