AngularJS 如何动态添加 HTML 并绑定到控制器

IT技术 javascript angularjs
2021-03-16 12:25:58

我刚刚开始使用 angularJS 并努力为我正在尝试做的事情找出合适的架构。我有一个单页应用程序,但URL 应始终保持不变我不希望用户能够导航到根目录之外的任何路由。在我的应用程序中,有一个主 div 需要托管不同的视图。当访问新视图时,我希望它接管主 div 中的显示。以这种方式加载的视图可以丢弃或保留在 DOM 中隐藏 - 我有兴趣了解每个视图如何工作。

我想出了一个粗略的工作示例来说明我正在尝试做的事情。 请参阅此 Plunk 中的工作示例。 基本上,我想将 HTML 动态加载到 DOM 中,并使标准的 angularJS 控制器能够连接到新的 HTML。有没有比使用我这里的自定义指令并使用 $compile() 连接到 angular 更好/更简单的方法?也许有类似路由器的东西,但不需要更改 URL 即可运行?

这是我目前使用的特殊指令(取自另一个 SO 帖子):

// Stolen from: http://stackoverflow.com/questions/18157305/angularjs-compiling-dynamic-html-strings-from-database
myApp.directive('dynamic', function ($compile) {
  return {
    replace: true,
    link: function (scope, ele, attrs) {
      scope.$watch(attrs.dynamic, function(html) {
        if (!html) {
            return;
        }
        ele.html((typeof(html) === 'string') ? html : html.data);
        $compile(ele.contents())(scope);
      });
    }
  };
});

谢谢,

安迪

5个回答

我会使用内置ngInclude指令。在下面的示例中,您甚至不需要编写任何 javascript。模板可以很容易地存在于远程 url 中。

这是一个工作演示:http : //plnkr.co/edit/5ImqWj65YllaCYD5kX5E?p=preview

<p>Select page content template via dropdown</p>
<select ng-model="template">
    <option value="page1">Page 1</option>
    <option value="page2">Page 2</option>
</select>

<p>Set page content template via button click</p>
<button ng-click="template='page2'">Show Page 2 Content</button>

<ng-include src="template"></ng-include>

<script type="text/ng-template" id="page1">
    <h1 style="color: blue;">This is the page 1 content</h1>
</script>

<script type="text/ng-template" id="page2">
    <h1 style="color:green;">This is the page 2 content</h1>
</script>
这是个好东西。非常感谢你!我需要花一些时间来学习内置的 angular 功能!
2021-04-21 12:25:58
2021-04-23 12:25:58

还有另一种方式

  1. 第 1 步:创建一个 sample.html 文件
  2. 第 2 步:创建一个带有一些 id=loadhtml 的 div 标签,例如: <div id="loadhtml"></div>
  3. 第 3 步:在任何控制器中

        var htmlcontent = $('#loadhtml ');
        htmlcontent.load('/Pages/Common/contact.html')
        $compile(htmlcontent.contents())($scope);
    

这将在当前页面中加载一个 html 页面

应该使用 AngularJs,而不是 jQuery
2021-04-21 12:25:58
@JonnyLin 这对我帮助很大:stackoverflow.com/questions/21370080/...
2021-04-22 12:25:58
有没有办法从工厂做到这一点?(因为我们无法从工厂访问 $scope ......)
2021-04-27 12:25:58
@mila 您怎么知道要在工厂中绑定到哪个“范围”?我通过在工厂中有一个名为 scope 的变量来完成此操作,并让 viewModel 在初始化时将 $scope 传递给工厂。
2021-05-03 12:25:58
@JonnyLin 我最终做了一些有点复杂的事情。在我的工厂中,我在需要时设置了“globalVariablesService.viewReset = true”。然后,在我的控制器中,我有一个用于 viewReset 的 $watch: $scope.$watch(function () { return globalVariables.viewReset }, function () { if (globalVariables.viewReset) { $http.get("/views/ social_template.html") .success(function(data) { $scope.social_content = data; });}}); ...在下一条评论中继续
2021-05-09 12:25:58

对于像我这样无法使用 angular 指令并且“卡在”在 angular 范围之外的人,这里有一些可能对您有所帮助的内容。

在网上和 angular doc 上搜索了几个小时后,我创建了一个编译 HTML 的类,将它放在一个目标中,并将它绑定到一个范围($rootScope如果$scope该元素没有

/**
 * AngularHelper : Contains methods that help using angular without being in the scope of an angular controller or directive
 */
var AngularHelper = (function () {
    var AngularHelper = function () { };

    /**
     * ApplicationName : Default application name for the helper
     */
    var defaultApplicationName = "myApplicationName";

    /**
     * Compile : Compile html with the rootScope of an application
     *  and replace the content of a target element with the compiled html
     * @$targetDom : The dom in which the compiled html should be placed
     * @htmlToCompile : The html to compile using angular
     * @applicationName : (Optionnal) The name of the application (use the default one if empty)
     */
    AngularHelper.Compile = function ($targetDom, htmlToCompile, applicationName) {
        var $injector = angular.injector(["ng", applicationName || defaultApplicationName]);

        $injector.invoke(["$compile", "$rootScope", function ($compile, $rootScope) {
            //Get the scope of the target, use the rootScope if it does not exists
            var $scope = $targetDom.html(htmlToCompile).scope();
            $compile($targetDom)($scope || $rootScope);
            $rootScope.$digest();
        }]);
    }

    return AngularHelper;
})();

它涵盖了我的所有案例,但如果您发现我应该添加的内容,请随时发表评论或编辑。

希望它会有所帮助。

如果页面动态加载,targetDom 是什么?
2021-04-18 12:25:58
这实际上是我试图修复的 :) 我应该每次加载 angular 以使我的动态加载 html 页面使用它。更多信息
2021-04-23 12:25:58
然后等待$targetDom加载,然后AngularHelper.Compile使用将插入 html 的 dom 和要插入的 html调用
2021-04-28 12:25:58
我收到错误:“未捕获的类型错误:$(...).html(...).scope is not a function”如果我给出一个“加载的”dom 的 id。
2021-05-15 12:25:58
您需要将 jQuery 元素传递给 Compile 方法,例如 AngularHelper.Compile($("body"), "<div>toto</div>")。此外,您的应用程序中是否正确加载了 angular ?i.imgur.com/tlQwPiM.png
2021-05-15 12:25:58

看看这个例子是否提供了任何说明。基本上,您配置一组路由并包含基于路由的部分模板。在主 index.html 中设置 ng-view 允许您注入这些部分视图。

配置部分如下所示:

  .config(['$routeProvider', function($routeProvider) {
    $routeProvider
      .when('/', {controller:'ListCtrl', templateUrl:'list.html'})
      .otherwise({redirectTo:'/'});
  }])

将局部视图注入主模板的入口点是:

<div class="container" ng-view=""></div>
感谢您的回答,尽管我认为这不会奏效,因为我有多个视图,但需要始终将 URL 保留在根目录下。
2021-04-17 12:25:58

我需要在加载几个模板后执行一个指令,所以我创建了这个指令:

utilModule.directive('utPreload',
    ['$templateRequest', '$templateCache', '$q', '$compile', '$rootScope',
    function($templateRequest, $templateCache, $q, $compile, $rootScope) {
    'use strict';
    var link = function(scope, element) {
        scope.$watch('done', function(done) {
            if(done === true) {
                var html = "";
                if(scope.slvAppend === true) {
                    scope.urls.forEach(function(url) {
                        html += $templateCache.get(url);
                    });
                }
                html += scope.slvHtml;
                element.append($compile(html)($rootScope));
            }
        });
    };

    var controller = function($scope) {
        $scope.done = false;
        $scope.html = "";
        $scope.urls = $scope.slvTemplate.split(',');
        var promises = [];
        $scope.urls.forEach(function(url) {
            promises.add($templateRequest(url));
        });
        $q.all(promises).then(
            function() { // SUCCESS
                $scope.done = true;
            }, function() { // FAIL
                throw new Error('preload failed.');
            }
        );
    };

    return {
        restrict: 'A',
        scope: {
            utTemplate: '=', // the templates to load (comma separated)
            utAppend: '=', // boolean: append templates to DOM after load?
            utHtml: '=' // the html to append and compile after templates have been loaded
        },
        link: link,
        controller: controller
    };
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>

<div class="container-fluid"
     ut-preload
     ut-append="true"
     ut-template="'html/one.html,html/two.html'"
     ut-html="'<my-directive></my-directive>'">
 
</div>