如何重新注册动态加载的 angular 模板指令
How to re-register a dynamically loaded angular templates' directive
我有一个指令,它加载一个模板,其中有一堆输入字段。其中之一是 jQuery/Bootstrap 日期选择器。
<my-directive-buttons></my-directive-buttons>
当用户 selects/clicks 在日期选择器字段上时,将显示日历。我还在输入字段中附加了一个 ng-click
:
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group datepick'>
<input type='text' class="form-control" ng-click="addCalendarFooter()"/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
单击时,将显示日历并调用 $scope.addCalendarFooter
:
app.directive('myDrectiveButtons', function($compile) {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
},
templateUrl: 'controls/input-fields.html',
link: function(scope, elem, attrs) {
},
controller: function($scope) {
$scope.addCalendarFooter = function() {
$('#datepicker').append($('<div></div>').load('myDir/calendar/customFooter.html'));
}
}
}
});
我成功地将 customFooter.html
的内容附加到日历中,但是,在 customFooter.html
中还有 ng-clicks
,按下时不会被调用。例如
customFooter.html
<div>
<button ng-click="controlClick()">Click Me</button>
</div>
然而,如果我将此按钮移出 customFooter.html
并移入 input-field.html
,以测试按钮逻辑是否正确,则点击被调用。
我在 .append
之后尝试了 $scope.$apply
和 $scope.digest
,但是我得到了 'digest already in progress error'
更新:
根据下面的评论,已尝试删除 jQuery 并使用 'angular way'
$scope.addCalendarFooter = function() {
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
var myEl = angular.element(document.getElementsByClassName('datepicker');
myEl.html(html);
$compile(myEl)($scope)
}
上面通过 ng-include 插入了我的 .html 模板,但是它是替换日期选择器的内容而不是插入到它的底部。尝试过 .append 但这也不值得。
如果您最初在模板中包含页脚,但使用 ng-if / ng-show 将其隐藏,该怎么办。然后该函数只会更改一个标志并显示先前隐藏的页脚。
您基本上是手动加载页脚并完全绕过 angular。 Angular 没有看到您正在加载 html,因此根本没有编译 html 模板和绑定指令,包括 ng-click。
您可以使用加载指定模板的 ng-include 指令,而不是自己制作自定义模板。或者,如果您的指令需要其他功能,只需在指令模板本身中包含 ng-include。
您说您的问题是在调用 $scope.$apply
或 $scope.digest
之后出现 $digest already in progress
错误。
绕过这个的聪明方法是使用$evalAsync。它最大的优势之一是它知道是否应该执行一个额外的摘要循环。
如果您使用的是 ng-include,请不要忘记路径开头和结尾的单引号。
Angular 关于 ng-include 的文档:https://docs.angularjs.org/api/ng/directive/ngInclude
make sure you wrap it in single quotes, e.g. src="'myPartialTemplate.html'"
应该是:
var html = "<ng-include src=\"'myDir/calendar/customFooter.html'\"><\ng-include>";
或:
var html = "<div ng-include=\"'myDir/calendar/customFooter.html'\"><\div>";
但不是:
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
引用您的更新:
The above inserts my .html template via the ng-include however is it replacing the contents of the datepicker rather than inserting at the bottom of it. Tried .append but that didn't worth either.
上述问题是由于使用 .html()
方法将 HTML 插入 DOM 节点并 覆盖 任何现有内容selected 节点:
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
var myEl = angular.element(document.getElementsByClassName('datepicker');
myEl.html(html); // <== here
$compile(myEl)($scope)
你用上面的逻辑所做的是,你首先 select .datePicker
元素,然后你 替换 它的内部 HTML使用 .html()
方法。
作为解决方法,您可以改用 .append()
方法。
注意: angular.element()
是 Angular 对元素的包装,就像在 jQuery
中您有 $()
一样。因此,在您的情况下使用 document.getElementByClassName()
方法是多余的。
虽然上述解决方法可能会解决您的问题,但最好坚持使用 AngularJS 可能提供的更简洁的方法。
Angular风格方法
您不需要通过 编程方式 adding/appending 控制器函数中的模板加载部分模板 - 至少以 Angular 的方式.这样,您最终可能无法将动态添加的 HTML 中的 angular 指令与范围正确绑定。
相反,只需将部分包含在原始指令模板中(使用 ng-include
)并使用 ngIf
或 ngShow
在单击按钮时显示它。
因此,假设您在原始指令模板中有页脚模板 (customFooter.html
),您可以获得如下预期结果:
指令模板
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group datepick'>
<input type='text' class="form-control" ng-click="addCalendarFooter()"/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div ng-include="myDir/calendar/customFooter.html" ng-if="isCalenderFooterAdded"></div>
指令控制器
controller: function($scope) {
$scope.addCalendarFooter = function() {
$scope.isCalendarFooterAdded = true;
// or use this if you want to toggle it
// $scope.isCalendarFooterAdded = !$scope.isCalendarFooterAdded ? true: false;
}
}
Plunkr 模拟类似情况。
我有一个指令,它加载一个模板,其中有一堆输入字段。其中之一是 jQuery/Bootstrap 日期选择器。
<my-directive-buttons></my-directive-buttons>
当用户 selects/clicks 在日期选择器字段上时,将显示日历。我还在输入字段中附加了一个 ng-click
:
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group datepick'>
<input type='text' class="form-control" ng-click="addCalendarFooter()"/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
单击时,将显示日历并调用 $scope.addCalendarFooter
:
app.directive('myDrectiveButtons', function($compile) {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
},
templateUrl: 'controls/input-fields.html',
link: function(scope, elem, attrs) {
},
controller: function($scope) {
$scope.addCalendarFooter = function() {
$('#datepicker').append($('<div></div>').load('myDir/calendar/customFooter.html'));
}
}
}
});
我成功地将 customFooter.html
的内容附加到日历中,但是,在 customFooter.html
中还有 ng-clicks
,按下时不会被调用。例如
customFooter.html
<div>
<button ng-click="controlClick()">Click Me</button>
</div>
然而,如果我将此按钮移出 customFooter.html
并移入 input-field.html
,以测试按钮逻辑是否正确,则点击被调用。
我在 .append
之后尝试了 $scope.$apply
和 $scope.digest
,但是我得到了 'digest already in progress error'
更新:
根据下面的评论,已尝试删除 jQuery 并使用 'angular way'
$scope.addCalendarFooter = function() {
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
var myEl = angular.element(document.getElementsByClassName('datepicker');
myEl.html(html);
$compile(myEl)($scope)
}
上面通过 ng-include 插入了我的 .html 模板,但是它是替换日期选择器的内容而不是插入到它的底部。尝试过 .append 但这也不值得。
如果您最初在模板中包含页脚,但使用 ng-if / ng-show 将其隐藏,该怎么办。然后该函数只会更改一个标志并显示先前隐藏的页脚。
您基本上是手动加载页脚并完全绕过 angular。 Angular 没有看到您正在加载 html,因此根本没有编译 html 模板和绑定指令,包括 ng-click。
您可以使用加载指定模板的 ng-include 指令,而不是自己制作自定义模板。或者,如果您的指令需要其他功能,只需在指令模板本身中包含 ng-include。
您说您的问题是在调用 $scope.$apply
或 $scope.digest
之后出现 $digest already in progress
错误。
绕过这个的聪明方法是使用$evalAsync。它最大的优势之一是它知道是否应该执行一个额外的摘要循环。
如果您使用的是 ng-include,请不要忘记路径开头和结尾的单引号。
Angular 关于 ng-include 的文档:https://docs.angularjs.org/api/ng/directive/ngInclude
make sure you wrap it in single quotes, e.g. src="'myPartialTemplate.html'"
应该是:
var html = "<ng-include src=\"'myDir/calendar/customFooter.html'\"><\ng-include>";
或:
var html = "<div ng-include=\"'myDir/calendar/customFooter.html'\"><\div>";
但不是:
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
引用您的更新:
The above inserts my .html template via the ng-include however is it replacing the contents of the datepicker rather than inserting at the bottom of it. Tried .append but that didn't worth either.
上述问题是由于使用 .html()
方法将 HTML 插入 DOM 节点并 覆盖 任何现有内容selected 节点:
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
var myEl = angular.element(document.getElementsByClassName('datepicker');
myEl.html(html); // <== here
$compile(myEl)($scope)
你用上面的逻辑所做的是,你首先 select .datePicker
元素,然后你 替换 它的内部 HTML使用 .html()
方法。
作为解决方法,您可以改用 .append()
方法。
注意: angular.element()
是 Angular 对元素的包装,就像在 jQuery
中您有 $()
一样。因此,在您的情况下使用 document.getElementByClassName()
方法是多余的。
虽然上述解决方法可能会解决您的问题,但最好坚持使用 AngularJS 可能提供的更简洁的方法。
Angular风格方法
您不需要通过 编程方式 adding/appending 控制器函数中的模板加载部分模板 - 至少以 Angular 的方式.这样,您最终可能无法将动态添加的 HTML 中的 angular 指令与范围正确绑定。
相反,只需将部分包含在原始指令模板中(使用 ng-include
)并使用 ngIf
或 ngShow
在单击按钮时显示它。
因此,假设您在原始指令模板中有页脚模板 (customFooter.html
),您可以获得如下预期结果:
指令模板
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group datepick'>
<input type='text' class="form-control" ng-click="addCalendarFooter()"/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div ng-include="myDir/calendar/customFooter.html" ng-if="isCalenderFooterAdded"></div>
指令控制器
controller: function($scope) {
$scope.addCalendarFooter = function() {
$scope.isCalendarFooterAdded = true;
// or use this if you want to toggle it
// $scope.isCalendarFooterAdded = !$scope.isCalendarFooterAdded ? true: false;
}
}