Использование угловых с турбонауками

Я пытаюсь использовать структуру Angularjs в своем приложении с turbolinks. После изменения страницы не инициализируются новые eventlisteners. Это какой-то способ заставить его работать? Спасибо заранее!

Ответ 1

AngularJS против Turbolinks

Turbolinks, а также AnguluarJS могут использоваться, чтобы заставить веб-приложение быстрее реагировать в том смысле, что в ответ на взаимодействие с пользователем что-то происходит на веб-странице без перезагрузки и повторной передачи всей страницы.

Они различаются в следующем отношении:

  • AngularJS помогает вам создать богатое клиентское приложение, где вы пишете много кода JavaScript, который выполняется на клиентской машине. Этот код делает сайт интерактивным для пользователя. Он взаимодействует с сервером на стороне сервера, то есть с Rails-приложением, используя JSON API.

  • Turbolinks, с другой стороны, помогает сделать сайт интерактивным без необходимости кода JavaScript. Это позволяет вам придерживаться кода Ruby/Rails на стороне сервера и все же "волшебным образом" использовать AJAX для замены и, следовательно, переопределить только те части страницы, которые изменились.

Где Turbolinks сильна в том, что вы можете использовать этот мощный механизм AJAX без каких-либо действий вручную и просто кода Ruby/Rails, может возникнуть этап, по мере роста вашего приложения, где вы хотели бы интегрировать инфраструктуру JavaScript, такую ​​как AngularJS,

Особенно на этом промежуточном этапе, когда вы хотели бы последовательно интегрировать AngularJS в ваше приложение, по одному компоненту за раз, может иметь смысл запускать Angular JS и Turbolinks вместе.

Как использовать AngularJS и Turbolinks вместе

Использовать обратный вызов для ручного бутстрапа Angular

В коде Angular у вас есть строка, определяющая ваш прикладной модуль, примерно так:

# app/assets/javascripts/angular-app.js.coffee
# without turbolinks
@app = angular.module 'MyApplication', ['ngResource']

Этот код запускается при загрузке страницы. Но поскольку Turbolinks просто заменяет часть страницы и предотвращает всю загрузку страницы, вы должны убедиться, что приложение Angular правильно инициализировано ( "загружено" ) даже после таких частичных перезагрузок, сделанных Turbolinks. Таким образом, замените указанное выше объявление модуля следующим кодом:

# app/assets/javascripts/angular-app.js.coffee
# with turbolinks
@app = angular.module 'MyApplication', ['ngResource']

$(document).on 'turbolinks:load', ->
  angular.bootstrap document.body, ['MyApplication']

Не загружать автоматически

В учебниках вы часто видите, как автоматически загружать приложение Angular, используя атрибут ng-app в вашем HTML-коде.

<!-- app/views/layouts/my_layout.html.erb -->
<!-- without turbolinks -->
<html ng-app="YourApplication">
  ...

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

Таким образом, просто удалите этот атрибут ng-app:

<!-- app/views/layouts/my_layout.html.erb -->
<!-- with turbolinks -->
<html>
  ...

Дополнительная литература

Ответ 2

Turbolinks пытается оптимизировать рендеринг страниц и будет конфликтовать с обычным bootstraping AngularJS.

Если вы используете Turbolinks в некоторых местах вашего приложения, а некоторые части используют Angular. Я предлагаю это элегантное решение:

Каждая ссылка на страницу angularapp (где вы используете ng-app = "appname" ) должна иметь этот атрибут:

<a href="/myapp" data-no-turbolink>Say NO to Turbolinks</a>.

Второе упоминание о Stackoverflow явно перезагружает/загружает каждое ng-приложение, обрабатывая страницу: load event. Я бы это навязчиво, не говоря уже о том, что вы потенциально загружаете что-то, что не на странице, поэтому тратит ресурсы.

Я лично использовал вышеупомянутое решение.

Надеюсь, что это поможет

Ответ 3

В случае ошибки

Неподготовленная ошибка: [ng: btstrpd] Приложение уже загружено с этим Элемент 'document'

после обновления до angular 1.2.x вы можете использовать ниже, чтобы устранить проблему.

angular.module('App').run(function($compile, $rootScope, $document) {
  return $document.on('page:load', function() {
    var body, compiled;
    body = angular.element('body');
    compiled = $compile(body.html())($rootScope);
    return body.html(compiled);
  });
});

В предыдущем посте @nates предлагалось изменить angular.bootstrap(document, ['YourApplication']) на angular.bootstrap("body", ['YourApplication']), но это вызывает появление несвязанного содержимого.

Ответ 4

Turbolinks не совсем понятна с клиентской средой MVC. Turbolinks используется, чтобы вырезать все, кроме тела, из ответа сервера. С клиентским MVC вы должны просто передавать JSON клиенту, а не HTML.

В любом случае turbolinks создает свои собственные обратные вызовы.

page:load
page:fetch
page:restore
page:change

Ответ 5

Добавьте в приложение следующий обработчик событий.

CoffeeScript:

bootstrapAngular = ->
  $('[ng-app]').each ->
    module = $(this).attr('ng-app')
    angular.bootstrap(this, [module])

$(document).on('page:load', bootstrapAngular)

JavaScript:

function bootstrapAngular() {
  $('[ng-app]').each(function() {
    var module = $(this).attr('ng-app');
    angular.bootstrap(this, [module]);
  });
};
$(document).on('page:load', bootstrapAngular);

Это приведет к запуску приложения angular после каждой страницы, загруженной Turbolinks.

Кредит https://gist.github.com/ayamomiji/4736614

Ответ 6

Плагин jquery.turbolinks может инициировать загрузку модулей с помощью директив ng-app. Если вы пытаетесь вручную загружать модули, jquery.turbolinks может привести к ошибкам ng: btstrpd. Одно из предостережений, которое я обнаружил, заключается в том, что jquery.turbolinks полагается на событие page:load, которое может запускаться до того, как закончится выполнение всех тегов <script> для каждой страницы. Это может привести к ошибкам $injector:nomod, если вы включаете определения модулей за пределы application.js. Если вы действительно хотите, чтобы ваши модули были определены в отдельных файлах javascript, которые включены только на определенные страницы, вы можете просто отключить turbolinks на любых ссылках на эти конкретные страницы через data-no-turbolink.

Ответ 7

Основываясь на комментариях, которые я видел, единственный допустимый сценарий для использования обоих вместе таким образом, что Angular будет конфликтовать с Turbolinks (например, когда я разрешаю Angular обрабатывать некоторую маршрутизацию), это если я иметь существующее приложение, которое я пытаюсь подключить к Angular.

Лично, если бы я сделал это с нуля, я думаю, что лучшим решением было бы решить, что должно обрабатывать маршрутизацию и придерживаться этого. Если Angular, чем избавиться от Turbolinks → , это не поможет вам, если у вас есть что-то близкое к одностраничному приложению. Если вы разрешите Rails обрабатывать маршрутизацию, просто используйте Angular для организации поведения на стороне клиента, которое не может обрабатываться сервером при обслуживании шаблонов.

Я пропустил здесь сценарий? Мне не кажется элегантным, чтобы попытаться разделить обязанности маршрутизации между различными фреймворками даже в большом приложении... Есть ли другой сценарий, когда Turbolinks будет вмешиваться в Angular, кроме обновления страницы или перехода к новой маршрут?

Ответ 8

Использование Turbolinks и AngularJS вместе

+1 для @fiedl для отличного ответа. Но я предпочитаю использовать page:change совместно с page:load, потому что это дает некоторую гибкость: DOM может получать событие page:load из источников, отличных от turbolinks, поэтому вы можете не захотеть иметь один и тот же обратный вызов.

Наблюдая за page:change, тогда page:load должно ограничивать ваше поведение обратного вызова исключительно событиями, инициируемыми турболинками.

function boostrapAngularJS () {
    angular.bootstrap(document.body, ['My Application']);
    addCallbackToPageChange();
}
function addCallbackToPageChange() {
    angular.element(document).one('page:change', function () {
        angular.element(this).one('page:load', boostrapAngularJS);
    });
}
addCallbackToPageChange();

(Это позволит/требует, чтобы вы сохраняли свое объявление ng-app в своем html, как обычно, при работе с AngularJS.)

Ответ 9

Turbolinks автоматически извлекает страницу, свопирует ее в <body> и объединяет ее <head>, все без затрат на полную загрузку страницы.

https://github.com/turbolinks/turbolinks#turbolinks

Итак, вместо директивы append ng-app в элементе <html>, мы можем просто сделать это в элементе <body>.

<html>
  <body ng-app="yourApplicationModuleName">
  </body>
</html>