AngularJS: Как открыть файл на новой вкладке?

LIVE DEMO

Учитывая URI файла, я хотел бы открыть его на новой вкладке (не в новом окне).

Похоже, что невозможно использовать $window.open(uri, '_blank').

Итак, я попробовал следующий трюк:

var link = angular.element('<a href="uri-here" target="_blank"></a>');
angular.element(document.body).append(link);
link[0].click();
link.remove();

и он работает.

Но если я ставлю точно такой же код в обратном вызове с обещаниями, он больше не работает (вместо этого он открывает файл в новом окне).

Любая идея, что здесь происходит?

PLAYGROUND ЗДЕСЬ

Ответ 1

Из вашего кода/содержимого вы не можете заставлять браузер открывать новую вкладку (а не новое окно или наоборот). Это зависит от настроек браузера, чтобы заставить его так или иначе.

Все остальное будет представлять угрозу безопасности.

Ответ 2

Давайте понимать, как работает блокировщик всплывающих окон.

Если пользователь запускает функцию для открытия нового URL-адреса, то всплывающее блокирование позволит это (оно должно применяться к любому современному браузеру - по крайней мере, firefox, chrome)

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

Это не работает.

function openInNewTab() {
    window.open('http://stackoverflow.com','_blank');
}

openInNewTab();//fail

Это работает

<h1><button onclick="openInNewTab()">Open In New Tab - working</button></h1>

Я создал простую версию plunkr - http://plnkr.co/edit/QqsEzMtG5oawZsQq0XBV?p=preview

Итак, чтобы ответить на ваш вопрос. Это невозможно, если пользователь не разрешает его (пользователь запускает его или белый указывает на сайт).

Цитата из firefox -

Всплывающие окна или всплывающие окна - это окна, которые отображаются автоматически без вашего разрешения.

https://support.mozilla.org/en-US/kb/pop-blocker-settings-exceptions-troubleshooting

* Открыть новую вкладку/новые окна не имеет никакого значения. Блокировщик всплывающих окон все равно будет блокироваться. Это не означает, что браузер разрешит открытие на новой вкладке. Совсем случайно для некоторых браузеров по умолчанию настроены таким образом.

Обход

Вы можете попросить пользователя явно вызвать функцию для открытия на новой вкладке после выполнения фона.
Вы можете отобразить сообщение в пользовательском интерфейсе, чтобы попросить пользователя открыть URL-адрес. Пример - http://plnkr.co/edit/iyNzpg64DtsrijAGbHlT?p=preview

Ответ 3

Вы можете открывать только новые окна внутри click обработчиков событий , запускаемых пользователем.

Причиной этого является юзабилити.

Я не уверен, что все браузеры имеют такое поведение, но некоторые браузеры не позволяют сценариям открывать окна без уведомления пользователя. Представьте себе, когда вы посещаете веб-страницу, и вдруг веб-страница открывает несколько окон = > это раздражает.

Смотрите DEMO (протестировано с моим Chrome и Firefox), даже мы запускаем событие click с помощью script, браузер все еще блокирует всплывающее окно.

$("#test").click(function(){
    openInNewTab();
});

$("#test").click();

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

См. ссылку для обхода

Если я поставлю точно такой же код в обратном вызове обещания, он не работает (вместо этого он открывает файл в новом окне).

Я удивлен, что вы все еще можете открыть новое окно. Но эта проблема действительно имеет много общего с событиями click, которые запускаются пользователем.

Ответ 4

Ваша проблема в два раза, и обе складки прогибаются на неопределенной территории.


В старые времена браузеров window.open сделал именно это. – открыть новое окно. Это потому, что концепция вкладок еще не была изобретена. Когда были введены вкладки, они обрабатывались точно так же, как окна, чтобы улучшить совместимость, и эта традиция продолжается и по сей день. Это и тот факт, что window.open был только стандартизован совсем недавно, означает, что JavaScript не может различать окна и вкладки.

Нет никакого "нормального" способа указать, должна ли ссылка открываться на новой вкладке или нет. Однако вы можете использовать следующий хак: укажите размер настраиваемого окна для вызова open (через третий аргумент), например:

window.open('http://example.com', '', 'width=' + screen.width);

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


В JavaScript есть доверенные события и ненадежные события. Надежными событиями являются, например, законные клики по ссылке пользователя, тогда как ненадежным событием будет ручной вызов click() по ссылке.

Только доверенные обработчики событий могут открывать новые окна/вкладки. Это предотвращает атаки на стороне клиента, которые приводят к краху браузера или путают пользователя, быстро открывая сто вкладок на mouseover или что-то подобное.

Ваш второй пример не работает, потому что блокиратор всплывающих окон блокирует ненадежное событие, которое вы запускали с помощью click(). Хотя это вызвано реальным щелчком, асинхронный вызов между ними отключает ссылку на доверенность.

Ответ 5

рабочая версия

$http.get('https://api.github.com/users/angular').then(openInNewTab());

ИЗМЕНИТЬ ----------------

Не знаю, почему, но метод click(), вызванный из функции обратного вызова, действует иначе, чем называть его прямым.

Здесь вы можете увидеть пример с заданным интервалом.

Вот почему я вызывал функцию напрямую, а не выполнял обратный вызов.

видеть его с обратным вызовом таймера

Ответ 6

или вы можете использовать услугу $window, см. здесь: http://plnkr.co/edit/8egebfFj4T3LwM0Kd64s?p=preview

angular.module("Demo", []).controller("DemoCtrl", function($scope, $http, $window) {
  $scope.uri = 'http://martinfowler.com/ieeeSoftware/whenType.pdf';

  function openInNewTab() {

    var link = angular.element('<a href="' + $scope.uri + '" target="_blank"></a>');

    angular.element(document.body).append(link);

    link[0].click();
    link.remove();
  }

  $scope.works = openInNewTab;

  $scope.doesntWork = function() {
    $http.get('https://api.github.com/users/angular').then($window.open($scope.uri));
  };
});