javascript 使用 Angular 加载部分页面并编译控制器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12987001/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 17:34:13  来源:igfitidea点击:

Loading Partial Page With Angular and Compile The Controller

javascriptjquerymodel-view-controllerdomangularjs

提问by Azri Jamil

In large scale application, our web application might be organize into separate partial page in order to increase the modularity of our application. In some case compiling a partial page loaded through XHR or Ajax request either using Angular $http.get or JQuery $.load will introduce an error.

在大型应用程序中,我们的 Web 应用程序可能会被组织成单独的部分页面,以增加我们应用程序的模块化。在某些情况下,使用 Angular $http.get 或 JQuery $.load 编译通过 XHR 或 Ajax 请求加载的部分页面会引入错误。

Using my scenario as example, exactly I'm using Kohana PHP framework so i can control the modularity of my web application on the server level. As usual all template and page been separate into view, leaving all HTML, JS and CSS together on presentation layer.

以我的场景为例,我正在使用 Kohana PHP 框架,因此我可以在服务器级别控制我的 Web 应用程序的模块化。像往常一样,所有模板和页面都被分离到视图中,将所有 HTML、JS 和 CSS 放在展示层上。

This will giving an great flexibility for me to implement the Javascript MVW/MVC stack on client side processing as my web app are heavily depend on AJAX request to fetch data from back end application. In my scenario im using AngularJS and below is a simple pseudo on how the data from Model presented to client.

这将为我在客户端处理上实现 Javascript MVW/MVC 堆栈提供很大的灵活性,因为我的 Web 应用程序严重依赖 AJAX 请求从后端应用程序获取数据。在我使用 AngularJS 的场景中,下面是一个关于模型中的数据如何呈现给客户端的简单伪代码。

Kohana Model > Kohana Controller > Kohana View > XHR > JQuery\Angular > DOM

Kohana 模型 > Kohana 控制器 > Kohana 视图 > XHR > JQuery\Angular > DOM

One of my part in my application that really give me bump and get me drink few bottles of metabolism drink to solve the application. Is where i have a Modal dialog and the partial page are load through XHR from server and attached it to selected DOM.

我在我的应用程序中的一个部分真的让我大吃一惊,让我喝了几瓶新陈代谢饮料来解决应用程序。我有一个模态对话框,部分页面通过 XHR 从服务器加载并将其附加到选定的 DOM。

The problem is when Angular try to compile the partial page, when it found the ng-controller directive it will be looking for the function referring to the processed directive. Error were produce where the controller is not found as it not yet evaluated by DOM parser. But when you pre-delare the function somewhere in your application just before your load the partial page, everything is OK. Below is the example on how i setup a Dialog service that will be called from link directive when i clicked the said link.

问题是当 Angular 尝试编译部分页面时,当它找到 ng-controller 指令时,它将寻找引用处理指令的函数。由于 DOM 解析器尚未评估控制器,因此在未找到控制器的情况下会产生错误。但是,当您在加载部分页面之前在应用程序中的某处预先声明该函数时,一切正常。下面是我如何设置对话框服务的示例,当我单击上述链接时,该服务将从链接指令中调用。

var dialogService = angular.module('dialog.service', []);
dialogService.factory('Dialog', function($http,$compile){
    var dialogService = {};
    dialogService.load = function(url, scope){
        $("#dialog:ui-dialog").dialog( "destroy" );
        $("#dialog").attr('title','Atlantis');

        $http.get(url).success(function (data) {
            html = $compile(data)(scope);
            $('#dialog-content').html(html);

            $("#dialog").dialog({
                width: '600px',
                buttons: {
                    "Ok": function() {
                        $( this ).dialog( "close" );
                        return true;
                    },
                },
                close: function(){
                    if (typeof (onClose) == 'function') { onClose(); }
                },
            });
        });
    }

    return dialogService;
});

After some research i have found some solution and sharing it with fellas on my answer for others beginner like me. (sorry for my English).

经过一些研究,我找到了一些解决方案,并在我为像我这样的初学者的回答中与伙计们分享。(对不起我的英语不好)。

回答by Azri Jamil

There's nothing wrong on AngularJS on this setup, others JS guru out there might already know the solution and very busy to share with us while inventing another cool web development tools or framework. That's OK keep doing that. This might not be a cool or ultimatum solution, please share any improvement or tips with us!

在这个设置上 AngularJS 没有任何问题,其他 JS 大师可能已经知道解决方案,并且在发明另一个很酷的 Web 开发工具或框架时非常忙于与我们分享。可以继续这样做。这可能不是一个很酷或最后通牒的解决方案,请与我们分享任何改进或提示!

To overcome this problem we need s strategy to setup, let me start with an example code so our brain will digest while the information flowing through. Below code is the placeholder where i create the the modal dialog using JQuery and the Ajax content will be insert.

为了克服这个问题,我们需要设置策略,让我从一个示例代码开始,这样我们的大脑就会在信息流过的时候进行消化。下面的代码是我使用 JQuery 创建模态对话框的占位符,并将插入 Ajax 内容。

<div ng-app="asng" id="dialog" title="" style="display:none">
     <div id="dialog-content"></div>
</div>

As a basic knowledge, we have to understand on how DOM parser are working. We might think that DOMP (DOM Parser) is a multi-threaded and that's the reason we can load multiple external resource in parallel. Actually DOMP are single threaded while parsing the DOM elements index from top to bottom. Below is the example on the partial page that I'm gonna load into #dialog-content DIV element.

作为基础知识,我们必须了解 DOM 解析器是如何工作的。我们可能认为 DOMP (DOM Parser) 是多线程的,这就是我们可以并行加载多个外部资源的原因。实际上 DOMP 在从上到下解析 DOM 元素索引时是单线程的。下面是我将加载到#dialog-content DIV 元素的部分页面上的示例。

<script language="JavaScript" type="text/javascript">
    function Transaction ($scope,$http){
        $scope.items = [{"country":"VN","quantity":"100"}];
        $scope.country_name = $scope.items;
    }
</script>

<style>
</style>

<div id="transaction-panel" class="user" data-ng-controller="Transaction">
        <form id="{{ form_name }}" action="">
        Country : [[ items.country ]] </br>
        Total : [[ items.quantity ]]
    </form>
</div>

Actually these partial still giving an error, although we have put the script block just before the element with ng-controller directive. Actually that's not really the case, the part that we need to tackle is how AngularJS compile service are compiling the partial DOM. Let go back on my question part above and inspect where the line that we do the compile thing.

实际上这些部分仍然给出错误,尽管我们已经将脚本块放在带有 ng-controller 指令的元素之前。其实并非如此,我们需要解决的部分是 AngularJS 编译服务如何编译部分 DOM。让我们回到上面我的问题部分,并检查我们进行编译的那一行。

html = $compile(data)(scope);
$('#dialog-content').html(html);

First line above will compile DOM in data variable, and insert into the root DOM unfortunately first line will shout an error : Controller Transaction not found.

上面的第一行将编译数据变量中的 DOM,不幸的是插入到根 DOM 中,第一行会出现错误:未找到控制器事务。

This happen because, the Script Blockin your partial page is not yet evaluate by DOMP parser because is not inserted into the root DOMP. Now you see the light OK, so we have to change the compiling strategy a bit, by inserting the new DOM and then we will parse back the inserted DOM look example below:-

发生这种情况的原因是,部分页面中的脚本块尚未被 DOMP 解析器评估,因为它没有插入到根 DOMP 中。现在你看到光明了,所以我们必须稍微改变编译策略,通过插入新的 DOM,然后我们将解析插入的 DOM 外观示例如下:-

html = $('#dialog-content').html(data);
$compile(html)(scope);

Slim and simple solution, it took me few head banging morning to solve this problem just because ignoring the simple concept on DOM parsing.

纤薄而简单的解决方案,我花了几个上午的时间才解决这个问题,只是因为忽略了 DOM 解析的简单概念。

回答by Peter Hollingsworth

If I understand what you are trying to do, here's a simple example.

如果我理解你想要做什么,这里有一个简单的例子。

I wanted to post via AJAX to a Django form and then replace the form content in the page with the returned markup. The returned markup includes an ng-controller, which I need to execute when it loads:

我想通过 AJAX 发布到 Django 表单,然后用返回的标记替换页面中的表单内容。返回的标记包括一个 ng-controller,我需要在它加载时执行:

.controller('MyForm', function($element, $compile, $scope){
    var scope = $scope;
    var $theForm = $element;
    var $formBlock = $element.find('.the_form');  // is replaced by the form response
    $element.find('.submit_the_form').click(function(){
        // submit the form and replace contents of $formBlock
        $.post($theForm.attr('action'), $theForm.serialize(), function(response){
            var newstuff = $formBlock.html(response);
            $compile(newstuff)(scope); // loads the angular stuff in the new markup
        });
    });
})

I think the line you're interested in is $compile(newstuff)(scope);

我认为您感兴趣的行是 $compile(newstuff)(scope);

EDIT: Crikey, tried this with some other markup this morning and did not work, for no reason I could figure out. Turned out that if I did not have a field with ng-model assigned, in the new markup, then the $compile does not execute. Added:

编辑:Crikey,今天早上用其他一些标记尝试了这个,但没有奏效,我无缘无故地弄清楚。原来,如果我在新标记中没有分配 ng-model 的字段,则 $compile 不会执行。添加:

<input type="hidden" name="dummy" value="0" ng-model="dummy"/>

...and now it compiles.

...现在它编译了。