Angularjs动态添加控制器

时间:2016-02-17 20:08:49

标签: javascript html angularjs single-page-application

看起来这几个问题已经问了好几次,但没有正确答案。

我的情况:我正在使用ajax将模板(带有html和脚本)init加载到div(由于某种原因不使用angular routing temple)。

index.html(主要)

<!DOCTYPE html>
<html ng-app="app" ng-controller="AppCtrl">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Web</title>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
    </head>
    <body>
        <div class="container body-content">
            <div class="dynamic-content" >
                <!-- Loading content Here -->
            </div>
            <button ng-click="loadTemplate()">Load Template</button>
        </div>

        <script>
            angular.module('app', [])
            .controller('AppCtrl', function ($scope) {
                $scope.someData = {};
                $scope.loadTemplate = function() {
                    ....
                    //AJAX to get the templet.html
                    //and load it into .dynamic-content
                    //then applying scope();                  
                }
            });
        </script>
    </body>
</html>

template.html(模板)

<div ng-controller="TempCtrl">
    <h2>About</h2>
    <h3>{{total}}</h3>
    <p>Testing the total</p>
    <button ng-click="update()">Update</button>
</div>

<script>
    console.log('begin')
    angular.module('app')
    .controller('TempCtrl', function ($scope) {
        $scope.total = 0;
        console.log('inside')
        $scope.update = function () {
            $scope.total += 1;
        };
    });
    console.log('end')
</script>

当我点击按钮Load Template时,它会将template.html文件加载到容器中,但我收到错误

  

错误:[ng:areq]参数'TempCtrl'不是函数,未定义

虽然它被添加到app控制器。

如何动态添加控制器并使其与动态html节点一起使用

DEMO HERE https://plnkr.co/edit/EAa9Md36hDzpQ1BgIQKg?p=preview

3 个答案:

答案 0 :(得分:6)

此博客描述了如何摆弄角度以强制它在引导后加载其他控制器:

http://www.bennadel.com/blog/2553-loading-angularjs-components-after-your-application-has-been-bootstrapped.htm

当然,这完全不受支持,并且可以随时更改角度来打破。

但是,这是使用此方法的代码的更新版本:

var app = angular.module('app', [])
app.config(
  function($controllerProvider, $provide, $compileProvider) {
    // Since the "shorthand" methods for component
    // definitions are no longer valid, we can just
    // override them to use the providers for post-
    // bootstrap loading.
    console.log("Config method executed.");
    // Let's keep the older references.
    app._controller = app.controller;
    app._service = app.service;
    app._factory = app.factory;
    app._value = app.value;
    app._directive = app.directive;
    app.controller = function(name, constructor) {
      console.log("controller...");
      console.log(name);
      console.dir(constructor);
      $controllerProvider.register(name, constructor);
      return (this);
    };
    // Provider-based service.
    app.service = function(name, constructor) {
      $provide.service(name, constructor);
      return (this);
    };
    // Provider-based factory.
    app.factory = function(name, factory) {
      $provide.factory(name, factory);
      return (this);
    };
    // Provider-based value.
    app.value = function(name, value) {
      $provide.value(name, value);
      return (this);
    };
    // Provider-based directive.
    app.directive = function(name, factory) {
      $compileProvider.directive(name, factory);
      return (this);
    };
  });
app.controller('AppCtrl', function($scope, $http, $compile) {
  $scope.someData = {};
  $scope.loadTemplate = function() {
    $http.get("template.html")
      .then(function(r) {
        // load in the html, including the script, which will be executed
        $(".dynamic-content").html(
          r.data
        );
        // compile the loaded html into an actual template and put it back where it was
        $(".dynamic-content").html($compile($(".dynamic-content").html())($scope));
      })
  }
});

请注意,我使用jQuery将HTML放入DOM中,导致脚本执行,然后将DOM从DOM中取出以便可以编译,之后我再次将它放回DOM中。 / p>

此外,您的template.html中还有一个未定义的变量,因此我将其更新为:

<script>
    console.log('begin')
    angular.module('app')
    .controller('TempCtrl', function ($scope) {
        $scope.total = 0;
        console.log('inside')
        $scope.update = function () {
            $scope.total += 1;
        };
    });
    console.log('end')
</script>

<div ng-controller="TempCtrl">
    <h2>About</h2>
    <h3>{{total}}</h3>
    <p>Testing the total</p>
    <button ng-click="update()">Update</button>
</div>

这是一个有效的插件:http://plnkr.co/edit/cB5N05

答案 1 :(得分:2)

更新了Dave's示例,其中包含角度组件支持

app.config(
  function ($controllerProvider, $provide, $compileProvider) {

    var app = angular.module('app');

    // Let's keep the older references.
    app._controller = app.controller;
    app._service = app.service;
    app._factory = app.factory;
    app._value = app.value;
    app._directive = app.directive;
    app._component = app.component;

    // Provider-based controller.
    app.controller = function (name, constructor) {
        $controllerProvider.register(name, constructor);
        return ( this );
    };
    // Provider-based service.
    app.service = function (name, constructor) {
        $provide.service(name, constructor);
        return ( this );
    };
    // Provider-based factory.
    app.factory = function (name, factory) {
        $provide.factory(name, factory);
        return ( this );
    };
    // Provider-based value.
    app.value = function (name, value) {
        $provide.value(name, value);
        return ( this );
    };
    // Provider-based directive.
    app.directive = function (name, factory) {
        $compileProvider.directive(name, factory);
        return ( this );
    };
    // Provider-based component.
    app.component = function (name, options) {
        $compileProvider.component(name, options);
        return ( this );
    };

});

答案 2 :(得分:0)

尝试在index.html中加载模板控制器,而不是在template.html中加载模板控制器,这在标记查找时已经存在。 在index.html脚本部分:

  angular.modules('app', [])
        .controller('AppCtrl', function ($scope) {
            $scope.someData = {};
            $scope.loadTemplate = function() {
                ....
                //AJAX to get the templet.html
                //and load it into .dynamic-content
                //then applying scope();                  
            }
        }).controller('TempCtrl', function ($scope) {
    $scope.total = 0;
    console.log('inside')
    $scope.update = function () {
        total += total;
    };
});

编辑: 这是因为有多个引用app模块的JS文件会很方便,这样每个文件都拥有一个控制器。