2012-10-20 45 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"/> 

......現在它編譯。