Я пытаюсь использовать структуру 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>
...
Дополнительная литература
- Загрузите AngularJS: http://docs.angularjs.org/guide/bootstrap
- Railscasts на Turbolinks (объясняет обратные вызовы): http://railscasts.com/episodes/390-turbolinks
- Демо-приложение: https://github.com/fiedl/rails-5-angular-and-turbolinks-demo
Ответ 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.
Ответ 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>