Загрузка частичной страницы с помощью Angular и компиляция контроллера

В крупномасштабном приложении наше веб-приложение может быть организовано на отдельной частичной странице, чтобы повысить модульность нашего приложения. В некоторых случаях компиляция частичной страницы, загруженной с помощью XHR или Ajax-запроса с использованием Angular $ http.get или JQuery $ .load, приведет к ошибке.

Используя мой сценарий в качестве примера, я использую PHP-инфраструктуру Kohana, чтобы я мог контролировать модульность моего веб-приложения на уровне сервера. Как обычно, все шаблоны и страницы были разделены на отдельные представления, оставив все HTML, JS и CSS вместе на уровне представления.

Это даст мне большую гибкость для реализации стека Javascript MVW / MVC при обработке на стороне клиента, так как мое веб-приложение сильно зависит от запроса AJAX для извлечения данных из серверного приложения. В моем сценарии я использую AngularJS и ниже просто псевдо о том, как данные из модели представлены клиенту.

Модель Kohana> Контроллер Kohana> Вид Kohana> XHR> JQuery \ Angular> DOM

Одна из моих частей в моем заявлении, которое действительно дает мне толчок и заставляет меня выпить несколько бутылок метаболического напитка, чтобы решить приложение. Где у меня есть модальное диалоговое окно, и частичная страница загружается через XHR с сервера и прикрепляется к выбранному DOM.

Проблема в том, что когда Angular пытается скомпилировать частичную страницу, когда он обнаружил директиву ng-controller, он будет искать функцию, ссылающуюся на обработанную директиву. Произошла ошибка, когда контроллер не найден, поскольку он еще не оценен анализатором DOM. Но когда вы предварительно делали функцию где-то в своем приложении перед загрузкой частичной страницы, все в порядке. Ниже приведен пример того, как я настраиваю службу 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;
});

После некоторых исследований я нашел какое-то решение и поделился им с ребятами в своем ответе для таких начинающих, как я. (Извините за мой английский).

Ответы на вопрос(2)

другие гуру JS, возможно, уже знают решение и очень заняты, чтобы поделиться с нами, изобретая другие классные инструменты или среду для веб-разработки. Это нормально, продолжай делать это. Возможно, это не крутое или ультимативное решение, поделитесь с нами какими-либо улучшениями или советами!

Чтобы преодолеть эту проблему, нам нужно настроить стратегию, позвольте мне начать с примера кода, чтобы наш мозг переваривал информацию, пока информация течет. Ниже приведен код заполнителя, в котором я создаю модальное диалоговое окно с использованием JQuery, и содержимое Ajax будет вставлено.

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

Как базовые знания, мы должны понимать, как работает DOM-парсер. Мы можем подумать, что DOMP (DOM Parser) является многопоточным, и именно поэтому мы можем загружать несколько внешних ресурсов параллельно. На самом деле DOMP являются однопоточными при анализе индекса элементов DOM сверху вниз. Ниже приведен пример частичной страницы, которую я собираюсь загрузить в элемент DIV # dialog-content.

<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-controller. На самом деле это не совсем так, мы должны решить, как служба компиляции 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.

 Dvid Silva22 апр. 2013 г., 19:44
Я пытаюсь использовать этот подход, но он говорит мне, что $ compile не определен, мне нужно добавить что-то еще?
 Robert Christian05 нояб. 2013 г., 01:41
У кого-нибудь есть конкретный пример этой работы? У меня есть похожая проблема, изложенная в этом SO:stackoverflow.com/questions/19779687/...
 wajatimur23 апр. 2013 г., 10:10
Мне нужно знать, как вы инициализируете AngularJS, вы можете поделиться на JsFiddle?
 wajatimur24 апр. 2013 г., 12:26
Просматривая ваш код, я понятия не имею, как работает ваш код, но это может произойти из-за того, как вы загружаете свой js. Вы используете какой-либо загрузчик скриптов? Вы должны убедиться, что AngularJS загружен, прежде чем вы сможете запустить свой контроллер приложения.
 Dvid Silva23 апр. 2013 г., 16:19
примеры кода очень понятны на сайте, используйтеjsfiddle.net/9mPGB

Я хотел опубликовать через 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
        });
    });
})

Я думаю, что строка, которая вас интересует - это $ compile (newstuff) (scope);

РЕДАКТИРОВАТЬ: Крики, попробовал это с какой-то другой разметкой сегодня утром и не работал, без причины я мог выяснить. Оказалось, что если у меня не было поля с назначенной ng-моделью в новой разметке, то $ compile не выполняется. Добавлено:

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

... и теперь он компилируется.

Ваш ответ на вопрос