I am using Angular's DomPortalHost to open a child component in a new browser window. It works for the most part.
Here is a working prototype of opening a child component in a new browser window:
https://stackblitz.com/edit/portalfun
I am able to pass data to and from child component - works great right?
Well.. when I have let's say, a map in the new browser window some of the map events seem to think the map exists in the original browser window. See:
https://www.youtube.com/watch?v=0387htqmXZw
Hilarity ensues:
I am able to click once in the new window to begin a selection (circle, etc) but not a second time. Using the view +/- controls seems to work fine. However, the map navigation/scrolling and the selection events think they are controlled from the original window.
The endgame for this little innovation project was to pass whatever data was selected in the map (syncing the grid you see in the background and the map). This works fine when I don't use DomPortalHost (that area below the grid is where the map was originally and it functions correctly).
I think that because *cdkPortal (see the stackblitz) is technically inside the original browser window:
<window *ngIf="showPortal" [dataFromParent]="dataToPass" (dataToParent)="this.onClosed($event)">
</window>
selector: 'window'...
<ng-container *cdkPortal>
<h1>Child component window</h1>
<div>{{dataFromParent}}</div>
<a class="btn-3" (click)="emitClose()">Close Window</a>
You can also close the parent window, or navigate to a different route. It will close the child window component.
</ng-container>
It's as if the map think's its been rendered in the original window, but is actually rendered in the new window.
The closest.. discovery that i've had was that some of the event handling has a [[Scope]] property set to the original window - not the new on. However I don't see how to overwrite this property.
If anyone has any ideas, resources, or a better approach please feel free to let me know. This is part of an innovation sprint, but it'd be cool to get it working as i'm sure it has a lot of use cases for others out there.
Imagine opening child components and passing data back and forth in new windows.. and not having to run a second cloned app or deal with the overheard of state management :)
Related
In my React app, I want to create a popup window that renders a table with some data. However, I want to make it render in a separate browser window instance as opposed to a modal that is attached to the app's DOM. Most of my research has led me to third party component libraries that just render an in-DOM modal just in different ways. What is the best way to create my desired effect, where clicking the "Open" button creates a new browser window instance that renders the table component?
Thanks
hmm.. maybe try the window.open() syntax
https://developer.mozilla.org/en-US/docs/Web/API/Window/open
I'm playing around with a few ideas for a project, and one of them needs to somehow have communication between 2 different browser pages/windows/tabs. My goal is this:
I have a main page that has a link that opens a new tab/window. In that window, there is the choice to 'navigate' a part of the main page. The issue is, to my knowledge, there are no physical ties between open windows (and no handle on the 'parent' window accessible by the child).
I've been trying to use opener to reference the parent window, but functions and elements are not responding to my calls from the child.
Is there any way for a child/other window to access elements/functions on a parent window?
I'm attempting to avoid using simulated tabs/frames (which would be easy enough to just reference the parent, or window element to accomplish the goal).
Yes, actually that is possible. If you use window.open() in JavaScript, you can use window.opener. and submit whatever requests you would normally make. Like:
window.opener.document.getElementById('id').innerHTML = "hello";
or using jQuery,
$(window.opener.document).find('#tableInParent').html("hello");
Read more here: http://wisercoder.com/javascript-jquery-parent-windows/
JSFIDDLE HERE
I hope this helps!
I have been working on this task off and on for awhile trying to find an optimal solution (other than telling users to disable popup blocking) and am stumped.
Essentially how it works is this (I omit code because there is a lot of it and propriety info):
I have an angular app implemented in an angular and utilizes fullcalendar.js who's content I want to print. Inside my angular controller I have the jQuery that manages the calendar itself (don't hit my fingers with a ruler please :) )
I want a specific set of styles when I want to print the calendar, so I have a directive that prepares all the content to be ported, and then use a uniform angular factory that is used for all printing activities. This uniform factory opens a new window that contains all the new styles I want and, via a callback, "cleans up" the HTML, which in my case I use for porting the HTML content of the calendar over to the new window.
So the flow basically is this: User clicks print button -> click event in calendar print directive is invoked, the directive calls the factory. -> Factory opens a new window and ports the content via the callback from the directive and then calls JavaScript's print() to print the window.
The problem I am encountering is this:
The print works fine on PC and Mac, but on iOS safari, the window does not pop up. I found that the issue was because iOS Safari requires all new window popups to be inside a click event.
To get around this, I thought I would add some modification to the uniform factory to suit my case: I would open a new window in the directive's click event, then pass a reference of that window into the factory, which can then use the reference to add the html content to its body. This introduced another issue with iOS Safari in that it stalls javascript execution of parent windows if a child window is open, so once the new window is open, the generation of the HTML and the calling of the factory is stalled until the user switches back to the parent tab. This is the point where I got stumped. Any suggested way to get around these issues? Or would I be stuck telling the user to disable popup blocking?
once the new window is open, the generation of the HTML and the
calling of the factory is stalled...
Can you change so the generation of HTML and factory call is made before opening the new window? Otherwise it sounds like you need to avoid the popup.
If you want to display another view in the same window, use ngInclude.
You can choose to switch the path of the ngInclude to swap the HTML or combine with ngShow to show and hide the correct parts when the user clicks.
It sounds like you use a factory as a parent scope and if so it should be converted to a controller that acts as a global scope above the different views.
If this is on the right track I could make a plunkr out of it.
Also, check out fullcalendar-ui for a premade directive if you want to go towards best practice.
Good luck!
After ~3 times coming and going from this over the course of a month, I finally figured it out.
Inside my directive that prepares the content to be printed, I generate a new calendar, then call the rest of the code (including the factory that opens a new window) inside a document.ready. Having the code inside the ready check seems to cause iOS Safari to think it is no longer directly inside a click event, so it would sometimes block the new window popup. Removing the document.ready check seems to have made it work, and has no ill effect on the other browsers.
I decided to create a function inside the directive for the factory call and call inside a document.ready if not iOS, otherwise just call it, to preserve functionality for desktop browsers.
The Filepicker.io modal widget (specifically the "IMAGE_SEARCH" service) appends to the window.history in the DOM after a search is made. This creates an issue working with Backbone.js when attempting to go back a previous page.
What causes this, and is there any way to prevent it?
[edit] Incorrectly referenced "IMAGE_SEARCH"
What causes this:
Navigation around the modal manipulates window.location.hash for compatibility with the window view and a number of other conveniences. Why these changes are affecting the window.history outside the iframe sandbox, I'm not sure.
How to prevent it:
I'm looking into whether we are leaking state somehow, but one easy way to prevent it is to use the {container: 'window'} option for filepicker.pick(), so that the dialog is created in a separate window.
I'm working on creating a Javascript Tab library. Actually, it's already been developed and is working great. But it's due for a rewrite to fix some underlying annoyances and quirks we've found while using it. Anyway, here's the current model.
The current model has a TabSet object, which houses the main functions for the tab library: addTab, removeTab, showTab, hideTab, and related history functions. Then there is a Tab object that contains the data/methods related to the tab: showThrobber, hideThrobber, reload, and creating the actual DOM elements for the tab. Now, you can see this is a bit disjointed. TabSet handles showing a tab and hiding a tab and Tab handles reloading the tab.
Here's the question: What is the best way to organize the methods for this tab library. The problem we are running in to is that the current model, while disjointed, makes sense. TabSet is indeed showing a tab, hiding a tab and removing a tab. But the Tab itself is indeed being shown, hidden and removed. Really, all the function make sense to be in either class: TabSet or Tab.
Let's use an analogy. When someone needs to talk, everyone needs to stop talking. There are two ways for this to happen. 1) The leader (TabSet) tells everyone to stop talking and then tells the speaker to start talking. 2) The speaker tells everyone to shutup and starts talking. It makes sense to have the controller tell other Tabs to hide and tell the new Tab to show. But it also makes sense to have the Tab tell all the other Tabs to hide and then show itself.
What are your thoughts?
Personally, I'd design it so that a Tab only knows about itself and the TabSet that is managing it. It wouldn't carry a reference to the other tabs.
I'd put show() method on Tab; internally it would ask the TabSet to hide all other tabs and show itself.
I'm assuming exactly one tab must be shown at all times, so there's no point in having a public method to hide an individual tab.
The idea behind that design is that you have less error checking to worry about. If your TabSet object had a showTab(tab) method, you'd have to check to make sure that the tab being passed in was actually one of the tabs in the set.
Usually when I design an API my first priority is to make it hard or impossible to pass in invalid inputs.