Javascript-форум (https://javascript.ru/forum/)
-   Angular.js (https://javascript.ru/forum/angular/)
-   -   Конфликт jQuery скрипта и AngularJS (https://javascript.ru/forum/angular/42160-konflikt-jquery-skripta-i-angularjs.html)

defreend 15.10.2013 14:52

Конфликт 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()

Olival888 15.10.2013 15:15

http://angular.ru/guide/understanding_directives

И конкретнее: "Если необходимо подождать, пока в $scope не поступят данные, воспользуйтесь ng-if для отложенной загрузки блока DOM."

DjDiablo 15.10.2013 15:29

Цитата:

Этот документ (косвенно) пытается объяснить, как директивы AngularJS и связанный движок компиляции, работают так, чтобы вы не разбрасывали лапшу по кругу
Угарная документация :)

P.S. Видимо скрипт срабатывает раньше чем сформирован DOM, это не конфликт. Следите напрямую за порядком инициализации. В идеале превратите ваш скрипт в директиву, или в случае если плагин не ваш то оберните вызов плагина директивой.

Также не стоит при написании плагинов забывать про функцию live, но по прежнему ваш jQuery код должен быть в директиве или вызываться из нее. Ангуляр гарантирует срабатывание директив в постоянном и предсказуемом порядке.

Olival888 15.10.2013 15:33

Какая есть )))
Лучше такая, чем никакой. Тем более полезные дела делают парни!

defreend 15.10.2013 16:29

Спасибо за советы.

Попробовал я использовать загрузку jQuery-скрипта через директиву. Создал простенькую директиву:
.directive('jqueryscript', function () {
    return {
        restrict: 'E',
        template: '<script type="text/javascript" src="js/jQueryJS.js"></script>'
    }
})

и вызвал ее в конце HTML-кода. Так все работает, но если с моего jQuery-скрипта убрать таймаут, то скрипт перестает выполнятся даже локально...

Заметил, что при использовании window.onload вместо $(document).ready все работает без ошибок, но это не оптимально из-за долгой загрузки скриптов...

Olival888 15.10.2013 16:31

Цитата:

Сообщение от Olival888 (Сообщение 276548)
http://angular.ru/guide/understanding_directives

И конкретнее: "Если необходимо подождать, пока в $scope не поступят данные, воспользуйтесь ng-if для отложенной загрузки блока DOM."

Не помогло???

defreend 15.10.2013 17:54

Цитата:

Сообщение от Olival888 (Сообщение 276560)
Не помогло???

Как я понял, ng-if работает начиная с версии Angular 1.2 , а у меня последняя релизная - 1.08.
При подключении 1.2 версии - начинают вылазить куча других ошибок и несовместимостей...

Olival888 15.10.2013 17:58

Вообще то её из angular-ui перевели в 1.1.5.
В 1.0.8 есть ng-include. Это почти то же самое. Должно помочь.

DjDiablo 16.10.2013 03:59

Цитата:

.directive('jqueryscript', function () {
    return {
        restrict: 'E',
        template: '<script type="text/javascript" src="js/jQueryJS.js"></script>'
    }
})

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

defreend 16.10.2013 15:57

Ну посмеяться мы все любители. Интересует конкретика.

Использовал такой простой вызов своего jQuery-скрипта я по одной причине - был уверен, что данная директива сработает в нужный момент (указана она в конце кода) после отрисовки всех HTML-объектов через ng-repeat.


Цитата:

Сообщение от Olival888 (Сообщение 276574)
В 1.0.8 есть ng-include. Это почти то же самое. Должно помочь.


Применил ng-include следующим образом. Сначала повесил эту директиву на блок с основным контентом
<div id="mainContent"  ng-include="showDOM()">
Далее написал в контроллере функцию проверки загрузки данных:
$scope.showDOM = function () {
          if ($scope.data.length > 0)
            return "template.html";
      }

Все равно не помогает. Стабильно мой JS код грузится только при событии window.onload и таймауту хотя бы в 100 мс...

Olival888 16.10.2013 16:27

Это не стабильно.
Попробуй найти ui-if в angularUI.

DjDiablo 16.10.2013 17:39

Вот два примера как можно разместить код 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 это вполне безопасно так как кэлбэк таймаута гарантированно сработает после рендеринга и иначе быть не может

Shitbox2 17.10.2013 03:51

Цитата:

не разбрасывали лапшу по кругу
Это не из официальной документации, это я добавил перевод из Ангулярской вики ))) Видимо, какая-то английская идиома)

defreend 17.10.2013 17:57

Спасибо всем за советы, будем разбираться.


Часовой пояс GMT +3, время: 16:36.