13

I have a considerable amount of data to show on the screen. I need to present a simplified list so the user can choose one of the items and see it's details.

So imagine I have a component SimpleListComponent, it will hold the data and present a simplified view

export class SimpleListComponent{
    @Input() data: any[];
}

The html

<ul>
    <li *ngFor="let item of data">
        <a>{{item.name}}</a>
    </li>
</ul>

The user should be able to click on one of the itens and open in a new tab a view with that item's details. So if I have a second Component

export class DetailedViewComponent{
    @Input() item: any;
}
<div>
    <!--All fields of item here-->
</div>

Edit: The catch here is that I'm presenting data from a very customized search, so I don't have a ID to get the details from the server or any other way to get the data again. So the only way is to, somehow, pass the data that is already loaded.

How can I achieve that in angular? Give the item data to the second component and open it in a new tab?

Rohling
  • 551
  • 2
  • 5
  • 12
  • 1
    target="blank" on link or whatever – Antoniossss Aug 24 '18 at 13:08
  • Ex: window.open('/login', '_blank'), incase you want to open from .ts – Bhimashankar Mantur Aug 24 '18 at 13:16
  • Do you mean a new browser tab, or some sort of new HTML tab within your web page? Having two browser tabs open on the same Angular application is, of course, possible, but it's adds a lot of complexity if you need them to interact with each other - so it may be better to introduce some sort of virtual tabs within your page. – Mark Hughes Aug 24 '18 at 13:16
  • @MarkHughes Thanks for the comment man. So it would be a new tab in the browser, but I don't need to bind the data or anything that involver interaction between tabs. It's just to present the data in a more clean view. I think I can achieve that with target="_blank" but I'm not sure how I'd pass my item to the new component – Rohling Aug 24 '18 at 13:28
  • You can't easily pass stuff between browser tabs like that. There are some ways to do it, but I'd call them mostly hacks... so your new tab would need to load the data it needs from the server. If you had a "virtual tab" within the page, you could pass the full object instead - the cross-tab part makes that much more difficult. – Mark Hughes Aug 24 '18 at 13:43
  • @MarkHughes I see. In my case I don't have a way to get the data again from the server (edited my question to be more specific), but in worst case scenario I will stick with the virtual tab approach. Thanks. – Rohling Aug 24 '18 at 14:06

4 Answers4

20

I know this is an old post but since this is the first result when you search “how to open angular component in new tab/window” I wanted to post an answer.

If you create a route for the component and load the route in a new tab you will end up bootstrapping the app again.

So if you want to open an angular component without bootstrapping the whole app you can do it using angular portals. You can also easily pass data between the parent and the child window.

I recently has this requirement and I couldn’t find any comprehensive resource on this so I put together an article on it.

https://medium.com/@saranya.thangaraj/open-angular-component-in-a-new-tab-without-bootstrapping-the-whole-app-again-e329af460e92?sk=21f3dd2f025657985b88d6c5134badfc

Here is a live demo of the example app

https://stackblitz.com/edit/portal-simple

tsaranya
  • 201
  • 2
  • 2
  • I am going following the provided article which sounds very promising. If it works the answer should have been marked as correct one. – Mark Jul 06 '20 at 17:11
  • What happens if a user wants to navigate to https://portal-simple.stackblitz.io/assets/modal/popout.html directly in the Browser by providing this url? – Mark Jul 08 '20 at 19:21
  • popout.html is a blank html page. If you directly go to that html it will be blank. This is only for situations when you have already loaded an angular app and you want to open another component in a child browser tab by clicking a link or button not by directly changing the url. – tsaranya Jul 10 '20 at 14:27
  • So, direct navigation is not possible? – Mark Jul 10 '20 at 16:20
  • 1
    I like what you've come up with. I have this requirement in a project I'm working on. The only thing I didn't like was how much would need to be changed each time I want to be able to open a new component in a new window. I made some changes to make the service more generic so any entry component can be popped-out without modification needing to be made to the service or tokens (except your popout modal enum, but that's only if you want to). Here's the link: https://stackblitz.com/edit/angular-portal-poc – starx207 Jul 14 '20 at 15:30
  • 1
    i have published an angular library, npm package, that does what you need - "popout any part of your Angular application into a new un-docked browser child window" check it out - https://www.npmjs.com/package/angular-popout-window – shemesh Nov 24 '20 at 15:45
5

You can create a routing for DetailedViewComponent and ""

In your routing:

{
    path: 'detailed/:id',
    component: DetailedViewComponent
}

And after that On typeScript of SimpleListComponent:

public detailedPath;
ngOnInit() {
     this.detailedPath = window.location.origin + '/detailed/';
}

On your Html of SimpleListComponent:

<ul>
   <li *ngFor="let item of data">
      <a href="{{detailedPath + item.id}}" target="_blank">
   </li>
</ul>

On TypeStript of DetailedViewComponent:

public id;
constructor(private routeParams: ActivatedRoute) {
}

ngOnInit() {
    this.routeParams.params.subscribe(params => {
      this.id = parseInt(params['id']);
    });
    //Some logic to get the details of this id
}
Alex Hora
  • 124
  • 1
  • 5
  • 2
    Can you explain why would DetailedViewComponent open in the new tab? What exactly does that in your code sample? – Mark Jul 10 '20 at 19:13
  • Will that work with a lazy loaded module that would have DetailedViewComponent? – Mark Jul 16 '20 at 19:14
3

In case someone runs into the same issue I ran:

I ended using localstorage to temporarily store my object and access it from the other window.

So the code ended up like:

<a target="_blank" [routerLink]="['/details', item.name]" click="passObject(item.name)">
passObject(i){
    localStorage.setItem('i.name', JSON.stringify(i));
}

And in the details component:

ngOnInit() {
    this.item = JSON.parse(localStorage.getItem(param));
}

Another idea that I could try is implementing a message service

Rohling
  • 551
  • 2
  • 5
  • 12
  • 1
    Anyone using this approach please be aware that the browser has limitations on the length of an object you can store in local storage. OP says they have a "considerable amount of data to show" so I would not consider this a correct solution. The second example with a messaging service would not work also since the service is not shared across tabs. – user3333134 Jun 28 '19 at 14:57
1

I would suggest you do it from HTML by using the target attribute :

<a target="_blank" [routerLink]="['/detail',item.name]">

In this example "/item/:name" should be defined in your routing module.

  • I see that /detail would then route to my DetailedViewComponent, but I need to pass the whole item, not just the name. Sorry if I misunderstood your question – Rohling Aug 24 '18 at 13:35
  • You would be going to another route. On this page you could use a Resolver to execute an HTTP GET and get the requested information. Example by Alligator.io https://alligator.io/angular/route-resolvers/ If this still remains unclear , tell me and I will create an example. – Kjell Gladiné Aug 24 '18 at 13:41
  • Its clear now, your answer makes sense, it was my question that was unclear. – Rohling Aug 24 '18 at 14:08