【发布时间】:2021-08-19 00:50:12
【问题描述】:
假设我有带有 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 应用程序。
假设我想插入一个输入元素,例如带有属性ng-required="age > 21" 的文本框名称driversLinces,假设我想从JavaScript 控制台插入这个具有条件必需功能的元素,以进行测试和验证。另外,假设我也想做同样的事情,但我想修改ng-required 属性,如果现有元素如age,我该怎么做?
我正在考虑创建一个以某种方式访问$compile 的函数,但不确定如何访问。你能帮助我吗?我只能从控制器内部访问 $compile 服务。
注意:由于某些限制和缺乏信息/资源,我无法访问完整的 HTML 代码。我可以使用 UI 建模器访问 HTML 和 AngularJS 表单。我可以添加我的自定义 HTML 代码,但我不知道是否可以用我自己的自定义 HTML 容器封装现有的表单部件,这是添加指令以访问内部部件所必需的。
我可以使用 angular.element() 访问 AngularJS 范围和 ng-form 元素。我可以在表单加载、单击按钮或模型值更改时触发我的 JavaScript。我可以添加一个表单元素并将其链接到 AngularJS 模型。我不知道如何从 JavaScript 访问 $compile 服务。
更新:
我将添加更多信息来解释我的目标或用例。
我想从 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 错误,尽管我可以看到在执行$compile 命令后添加了required 属性。我注意到每次更新字段值时都必须执行$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 代码来使用 $compile,然后在该元素上运行 $compile 服务。我认为将所需的部分注入 HTML 并运行 $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
我找到了解决方案。检查我在下面添加的答案。
塔雷克
【问题讨论】:
-
您需要在控制器上下文之外访问 $compile 的用例是什么?您是否考虑过自定义指令甚至`ng-include?span>
-
我在一个使用 AngularJS 的平台上,顶部有一个附加层。我没有时间和资源来挖掘和弄清楚如何添加控制器和指令,因为这需要很长时间,而且我认为我不能将 HTML 链接到指令。我可以轻松编写 JavaScript 函数,并且可以使用脚本按钮访问活动页面上的元素。我可以使用
angular.element()访问scope。我需要为某些 HTML 现有元素修改ng-readonly和ng-required表单 JavaScript。我希望能够从控制台对其进行测试并在表单加载时触发它。 -
将 html 链接到指令的多种方法。远程模板文件、模板函数、模板字符串、$templateCache服务等。指令也可以使用$compile
-
在最坏的情况下,您可以使用
angular.element().scope访问编译功能,但这对我来说似乎很老套 -
... 继续... 现有的 HTML 和 AngularJS 表单可以通过建模器 UI 访问(我无法修改原始 HTML 源代码)。我还可以在页面上添加我自己的自定义 HTML 代码,如果模型变量值发生更改,我可以在页面加载时触发 JavaScript 代码,以及单击按钮。我可以添加元素并将它们链接到
nd-model。我不知道我是否可以将现有的 HTML 表单部分与我自己的客户 HTML 容器封装起来,这是将其链接到指令所必需的。我需要尽快做某事,因为我没有太多的试错空间。
标签: javascript angularjs validation compilation angularjs-forms