Конфликт jQuery скрипта и AngularJS
Добрый день. Я еще относительно новичок в JS и AngularJS и столкнулся на первый взгляд с банальной проблемой.
Есть AngularJS модуль, который отвечает за получение данных с JSON-а и записывает их в объект $Scope. Впоследствии, через ng-Repeat я подгружаю эти данные на HTML страницу. Вроде бы все норм, но когда я написал небольшой скрипт при помощи jQuery (скрытие блоков на подобие аккордеона с анимацией) для манипуляции с полученными через ng-Repeat DOM-элементами, возникли проблемы. Один раз из 10, скрипт на jQuery не срабатывает. Причем, это появилось, только когда я залил проект на сервер. Пробовал использовать timeout в пол секунды, для загрузки jQuery-скрипта - стало получше, но все равно, если скрипт сильно разрастается в размере, ошибки появляются все чаще. Нужно, как то установить загрузку моего jQuery-скрипта только после полного окончания формирования DOM-a посредством AngularJS. P.S. Вариант с RequireJS не проходит по ряду причин. P.P.S. Само собой скрипт jQuery обрамлен в событие $(document).ready() |
http://angular.ru/guide/understanding_directives
И конкретнее: "Если необходимо подождать, пока в $scope не поступят данные, воспользуйтесь ng-if для отложенной загрузки блока DOM." |
Цитата:
P.S. Видимо скрипт срабатывает раньше чем сформирован DOM, это не конфликт. Следите напрямую за порядком инициализации. В идеале превратите ваш скрипт в директиву, или в случае если плагин не ваш то оберните вызов плагина директивой. Также не стоит при написании плагинов забывать про функцию live, но по прежнему ваш jQuery код должен быть в директиве или вызываться из нее. Ангуляр гарантирует срабатывание директив в постоянном и предсказуемом порядке. |
Какая есть )))
Лучше такая, чем никакой. Тем более полезные дела делают парни! |
Спасибо за советы.
Попробовал я использовать загрузку jQuery-скрипта через директиву. Создал простенькую директиву:
.directive('jqueryscript', function () {
return {
restrict: 'E',
template: '<script type="text/javascript" src="js/jQueryJS.js"></script>'
}
})
и вызвал ее в конце HTML-кода. Так все работает, но если с моего jQuery-скрипта убрать таймаут, то скрипт перестает выполнятся даже локально... Заметил, что при использовании window.onload вместо $(document).ready все работает без ошибок, но это не оптимально из-за долгой загрузки скриптов... |
Цитата:
|
Цитата:
При подключении 1.2 версии - начинают вылазить куча других ошибок и несовместимостей... |
Вообще то её из angular-ui перевели в 1.1.5.
В 1.0.8 есть ng-include. Это почти то же самое. Должно помочь. |
Цитата:
Я распечатаю код, вырежу, вставлю в рамочку и повешу на стенке. Будет меня радовать долгими зимними вечерами. |
Ну посмеяться мы все любители. Интересует конкретика.
Использовал такой простой вызов своего jQuery-скрипта я по одной причине - был уверен, что данная директива сработает в нужный момент (указана она в конце кода) после отрисовки всех HTML-объектов через ng-repeat. Цитата:
Применил ng-include следующим образом. Сначала повесил эту директиву на блок с основным контентом <div id="mainContent" ng-include="showDOM()">Далее написал в контроллере функцию проверки загрузки данных:
$scope.showDOM = function () {
if ($scope.data.length > 0)
return "template.html";
}
Все равно не помогает. Стабильно мой JS код грузится только при событии window.onload и таймауту хотя бы в 100 мс... |
Это не стабильно.
Попробуй найти ui-if в angularUI. |
Вот два примера как можно разместить код jquery внутри директивы
Решение 1 делаем крошечную директиву
projectModule.directive('clickhide',function(){
return function($scope,$element){
$element.children().hide();
$element.on('click',function(){
$(this).children().toggle();
});
}
})
Смотрим в работе
<!DOCTYPE HTML>
<html ng-app="project">
<head>
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="http://code.angularjs.org/angular-1.0.1.js"></script>
</head>
<body >
<script>
var projectModule = angular.module('project',[]);
// наша директива
projectModule.directive('clickhide',function(){
return function($scope,$element){
$element.children().hide();
$element.on('click',function(){
$(this).children().toggle();
});
}
})
function FirstCtrl($scope) {
$scope.data=[1,2,3,4,5,6];
}
</script>
<div ng-controller="FirstCtrl">
<ul>
<li ng-repeat="i in data" clickhide>Кликни по мне {{i}} <br/>
<ul>
<li>пример 1</li>
<li>пример 2</li>
<li>пример 3</li>
</ul>
</li>
</ul>
</div>
</body>
</html>
Помучить здесь Решение 2 Используем делегирование событией
<!DOCTYPE HTML>
<html ng-app="project">
<head>
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="http://code.angularjs.org/1.2.0-rc.3/angular.min.js"></script>
</head>
<body >
<script>
var projectModule = angular.module('project',[]);
// наша директива
projectModule.directive('clickhide',function(){
return function(scope,element){
//вопрос чем замеить setTimeout остается открытым
//так как link post это последний callback
//Впрочем содержимое можно скрыть при помощи CSS
setTimeout(function(){
$('.s',element).children().toggle();
},1)
$(element).on('click','.s',function(){
$(this).children().toggle();
})
}
})
function FirstCtrl($scope) {
$scope.data=[1,2,3,4,5,6];
}
</script>
<div ng-controller="FirstCtrl">
<ul clickhide>
<li ng-repeat="i in data" class="s" >Кликни по мне {{i}} <br/>
<ul>
<li>пример 1</li>
<li>пример 2</li>
<li>пример 3</li>
</ul>
</li>
</ul>
</div>
</body>
</html>
Помучать можно здесь Несмотря на то что я применил setTimeout это вполне безопасно так как кэлбэк таймаута гарантированно сработает после рендеринга и иначе быть не может |
Цитата:
|
Спасибо всем за советы, будем разбираться.
|
| Часовой пояс GMT +3, время: 17:19. |