2012-10-20 39 views
6

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

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

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

Kohana的型号> Kohana的控制器>的Kohana视图> XHR> JQuery的\角> DOM

我的一个在我的应用程序部分,真正给我撞,让我喝代谢喝几瓶解决应用程序。在哪里我有一个模式对话框,部分页面通过XHR从服务器加载并将其连接到选定的DOM。

问题是,当Angular尝试编译部分页面,当它发现ng-controller指令时,它将查找引用已处理指令的函数。由于DOM解析器尚未评估控制器,因此产生错误。但是,当您在加载部分页面之前在应用程序的某个地方预先放置函数时,一切正常。下面是我如何设置一个Dialog服务的例子,当我点击上述链接时,会从链接指令中调用它。

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; 
}); 

经过一番研究,我发现了一些解决方案,并与我的回答分享给我,像我这样的初学者。 (对不起我的英语不好)。

回答

5

AngularJS在这个设置上没有什么问题,其他的JS专家可能已经知道解决方案,并且很忙于与我们分享,同时发明另一​​个很酷的web开发工具或框架。这没关系。这可能不是一个很酷或最后通solution的解决方案,请与我们分享任何改进或提示!

为了解决这个问题,我们需要设置策略,让我从一个示例代码开始,让我们的大脑在信息流经时消化。下面的代码是使用JQuery创建模式对话框的占位符,Ajax内容将被插入。

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

作为基础知识,我们必须了解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> 

其实这些部分仍然给了一个错误,虽然我们已经把脚本块只是NG-控制器指令中的元素之前。事实上情况并非如此,我们需要解决的部分是AngularJS编译服务如何编译部分DOM。回到我上面的问题部分,并检查我们在哪里编译的东西。上述

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

首先线将编译DOM中的数据的变量,并插入到根DOM不幸第一线会喊一个错误:未找到控制器事务。

发生这种情况的原因是,您的部分页面中的脚本块尚未由DOMP解析器评估,因为未插入到根DOMP中。现在你看到了光明行,所以我们要改变编译策略一点,通过插入新的DOM,然后我们将解析向后下方插入DOM看看例子: -

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

苗条和简单的解决方案,它只是因为忽略了DOM解析中的简单概念,我早上几个小时才解决了这个问题。

+1

我想使用这种方法,但它告诉我$编译没有定义,我是否需要添加别的东西? –

+0

我需要知道你如何初始化AngularJS,你能分享到JsFiddle吗? – wajatimur

+0

代码示例在网站中很清楚,使用 http://jsfiddle.net/9mPGB/ –

0

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

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

.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 
     }); 
    }); 
}) 

我觉得你感兴趣的行是$编译(Newstuff文件)(范围);

编辑: Crikey,今天早上尝试了一些其他标记,并没有工作,无缘无故我能弄明白。原来,如果我没有分配ng-model的字段,那么在新的标记中,$ compile不会被执行。增加:

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

......现在它编译。