使用Angular加载部分页面并编译控制器
在大规模应用程序中,我们的Web应用程序可能会组织成单独的部分页面,以增加应用程序的模块性。 在某些情况下,使用Angular $ http.get或JQuery $ .load编译通过XHR或Ajax请求加载的部分页面将引入错误。
以我的场景为例,我正在使用Kohana PHP框架,因此我可以在服务器级别上控制我的Web应用程序的模块性。 像往常一样,所有模板和页面都被分离到视图中,将所有HTML,JS和CSS放在表示层上。
这将为我在客户端处理上实现Javascript MVW / MVC堆栈提供极大的灵活性,因为我的Web应用程序在很大程度上依赖于从后端应用程序获取数据的AJAX请求。 在我的场景中,我使用AngularJS和以下是关于如何将模型中的数据呈现给客户端的简单伪。
Kohana模型> Kohana控制器> Kohana查看> XHR> JQuery \ Angular> DOM
我的应用程序中的一部分真的让我碰到并让我喝几瓶新陈代谢饮料来解决应用问题。 我在哪里有一个modal dialog,部分页面从服务器通过XHR加载并附加到选定的DOM。
问题是当Angular尝试编译部分页面时,当它找到ng-controller指令时,它将查找引用已处理指令的函数。 由于DOM解析器尚未评估控制器,因此产生错误。 但是,当您在加载部分页面之前在应用程序中的某个位置预先启用该function时,一切正常。 下面是我如何设置一个Dialog服务的示例,当我点击上述链接时,该服务将从link指令调用。
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; });
经过一些研究后,我找到了一些解决方案并与其他人一起分享了我对其他初学者的回答。 (对不起我的英语不好)。
AngularJS在这个设置上没有任何问题,其他JS大师可能已经知道解决方案并且非常忙于与我们分享,同时发明了另一个很酷的Web开发工具或框架。 那可以继续这样做。 这可能不是一个很酷或最后通的解决方案,请与我们分享任何改进或提示!
为了克服这个问题,我们需要设置策略,让我从一个示例代码开始,这样我们的大脑就会在信息流过时消化。 下面的代码是占位符,我使用JQuery创建模式对话框,将插入Ajax内容。
作为基础知识,我们必须了解DOM解析器的工作原理。 我们可能认为DOMP(DOM Parser)是一个multithreading的,这就是我们可以并行加载多个外部资源的原因。 实际上DOMP是单线程的,同时从上到下解析DOM元素索引。 下面是部分页面上的示例,我将加载到#dialog-content DIV元素中。
实际上这些部分仍然给出了错误,尽管我们已经将脚本块放在元素之前使用ng-controller指令。 实际上情况并非如此,我们需要解决的部分是AngularJS编译服务如何编译部分DOM。 让我们回到上面的问题部分,检查我们编译事物的行。
html = $compile(data)(scope); $('#dialog-content').html(html);
上面的第一行将在数据变量中编译DOM,并且插入到根DOM中,不幸的是第一行将发出错误:未找到Controller Transaction。
发生这种情况是因为,部分页面中的脚本块尚未由DOMP解析器评估,因为未插入根DOMP中。 现在你看到了光线好了,所以我们必须通过插入新的DOM来改变编译策略,然后我们将解析下面插入的DOM外观示例: –
html = $('#dialog-content').html(data); $compile(html)(scope);
简洁而简单的解决方案,仅仅因为忽略了DOM解析的简单概念,我早上几乎没有敲击头来解决这个问题。
如果我理解你想要做什么,这是一个简单的例子。
我想通过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 }); }); })
我认为您感兴趣的行是$ compile(newstuff)(范围);
编辑:Crikey,今天早上用其他标记尝试了这个并没有用,无缘无故我能弄明白。 原来,如果我没有分配ng-model的字段,在新标记中,则$ compile不会执行。 添加:
……现在它汇编了。