一个Angular UI Router状态共享范围中的两个视图

时间:2014-02-20 09:54:57

标签: angularjs angular-ui angular-ui-router

我是AngularUI路由器的新手,并希望将它用于以下场景:

所有网页共有的 包括一个顶部导航栏,其中包含右侧带有按钮的菜单,以及填充下方空间的内容部分。该页面有几个页面,我映射到UI路由器状态(第1页,第2页,...)。每个页面都有自己的菜单项和自己的内容。 菜单需要与内容共享范围,因为它们相互作用(例如,保存按钮在内容中提交表单,只有在表单有效时才应启用它。)

mockup

HTML粗略如下:

<body>
    <nav class="...">
        <h1>my site</h1>
        <div>MENU SHOULD GO HERE</div>
    </nav>
    <div class="row">
        <div class="column ...">
            CONTENT SHOULD GO HERE
        </div>
    </div>        
</body>

现在,我正在为每个州使用两个并行视图和两个控制器。但这样,两个示波器/控制器无法互动。

那你怎么做到这一点?

2 个答案:

答案 0 :(得分:22)

$ scope不是模型,它是对模型的引用,介于数据和介质之间。风景。如果两个或更多控制器中的$ scope需要共享一个模型/状态/数据,则通过注册角度服务来使用单个对象实例。可以将一个服务/工厂注入到任意数量的控制器中,然后一切都可以解决这个问题。

下面是一个工厂的演示,它连接了navbar&amp;中的$ scopes。使用ui-router http://plnkr.co/edit/P2UudS?p=preview的主体(仅限左侧标签)

ui-router(viewC是导航栏):

$stateProvider
.state('left', {
  url: "/",
  views: {
    "viewA": {
      controller: 'LeftTabACtrl',
      template: 'Left Tab, index.viewA <br>' +
                '<input type="checkbox" ng-model="selected2.data" />' +
                '<pre>selected2.data: {{selected2.data}}</pre>'
    },
    {...},
    "viewC": {
      controller: 'NavbarCtrl',
      template: '<span>Left Tab, index.viewC <div ui-view="viewC.list"></div>' +
                '<input type="checkbox" ng-model="selected.data" />' +
                '<pre>selected.data: {{selected.data}}</pre></span>'
    }
  }
})

工厂&amp;控制器:

app.factory('uiFieldState', function () {
    return {uiObject: {data: null}}
});

app.controller('NavbarCtrl', ['$scope', 'uiFieldState', '$stateParams', '$state',
    function($scope, uiFieldState, $stateParams, $state) {
        $scope.selected = uiFieldState.uiObject;
    }
]);

app.controller('LeftTabACtrl', ['$scope', 'uiFieldState', '$stateParams', '$state',
    function($scope, uiFieldState, $stateParams, $state) {
        $scope.selected2 = uiFieldState.uiObject;
    }
]);

如您所见,工厂对象{uiObject: {data: null}}通过uiFieldState&amp;注入到控制器中。那么它只是$scope.selected = uiFieldState.uiObject;用于将工厂连接到范围ng-model="selected.data" .`

答案 1 :(得分:6)

您应该使用:

$on and $emit

发送控制器,用于发送数据。

angular.module('MyApp').controller('MyController', ['$scope', '$rootScope', function ($scope, $rootScope){

  $rootScope.$emit('SomeEvent', data);
}]);

如何以一种安全的方式实现$ rootScope的示例,以便在使用后销毁和修复内容:

angular
.module('MyApp')
.config(['$provide', function($provide){
    $provide.decorator('$rootScope', ['$delegate', function($delegate){

        Object.defineProperty($delegate.constructor.prototype, '$onRootScope', {
            value: function(name, listener){
                var unsubscribe = $delegate.$on(name, listener);
                this.$on('$destroy', unsubscribe);
            },
            enumerable: false
        });


        return $delegate;
    }]);
}]);

控制器包含应该处理的数据。

angular.module('MyApp')
.controller('MySecondController', ['$scope', function MyController($scope) {

        $scope.$onRootScope('SomeEvent', function(event, data){
            console.log(data);
        });
    }
]);

您可以传入$ rootScope,而不是使用我们在配置中定义的$ scopes方法$ onRootScope。但是,这不是使用$ emit和$ onRootScope的推荐方法。

您可以使用$ broadcast,而不是使用$ emit。但是,随着应用程序的增长,这会给您带来非常大的性能问题。因为它通过所有控制器冒泡数据。

如果您的控制人是父母和孩子,他们不必使用$ rootScope。

以下是$ emit和$ broadcast:jsFiddle

之间差异的示例

他们的确是性能差异:

enter image description here