1

My project is using the Angular + Nativescript code sharing project to build for both web as well as mobile for Android and IOS.

The problem is trying to remove the Action Bar for the entire application. I have read a few posts on this issue however none of the solutions seem to work or at the very least end up not being a very good solution.

I have tried to add <Page actionBarHidden="true"></page> however this did not work at all in app.component or in other components that contain routes such as a home.component with the route home. Such as:

<Page actionBarHidden="true">
  <StackLayout orientation="vertical">
    <Image src="res://buy" stretch="none" horizontalAlignment="center"></Image>
  </StackLayout>
</Page>

I also tried an approach specifically to android to see if I could fix this through the AndroidManifest.xml file like I would if I made a native Android App by updating the android manifest to take away the action bar. For a sanity test I also tried using it through styles.xml such as:

<style name="AppThemeNoActionBar" parent="AppTheme">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>

After these failed attempts I tried the following code that was recommend by others involving Page such as:

import { Page } from 'tns-core-modules/ui/page';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

  ngOnInit() {
    this.page.actionBarHidden = true;
  }
}

The problem with this approach is for this solution to work I need to create a tns file for every component that has a route just to call this to remove the app bar completely because each page seems to handle their own app bar. Now this is not really maintainable on a large scale as well as it forces me to create a tns file for all components that have a route.

Lastly, I saw an example where we have a service that has this logic for this.page.actionBarHidden as well as rootFrame.actionBarVisibility = 'never' and you would call that in the component.ts file without needing to create a component.tns.ts file however the problem with this is now you need to create a regular service that has an empty function to be called, create a tns file of that service for the actual logic, as well as have to call it in every component that has a route.

As you can see some solutions will not work at all and others require a lot of extra code and maintainability especially as the app grows making them not very desirable solutions.

I will continue to look into this as well as I believe there has to be a clean solution to this.

halfer
  • 19,824
  • 17
  • 99
  • 186
L1ghtk3ira
  • 3,021
  • 6
  • 31
  • 70

2 Answers2

5

You may simply set actionBarVisibility to never on your page-router-outlet itself.

<page-router-outlet actionBarVisibility="never"></page-router-outlet>
Manoj
  • 21,753
  • 3
  • 20
  • 41
  • Hey Manoj, thanks for your Answer. This does work as well as I was able to see it in the docs for it, must of missed it the first time. As well as surprisingly I did not this as an 'answer' on other stack posts or github issues. Thanks. – L1ghtk3ira May 13 '19 at 09:41
  • It works on my end and I have seen people using this widely. So if you still have issues, please share a sample where the issue can be reproduced. – Manoj May 13 '19 at 09:49
0

After more research and testing I was able to find a solution that is working as intended. As well as I'll explain the reasoning as to why some of the other methods did not work as intended.

First off is the <Page actionBarHidden="true">. According to my research and testing this only works if you are building specifically for nativescript only and not as an Angular + Nativescript Code Sharing Project. The reason for this is when using Angular for web development we are using <router-outlet></router-outlet>, for those new to Angular this handles changing the routes within the application and showing the correct component based off the route.

Now when we start doing the Nativescript we would like to reuse as much code as we can including our routes. In which case we end up using <page-router-outlet></page-router-outlet> in our app.component.tns.html file. Much like Angular when we change routes this will control the showing of the correct component based off the route.

The problem occurs because the <page-router-outlet></page-router-outlet> creates a <Page></Page> automatically for us. So putting one in our template whether it is the app.component.tns.html or the home.component.tns.html will not work because it already has one we just cant get an easy reference to it in our html file.

For the problem of trying to do it through the android manifest in your App_Resources folder I have also had no luck with this. I believe because when we use <page-router-outlet></page-router-outlet> Nativescript internally changes the manifest to reflect and by default force upon us the action bar. I have tried setting it a few different ways and regardless it is the same. I was able to get it working though the Platform folder however I would not recommend this as sometimes we need to remove and add platforms and this could result in us forgetting or having to keep implementing the same solution waisting precious dev time.

For the next issue using this.page.actionBarHidden = true; this issue falls into the same category as the first issue. When you try doing it in your app.component.tns.ts file it will never work with that command alone because we are using <page-router-outlet></page-router-outlet>. Essentially the AppComponent does not see the page at all because it does not belong to it. When the app loads if your first default route is pointed to the home Component then you would need to use that this.page.actionBarHidden inside the Home component. However, to not fail in web you would need to create a tns file for every component that has a route to have that logic in there specifically and that is not practical in terms of maintainability.

For the last issue we should not have to duplicate code. In this case that would be calling the function on every component.tns.ts file just to remove something we want app wide. As well as to create extra tns files that we don't need and managing another service to run one piece of code that only applies to nativescript.

The Solution

This is the simplest solution I could fine that allows the handling of the action bar to be in one location so that it is easy to change at any time. The solution is to use Angular's Router. What we do in our ngOnInit is we subscribe to the Routers' events. Then when a Router event fires we check and validate if it is the end of Navigation to the component being routed to. At this stage when that check passes the application has already navigated to route and it is now safe for us to get a reference to that Frame or Page and remove the action bar.

Nativescript has a function called topMost() that allows us to get reference to the Frame or Page being shown. According to their code definition: Gets the topmost frame in the frames stack. An application will typically have one frame instance. Multiple frames handle nested (hierarchical) navigation scenarios.

So using this we can easily get a reference to the Page that is currently the frame being displayed. Now that we have the frame being displayed we simply set the actionBarVisibility to false;

import { Component } from '@angular/core';
import { Page } from 'tns-core-modules/ui/page';
import { Router, NavigationEnd } from '@angular/router';
import { topmost } from 'tns-core-modules/ui/frame/frame';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  constructor(private _Router: Router, private page: Page) {

  }

  ngOnInit(): void {

    this._Router.events.subscribe((ev) => {
      if (ev instanceof NavigationEnd) {
        const rootFrame = topmost();
        rootFrame.actionBarVisibility = 'never';
      }
    });
  }
}
L1ghtk3ira
  • 3,021
  • 6
  • 31
  • 70