30

目前我有一个有侧边栏的应用程序,侧边栏ng-include根据用户选择的操作加载不同的 html 模板。这是一个与地图相关的应用程序,例如,如果用户选择“添加腿”按钮,它将add_leg.html使用以下命令将模板加载到侧边栏中ng-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>

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

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

我试图像这样拆分它:

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

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

例如,假设我按下“添加腿”按钮,它将需要调用addLegLegCtrlLegCtrl没有加载到应用程序上,因此它无权访问该方法。我可以保留addLeg()在内部MainCtrl,并让它更改sidebar_template变量以加载模板,但模板中的任何内容都不起作用,因为它正在从内部调用方法LegCtrl

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

// 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(也许使用广播?)。LegCtrlMainCtrl.addLeg

如果有人能指出我正确的方向,那就太好了。很抱歉这篇巨大的帖子,它需要一些解释才能使其连贯。希望这是有道理的。谢谢。

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

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

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

4

3 回答 3

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可以绑定到多个视图以支持完整的功能。

于 2013-07-23T05:56:40.283 回答
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 应该可以解决这些问题。

于 2014-07-04T15:39:05.377 回答
4

我已经将您的 plunkr 演示分叉成一个我相信您正在寻找的演示: http ://plnkr.co/edit/whsjBT?p=preview

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

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

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

于 2013-08-03T08:09:06.577 回答