http://blog.softnauts.com/2014/03/18/building-angular-directive-that-shows-content-in-new-window/
To make our life easier, we decided to write the directive for displaying its content in a new window.
We want to preserve bidirectional data binding between parent and child windows.
Also, after removing the directive from the parent window DOM - the child window should disappear.
THE GOAL
You may see exactly what we want on jsFiddle (remember to allow it to open popups).
Sample code :
<new-window>
{{code}}
<input ng-model="code" />
</new-window>
<div>
{{code}}
<input ng-model="code"/>
</div>
This code should open a new window with input and text, in a parent window should also be visible input and text, changing input value in any window should be propagated over application.
Another example:
<input ng-model="newItem" />
<button ng-click="items.push(newItem);">push!</button>
<button ng-click="items = [];">clear</button>
<div ng-repeat="code in items">
{{code}}
</div>
<new-window ng-repeat="code in items">
{{code}}
<input ng-model="code" />
</new-window>
We should see the parent window input, and we should be able to add input's content to an array by clicking "push" button. We also should see the button for cleaning an array, and finally all the elements of an array... After cleaning the array all children windows should disappear, and after adding a new element to the array, another window should appear.
With windows displayed as a result of displaying items from the array, bidirectional data binding is not preserved - do you know why? :)
READY DIRECTIVE CODE
Let's see how the final directive looks like, then we'll discuss each part.
app.directive('newWindow', ['$window', '$compile',
function($window, $compile) {
return {
restrict: 'EA',
link: function($scope, $element, attr) {
$element.on('$destroy', function() {
$scope.window.close();
});
},
controller: function($scope, $element) {
$scope.window = $window.open('', '_blank');
angular
.element($scope.window.document.body)
.append($compile($element.contents())($scope));
}
}
}
]);
OPENING WINDOWS AND BINDING DATA
controller: function($scope, $element) {
$scope.window = $window.open('', '_blank');
angular
.element($scope.window.document.body)
.append($compile($element.contents())($scope));
}
Open a new window, saving its handle in our local scope - will be essential if later we would like to close the window. The most interesting in this part is the append method parameter , which fill the newly opened window with its content. We use here the service $compile , which does not work as described in the documentation... This call should return a string with the template compiled in our scope, but it rather returns a reference to the DOM object, which will later be compiled... For our needs, it's even better - angular preserves data binding, and we display the object in a new window.
CLOSE THE WINDOW
link: function($scope, $element, attr) {
$element.on('$destroy', function() {
$scope.window.close();
});
}
If our directive is removed from the DOM tree, for example, by deleting the item from the table ng-repeat iterates, the window should disappear. Window closing code should exists in handler of $destroy event, which is emitted by the angular before the destruction of the directive. In such situation we simply close the window whose handle we saved in the local scope.
STYLING
new-window { display: none; }
We want to display the directive in a new window, while it should stay invisible in parent window.
WHAT DO WE GAIN
New window does not need to know anything about JavaScript , or about Angular , because the whole logic remains in the parent window. We don't need to think about it, and the only thing we need to do is to build content of new window.
WHAT DO WE LOSE
It's harder to prepare code for new window, as it's not enough to simply write it somewhere and click "refresh" in the browser. Debugging may also not be as easy as it was in a single-window app.
Orginally posted on Janek's Wiki