如何从外部调用 AngularJS $compile AngularJS module/code?

How to invoke AngularJS $compile from outside AngularJS module/code?

假设我有 HTML 和 AngularJS module/controller 如下:

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 应用程序。

假设我想插入一个输入元素,例如文本框名称 driversLinces,属性为 ng-required="age > 21",假设我想插入这个元素,该元素具有来自 [=143= 的条件必需特征] 用于测试和验证目的的控制台。另外,假设我想做同样的事情,但我想修改 ng-required 属性 如果现有元素如 age,我该怎么做?

我正在考虑创建一个可以访问 $compile 的函数,但不确定如何访问。你能帮助我吗?我只能从控制器内部访问 $compile 服务。

注意:由于某些限制和缺少 information/resources,我对完整 HTML 代码的访问受到限制。我可以使用 UI 建模器访问 HTML 和 AngularJS 表单。我可以添加我的自定义 HTML 代码,但我不知道我是否可以用我自己的自定义 HTML 容器封装现有的表单部件,这是添加访问内部部件的指令所必需的。

我可以使用 angular.element() 访问 AngularJS 范围和 ng-form 元素。我可以在表单加载、单击按钮或模型值更改时触发我的 JavaScript。我可以添加一个表单元素并将其 link 添加到 AngularJS 模型中。我不知道如何从 JavaScript.

访问 $compile 服务

更新:

我将添加更多信息来解释我的 objective 或用例。 我想将自定义验证规则和错误添加到来自 JavaScript 的 AngularJS 表单。我正在使用的平台使用 AngularJS,但不允许我轻松访问 AngularJS 代码来添加指令,或者至少目前,我没有为此所需的资源目的。但是,这个平台让我能够在单击按钮时触发我的自定义 JavaScript 代码,该按钮可以在加载表单时自动触发(加载事件)。另外,我可以传递被单击的按钮的 ID。这样,我就可以使用 angular.element('#id').scope() 访问范围。这使我能够访问几乎所有其他元素。我可以在范围对象中看到所有 ng-modelsng 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;
    }

上面的方法似乎工作正常,但是,我仍然对使用 $compile 感兴趣,方法是将验证规则或指令注入 HTML 代码,然后 运行 $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/

按照这个方法,我应该能够在 运行 时间内为任何字段加载验证规则,只要有一个选择器来抓取元素。

我现在正在努力解决在目标应用程序上应用相同方法时出现的错误。我有两个问题:

  1. 如果我在应用程序名称中使用 const injector = angular.injector(['ng', 'myApp']),我会收到错误消息:Uncaught Error: [$injector:unpr] Unknown provider: $rootElementProvider
  2. 如果我不添加应用名称,不会抛出错误,但不遵守验证规则。

但是,如果我使用 formController.$validators 对象,我可以添加验证规则并遵守它。我不确定为什么没有人推荐这种方法。

感谢您的帮助和反馈。

更新 4

我找到了解决办法。检查我在下面添加的答案。

塔雷克

要在 AngularJS 之外调用 $compile 函数,您可以使用:

const injector = window.angular.injector(['ng', 'your-module']);
injector.invoke(function($rootScope, $compile) {
  $compile('<div custom-directive></div>')($rootScope);
})

添加动态验证规则,可参考custom validation。 正如您提到的,controller Scope 也可以从 angular.element().scope 中检索。

这里有一个关于如何动态加载验证器并编译它的演示。 https://plnkr.co/edit/4ay3Ig2AnGYjLQ92?preview

修复方法是使用以下命令获取注入器:

var injector = angular.element("#myAngularAppID").injector();

其中 myAngularAppID id 定义了 ng-app 的 HTML 元素的元素 ID。

注入器语句的以下变体不起作用:

//Without using the app
var injector = window.angular.injector(['ng']);
//With the app
var injector = window.angular.injector(['ng', 'myApp'])

执行上述更正后,问题就解决了。

特别感谢@PhineasJ。此外,以下参考资料对我有帮助:

  1. Injector returns undefined value?

检查 JS Fiddle,它具有使用 $compile 动态添加 HTML 元素并将它们绑定到 AngularJS 范围的所有可能变体:

https://jsfiddle.net/tarekahf/5gfy01k2/