提问人:tarekahf 提问时间:6/1/2021 最后编辑:tarekahf 更新时间:8/4/2021 访问量:436
如何从 AngularJS 模块/代码外部调用 AngularJS $compile?
How to invoke AngularJS $compile from outside AngularJS module/code?
问:
假设我有带有 AngularJS 模块/控制器的 HTML,如下所示:
angular
.module("myModule", [])
.controller("myController", ['$scope', '$compile', function ($scope, $compile) {
$scope.txt = "<b>SampleTxt</b>";
$scope.submit = function () {
var html = $compile($scope.txt)($scope);
angular.element(document.getElementById("display")).append(html);
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myModule" >
<div ng-controller="myController">
<form name="myForm">
<span>Age:</span><input type="number" name="age" ng-model="age"/>
<textarea ng-model="txt" ></textarea>
<input type="button" value="submit" ng-click="submit()" />
</form>
<div id="display"></div>
</div>
</body>
上面的示例将允许在运行时使用 $compile 向 AngularJS 应用程序添加元素。
假设我想插入一个输入元素,例如带有属性的文本框名称,假设我想从 JavaScript 控制台插入这个具有条件必需功能的元素,以便进行测试和验证。另外,假设我想做同样的事情,但我想修改属性,如果现有元素(例如 ,我该怎么做?driversLinces
ng-required="age > 21"
ng-required
age
我正在考虑创建一个函数,该函数将以某种方式访问但不确定如何访问。你可以帮我吗?我只能从控制器内部访问$compile服务。$compile
注意:由于某些限制和缺乏信息/资源,我对完整 HTML 代码的访问有限。我可以使用 UI 建模器访问 HTML 和 AngularJS 表单。我可以添加我的自定义 HTML 代码,但我不知道我是否可以用我自己的自定义 HTML 容器将现有表单部件括起来,这是添加访问内部部件的指令所必需的。
我可以使用 .我可以在 Form-Load 上、单击按钮或模型值更改时触发我的 JavaScript。我可以添加一个表单元素并将其链接到 AngularJS 模型。我无法弄清楚如何从 JavaScript 访问 $compile 服务。ng-form
angular.element()
更新:
我将添加更多信息来解释我的目标或用例。
我想从 JavaScript 向 AngularJS 表单添加自定义验证规则和错误。我正在使用的平台使用 AngularJS,但不允许我轻松访问 AngularJS 代码来添加指令,或者至少目前,我没有为此目的所需的资源。但是,这个平台使我能够在单击按钮时触发我的自定义 JavaScript 代码,该按钮可以在表单加载时自动触发(加载事件)。此外,我可以传递单击的按钮的 ID。有了这个,我就能够使用 .这使我能够访问几乎所有其他元素。我可以在作用域对象中看到所有和它的所有父级。有时,我必须访问才能到达根目录,但我认为最终我能够从作用域对象访问几乎任何内容。angular.element('#id').scope()
ng-models
ng form controllers
$parent
现在,我需要能够找到表单元素并添加自定义验证规则。我可以遍历范围对象中的所有表单元素,并且可以弄清楚如何获取元素 ID 及其绑定详细信息。我现在需要的是如何在表单加载事件上添加自定义验证规则和错误消息。
例如,我可以使用 JSON 来表示 AngularJS 表单的验证规则,如下所示:
[
{
"id": "employee-name",
"required": true,
"msg": "Employee name is required."
},
{
"id": "degree",
"customValidation": "someJSFunctionName",
"msg": "The provided degree is invalid. Please review the rules and try again."
}
]
然后,在表单加载事件中,我想将上述规则加载到表单上并使其生效。这怎么可能?考虑到我可以访问范围对象,我只能使用 JavaScript,并且我不能使用 AngularJS 指令。
更新2:
根据下面 PhineasJ 提供的答案,我使用控制台执行以下命令:
var injector = window.angular.injector(['ng']);
var $compile = injector.get('$compile');
var elm = angular.element("my-element-selector");
var elmScope = elm.scope();
elm.attr('ng-required', true);
var elmCompile = $compile(elm[0])(elmScope);
虽然上述内容没有引发任何错误,但是,它并没有正常工作。如果我将该字段设置为空,它不会触发错误,尽管我可以看到该属性是在执行命令后添加的。我注意到每次更新字段值时都必须执行服务,以便验证规则反映出来,但我没有看到字段的对象正在更新。它始终是空的。elm
ng-required
required
$compile
$compile
ctrl.$error
然后我尝试了以下方法:
var injector = window.angular.injector(['ng', 'myApp']);
var $compile = injector.get('$compile');
...我收到错误.Uncaught Error: [$injector:unpr] Unknown provider: $rootElementProvider
然后我尝试了以下方法:
var mockApp = angular.module('mockApp', []).provider({
$rootElement:function() {
this.$get = function() {
return angular.element('<div ng-app></div>');
};
}
});
var injector = window.angular.injector(['ng', 'mockApp', 'myApp']);
...第一次没有抛出任何错误,但是当我再次尝试时,我得到了错误。所以我坚持这项服务。The view engine is already initialized and cannot be further extended
$compile
我确实尝试直接使用添加规则,并且取得了成功。详情如下:$validators()
//The elm form controller is found on the $parent scope and this is beyond my control.
//The ng-form element names are generated by the back-end and I have no control over this part. In this case the HTML element 'elm' is the form element name 'ewFormControl123'.
elmScope.$parent.ewFormControl123.$validators.required =
function (modelValue, viewValue) {
console.log(modelValue, viewValue);
var result = !!(modelValue??null);
console.log("result = ", result);
return result;
}
以上似乎工作正常,但是,我仍然有兴趣通过将验证规则或指令注入 HTML 代码,然后在该元素上运行服务来使用。我认为将所需的部分注入 HTML 并运行会更好。$compile
$compile
$compile
更新 3
在@PhineasJ的帮助下,我设法准备了一个使用和服务的小样品。这工作很成功,但相同的方法在目标应用程序上不起作用。AngularJS injector
$compile
W3School 原始样本:https://www.w3schools.com/angular/tryit.asp?filename=try_ng_ng-required
JS Fiddle 示例:https://jsfiddle.net/tarekahf/5gfy01k2/
按照这种方法,只要有一个选择器来抓取元素,我就应该能够在运行时为任何字段加载验证规则。
我现在正在努力解决在目标应用程序上应用相同方法时遇到的错误。我有两个问题:
- 如果与应用名称一起使用,则会出现以下错误:
const injector = angular.injector(['ng', 'myApp'])
Uncaught Error: [$injector:unpr] Unknown provider: $rootElementProvider
- 如果我不添加应用名称,则不会引发错误,但不会遵守验证规则。
但是,如果我使用该对象,我可以添加验证规则并遵守它。我不确定为什么没有人推荐这种方法。formController.$validators
感谢您的帮助和反馈。
更新 4
我找到了解决方案。检查我在下面添加的答案。
塔里克
答:
要在 AngularJS 外部调用$compile函数,yon 可以使用:
const injector = window.angular.injector(['ng', 'your-module']);
injector.invoke(function($rootScope, $compile) {
$compile('<div custom-directive></div>')($rootScope);
})
若要添加动态验证规则,可以引用自定义验证。
也可以从您提到的中检索。controller Scope
angular.element().scope
下面是一个关于如何动态加载验证器并编译它的演示。https://plnkr.co/edit/4ay3Ig2AnGYjLQ92?preview
评论
angular.element.scope
const injector = window.angular.injector(['ng', 'your-module']);
Uncaught Error: [$injector:unpr] Unknown provider: $rootElementProvider
$rootElementProvider
Uncaught Error: The view engine is already initialized and cannot be further extended
var mockApp = angular.module('mockApp', []).provider({ $rootElement:function() { this.$get = function() { return angular.element('<div ng-app></div>'); }; } });
var injector = window.angular.injector(['ng', 'mockApp', 'oneModule']);
解决方法是使用以下命令获取喷油器:
var injector = angular.element("#myAngularAppID").injector();
其中 id 定义 HTML 元素的元素 ID。myAngularAppID
ng-app
injector 语句的以下变体不起作用:
//Without using the app
var injector = window.angular.injector(['ng']);
//With the app
var injector = window.angular.injector(['ng', 'myApp'])
一旦实施了上述更正,问题就解决了。
特别感谢@PhineasJ。此外,以下参考资料对我有帮助:
检查 JS Fiddle,它具有所有可能的变体,可用于动态添加 HTML 元素并将它们绑定到 AngularJS 范围:$compile
评论
scope
angular.element()
ng-readonly
ng-required
angular.element().scope
nd-model