Check out our Angular Book Series.

Open a Link Asyncronously in a New Window with AngularJS - Approach 3

I was working on a client's AngularJS project. When the user clicked a button to open another application, we wanted to make a service call to log the request and make sure we redirected the user to the right place. Some users would see different versions of the other application, and the service call told us the proper variables to pass.

Unfortunately, after we made the service call the link would not open. I started to research for more information as to what the problem may be. Basically, a browser won't open external pages if they aren't done in response to a user interaction such as clicking a button. The browser assumed user request was ended by the time our promise object resolved.

This is how I solved the issue.

By, the way, this is the third in the series about opening links through AngularJS. Check out the first and second.

The Setup

First, add Angular to your Application:

<script src="//"></script>

Then, create an Angular Module and controller:

angular.module('test').controller('someController',['$scope','$window','$q', function($scope,$window,$q){

Three elements are injected into the controller. $scope is the common service used to communicate between the view and the controller. $window gives you an Angular reference to the browser's window object. We'll use $window to open the new page. Finally, $q is added. We are going to use $q to create a promise object to simulate an actual remote service call.

Open the new page

There are multiple steps that we took to create the new page. The new page must be open with user interaction, so let's create the buttons first:

<body ng-app="test">

<div ng-controller="someController">
<button ng-click="onButtonClick(true)" >Open Link Async Success</button>

<button ng-click="onButtonClick(false)" >Open Link Async Refuse</button>


This code contains two buttons; one that will successfully open the page and another that will not--as if the service call was rejected for reason. Both call the same onButtonClick method, passing in a Boolean value specifying whether the link should be open or not:

Create the stub for the method:

$scope.onButtonClick = function(openOrClose){

The new window must be open in response to the click; so first open the window:

var newWindow = $'about:blank','myCustomWindowTitle');

This uses $ to open the new window and it opens to a blank about page.

Next, make the remote service call, in our case we simulate it using $q. Create the promise:

var defer = $q.defer();

Write the success and failure functions:

newWindow.location.href = ''
}, function(){

The failure function will close the new window we created. The success function will change the location of the window, in essence opening the new page.

Now, decide whether to resolve or reject the promise:

} else {

The decision is made based on the value of the openOrClose argument passed into the onButtonClick() method.

Load the app and you'll see something like this:

A boring UI. Click the 'refuse' button and the service call is so quick and the window will close as quick as it would open. This is undesirable, but I don't know of another way. The user may see a blink.

Click the open button, and you'll see this:

The link to my blog will open in a new tab, based on my default browser settings.

Play with the code here.

What is Next?

The final entry in this series will show you how to submit a form post after asynchronously making a call. That will be out next week.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version