动态加载控制器和ng-include

时间:2013-07-23 05:18:33

标签: angularjs

目前我的应用程序有侧边栏,侧边栏根据用户选择的操作使用ng-include加载不同的html模板。这是一个与地图相关的应用,例如,如果用户选择“添加支持”按钮,则会使用add_leg.htmlng-include模板加载到侧边栏中:

// The Javascript code:
$scope.addLeg = function() {
    $scope.sidebar = true;
    $scope.sidebar_template = '/partials/legs/add_leg.html';    
}

// Simplified example of HTML:
<html>
<div ng-app="MyApp" ng-controller="MainCtrl">
    <a ng-click="addLeg()">Add Leg</a>
    <a ng-click="addRoute()">Add Route</a>
    <a ng-click="editLeg()">Edit Leg</a>
    <a ng-click="editRoute()">Edit Route</a>
    ...

    <div id="sidebar" ng-class="{'sidebar-hidden': sidebar == false}">
        <div ng-include src="sidebar_template"></div>
    </div>

    <google-map></google-map>
</div>

这一切都很好,并按预期工作,但目前我的应用程序只使用一个控制器(MainCtrl中的js/controllers.js),它开始变得非常混乱。我现在有很多方法,因为应用功能正在扩展。我想将控制器分成多个控制器,同时保留侧边栏功能。

我想让MainCtrl作为控制侧边栏模板加载的主控制器(通过更改指向文件目标的sidebar_template变量),我想让它控制一些全局地图相关的方法(比如从坐标中获取郊区名称等)。

我试图像这样分开它:

controllers/js/main.js - MainCtrl
controllers/js/legs.js - LegCtrl
controllers/js/routes.js - RouteCtrl

我希望LegCtrlRouteCtrl继承MainCtrl,以便我可以访问其范围和方法,这一切都很好。但现在的问题是如何根据所需的功能将控制器动态加载到侧边栏div上。最初我的所有方法都在MainCtrl中,并且在包围div的包围div上(参见上面的例子),所以这不是问题。

例如,假设我按下“添加支持”按钮,则需要在addLeg中调用LegCtrl,但应用中未加载LegCtrl,因此无法访问该方法。我可以将addLeg()保留在MainCtrl内,并让它更改sidebar_template变量以加载模板,但模板中的任何内容都无法正常工作,因为它正在{{1}内部调用方法现在。

我需要以某种方式动态加载侧边栏的LegCtrl div上的控制器,这可能是这样的:

ng-include

在上面的非工作示例中,您可以看到我想到的可能解决方案,但我需要// MainCtrl $scope.addLeg = function() { $scope.required_controller = LegCtrl; $scope.sidebar = true; $scope.sidebar_template = '/partials/legs/add_leg.html'; LegCtrl.addLeg(); } <div id="sidebar" ng-class="{'sidebar-hidden': sidebar == false}"> <div ng-include src="sidebar_template" ng-controller="{{required_controller}}"></div> </div> 作为实际的控制器函数,而不是对象(使LegCtrl工作) 。我还需要一些方法从ng-controller(也许使用广播?)addLeg拨打LegCtrl

如果有人能指出我正确的方向,那将是伟大的。对于这篇巨大的帖子感到抱歉,它需要一些解释才能使它变得连贯。希望这是有道理的。感谢。

更新:我想我找到了一个使用服务作为导航控件的解决方案(它会加载相关模板并向动态加载的新控制器广播一个事件来告诉它执行什么功能):

http://plnkr.co/edit/Tjyn1OiVvToNntPBoH58?p=preview

现在尝试测试这个想法,但广播MainCtrl.addLeg不起作用。我认为这是因为广播在模板加载之前触发。我怎样才能解决这个问题?这对我正在做的事情是一个很好的解决方案吗?

3 个答案:

答案 0 :(得分:12)

如果我已经正确理解了你可以尝试的是专门创建一个模板视图以创建一个新的腿。

从主控制器实现一些逻辑来显示模板

$scope.addLeg=function() {
   $scope.showAddLeg=true;
}

AddLeg模板视图将加载控制器,从而提供实际添加新支路的机制。模板看起来像

<script type="text/ng-template" class="template" id="addLegTemplate">
    <div ng-controller='LegsController'>
    <!--html for adding a new leg-->
    </div>
</script>

您可以使用ng-if + ng-include。

在主html中包含此模板
<div ng-if='showAddLeg'><div ng-include='addLegTemplate'/></div>

基本上,您可以创建多个视图并绑定到同一个控制器(但实例会有所不同)。在这种情况下,LegsController可以绑定到多个视图以支持完整功能。

答案 1 :(得分:5)

我喜欢这种数据驱动的场景,只是操纵模板中的行:

$scope.templates = [
    { name: 'include1.html', url: 'partials/include1.html' }
];
$scope.addTemplate = function(name, url) {
    $scope.templates.push({ name: name, url: url });
};

和标记:

<div ng-repeat="template in templates" ng-include="template.url"></div>

要添加或删除视图,只需修改模板即可!如果您需要更多控制器代码,则可以在include中包含指向脚本的链接。我想在部分视图本身中绑定到数据可能会有并发症,但是$ compile应该解决这些问题。

答案 2 :(得分:4)

我已经把你的plunkr演示分成了一个我相信你正在寻找的东西:http://plnkr.co/edit/whsjBT?p=preview

这演示了一个事件从一个控制器广播到另一个控制器之后第二个控制器(在我们的示例中为LegCtrl)通过ng-include加载并传递数据。

我使用ng-include中的$includeContentLoaded事件来延迟广播事件,直到加载add_leg.html的角度报告为止。另外我认为您使用$broadcast()的方式存在一些问题......第一个参数应该与$on()LegCtrl中使用的参数相同

另一个需要考虑的想法就是使用您的Navigation服务本身在控制器之间共享状态,如果这在您的方案中是合适的。