Check out our new training course on AngularJS for Flex Developers

Submit a Form Post Asyncronously to a New Window with AngularJS - Approach 4

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 to setup the secondary app.

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. 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 service call ended and the promise object resolved.

This is one solution we considered for the issue, which uses a form post to open the new link.

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

The Setup

First, add Angular to your Application:


<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>

JQuery is also required for this approach:


<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" ></script>

Then, create an Angular Module and controller:


angular.module('test',[]);
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 Form Async Success</button>

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

</div>

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.

Remember to create the form:


<form method="post" action="https://www.jeffryhouser.com" id="myForm" target="myNewWindow">
</form>

An ID is specified, and we'll use this to get a hook to the form inside the angular code. Target is specified, and tells the form to submit to the window named 'myNewWindow'. The form action will post go back to my blog--however you could post it anywhere you want, even passing variables for processing.

Create the stub for the click method:


$scope.onButtonClick = function(openOrClose){
}

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


var newWindow = $window.open('about:blank','myCustomWindowTitle');

This uses $window.open() 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();

Next, get a link to the form tag:


var form = angular.element('#myForm')

The angular.element is used to get a handle to the form based on the form's ID. This uses JQuery under the hood, but did not work w/ the JQuery lite that is part of AngularJS, so that is why we had to use the full Jquery library earlier.

Write the success and failure functions:


defer.promise.then(function(){
form.submit();
}, function(){
newWindow.close();
});

The failure function will close the new window we created. The success function will submit the form to the new window we just opened.

Now, decide whether to resolve or reject the promise:


if(openOrClose){
defer.resolve();
} else {
defer.reject();
}

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. The user may see a blink, or anomaly in the UI. This is undesirable, but I don't know of another way.

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.

Final Thoughts

This was an interesting experiment, and it suited my client's need at the time. I always have caution about opening and controlling third party windows on the client's browser; because I don't want to build apps that overstep their bounds.

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 5.9.2.002.