html - AngularJS 动态添加到页面
问题描述
我们在电子浏览器中有这个 AngularJS SP 应用程序(智能镜像),它具有用户可创建的扩展。
扩展是使用角度指令并使用控制器和服务的 html 小片段。
要安装扩展,必须编辑主页并插入用于控制器和服务功能的脚本标签以及<div ng-include= ...>
用于 HTML 片段的
硬编码这个单页应用程序效果很好。
但我想向这个应用程序(开源)添加功能以某种方式动态加载这些元素......
将标签添加到 dom 有效,但未正确处理。在运行脚本(来自插入的标签)之前处理 HTML,当 ng-include 插入 HTML 片段时,控制器尚未定义......
正文(硬编码位置的扩展被注释掉)
<body ng-controller="MirrorCtrl" ng-cloak>
<div class="top">
<div class="top-left">
<!-- <div ng-include="'plugins/datetime/index.html'"></div>
<div ng-include="'plugins/calendar/index.html'"></div> -->
</div>
<div class="top-right">
<!-- <div ng-include="'plugins/weather/index.html'"></div>
<div ng-include="'plugins/traffic/index.html'"></div>
<div ng-include="'plugins/stock/index.html'"></div>
<div ng-include="'plugins/tvshows/index.html'"></div>
<div ng-include="'plugins/ha-display/index.html'"></div> -->
</div>
</div>
...
...
<script src="filename.service"/>
<script src= filename.controller"/>
</body>
日历扩展 html(插入页面的特定 div 区域)
<ul ng-controller="Calendar" class="calendar fade" ng-show="focus == 'default'" ng-class="config.calendar.showCalendarNames ? 'show-calendar-names' : ''">
<li class="event" ng-repeat="event in calendar" ng-class="(calendar[$index - 1].label != event.label) ? 'day-marker' : ''">
<div class="event-details">
<span class="day">
<span ng-bind="event.startName"></span>
<span ng-if="event.startName != event.endName"> - <span ng-bind="event.endName"></span></span>
</span>
<div class="details calendar-name" ng-bind="event.calendarName"></div>
<span class="summary" ng-bind="event.SUMMARY"></span>
<div class="details" ng-if="event.start.format('LT') != event.end.format('LT')">
<span ng-if="event.startName != event.endName"><span ng-bind="event.start.format('M/D')"></span> <span ng-bind="event.start.format('LT')"></span> - <span ng-bind="event.end.format('M/D')"></span> <span ng-bind="event.end.format('LT')"></span></span>
<span ng-if="event.startName == event.endName"><span ng-bind="event.start.format('LT')"></span> - <span ng-bind="event.end.format('LT')"></span></span>
</div>
<div class="details" ng-if="event.start.format('LT') == event.end.format('LT')">All day</div>
</div>
</li>
</ul>
日历扩展控制器(由 html 使用)
function Calendar($scope, $http, $interval, CalendarService) {
var getCalendar = function(){
CalendarService.getCalendarEvents().then(function () {
$scope.calendar = CalendarService.getFutureEvents();
}, function (error) {
console.log(error);
});
}
getCalendar();
$interval(getCalendar, config.calendar.refreshInterval * 60000 || 1800000)
}
console.log("registering calendar controller")
angular.module('SmartMirror')
.controller('Calendar', Calendar);
日历扩展服务(由控制器使用,在此讨论中缩短)
(function () {
'use strict';
function CalendarService($window, $http, $q) {
...
...
return service;
}
console.log("registering calendar service")
angular.module('SmartMirror')
.factory('CalendarService', CalendarService);
} ());
所以想要添加扩展的用户必须创建这些文件,编辑主页 HTML 并插入它们
<div ng-include src="filename.html"></div>
在正确的位置,然后添加
<script src="filename.service" >
和
<script src="filename.controller">
在正确的位置和顺序中,服务需要在控制器之前完成,因为控制器使用服务。
无论如何,很容易添加代码来定位所有扩展并将元素动态插入到 dom 中各自的位置......但是......
在硬编码中,脚本是在正文中的 html 之后添加的
所以,我添加了一个新脚本(在加载页面时处理),它定位并插入所有元素以在正确的位置支持扩展..
然后脚本结束......(硬编码HTML中的最后一个)并且HTML指令被处理并繁荣,动态添加的脚本尚未加载或处理,因此找不到控制器......
我可以创建一个包含所有这些信息的临时 HTML 文件并加载它而不是处理动态加载,但我认为最好解决这个问题
我尝试创建自己的角度指令并将其编译,但陷入循环
<divinc src="filename.service"></divinc>
插入的 div 是正确的,作为 divinc 指令的子项
angular.module('SmartMirror')
.directive("divincl", ["$compile" ,function($compile){
return {
priority: 100,
terminal: true,
compile: function(scope, element, attrs) {
var html = "<div ng-include=\"" + element['incl']+ "\" onload='function(){console.log(\'html loaded\')}'></div>"
var templateGoesHere = angular.element(document.getElementById(element['id']));
templateGoesHere.html(html);
//document.body.innerHTML='';
var v= $compile(templateGoesHere);
//scope.$apply();
return function linkFn(scope) {
v(scope) // Link compiled element to scope
}
}
}
}]);
关于如何解决这个问题的建议..谢谢
解决方案
为了使 angularjs 1.7 应用程序动态加载扩展,有两种方法:
- 要么使用“嵌套的 angularjs 应用程序”,这显然是 angularjs 的高级用法,并且需要您在 2 个 angularjs 应用程序之间进行通信,使用 $scope.$apply 告诉另一个应用程序进行更新等。
- 要么不要在前端动态加载它们,而是在生成包含应用程序的 html 页面时在后端加载它们。尝试从一开始就列出所有扩展名。
我建议您忘记使用ng-include
too 以及尝试在<script></script>
应用程序的指令中添加的事实。
首先,你需要重新理解一个 angularjs 应用程序是如何启动的。
- 当您加载您的主应用程序时,您有一个脚本,其中进行了
angular.module
,angular.directive
,angular.value
,angular.config
,angular.run
... 调用。这是声明步骤 - 如果你声明了一个模块
MyApp
并且在你的 html 中有一个 DOM 元素ng-app="MyApp"
,angularjs 将自动angular.bootstrap()
在这个 DOM 元素上运行以便启动MyApp
。应用程序从这里execution
开始。您不能再在模块中声明任何内容MyApp
。
其次,我认为<script></script>
模板内的代码已被 Angular 清理和删除。另外,即使你执行了代码,由于declaration step
已经完成,你不应该创建新的指令或注册新的服务,它不会工作。
一个好方法是,当您加载插件时,您:
- 从一开始就加载插件的脚本,它必须声明一个新模块,如
MyPlugin1
. - 在包含插件的指令中,输入我发送给您的链接代码,这样可以插入子应用程序。最后,您将
<div ng-app="MyPlugin1"></div>
在指令的模板中拥有一个 - 然后调用
angular.bootstrap
该节点,这将使启动子应用程序成为可能。
如果你这样做,你可以运行子应用程序,但你没有传递参数。为了给它传递参数,你可以把模块的代码MyPlugin1
放在一个函数里面,以便有一个应用工厂。然后用于app.value('param1', parameter1)
初始化应用程序。
例如:
function declarePlugin1(myParam1, myParam2) {
var app = angular.module('MyPlugin1', []);
// app.directive();
app.value('myParam1', myParam1);
app.value('myParam2', myParam2);
}
在指令 call 内部declarePlugin1("test", 42);
,它将MyPlugin1
使用初始化值声明应用程序,然后angular.bootstrap
告诉 angularjs 启动该应用程序。
您也可以传递回调,以便在 2 个应用程序之间进行通信。
推荐阅读
- vue.js - VueJS 过滤器返回警告的原因可能是什么 - 不是函数?
- angular - Angular6中的模态
- android - 带有 xml 的 CustomView 不显示在屏幕上
- javascript - three.js:如何为材质 three.circleGeometry 或 Three.SpriteMaterial 制作 4 种颜色?(下面的例子)
- django - 我怎样才能给 django formset 实例
- python - 为什么 zip(*) 没有恢复我的原始列表
- javascript - 从中获取数据
- javascript - 脚本运行多次
- javascript - 如何让 mousemove 事件在 vue 组件中正常运行?
- ejabberd - ejabberd 15 不仅允许从本地主机注册