skip to Main Content

I need to deliver an Angular application to an external team. When they try to load directly a page they get a 404 Not found error. The server is an Apache and I haven’t access to this server.

I have asked them that they should configure the server according to documentation (rewrite rules): https://angular.io/guide/deployment#server-configuration but they refuse to do it. I have no other choice. I need to run the Angular application anyway or redo the application completely using directly html and js.

I need a mechanism that loads always index.html and redirects to the destination page.

This is the build command:

ng build --prod --base-href=./

I’ve also tried attaching the rewrite rules in a .htaccess in the same folder than my index.html but it doesn’t work for them either, maybe because they haven’t enabled mod_rewrite:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

2

Answers


  1. Chosen as BEST ANSWER

    I don't like the solution I found, but it is the only one I have achieved. It is cumbersome, makes maintenance difficult and should not be used in large applications. In my case, maintenance is not a problem and the application will practically not grow in the future.

    Ideally, the server should be configured with rewrite rules to avoid all this extra code.

    First: all the urls must load index.html. For this I've created an static file like onepage.html, otherpage.html, and so on. If I have deeper paths I need to create folders like usersuserspage.html. The structure of my folders would look like this:

    src
        index.html
        onepage.html
        otherpage.html
        users
            userspage.html
        ...
    

    Then I've edited this files to redirect to index.html from its folder. For onepage.html, otherpage.html:

    <!doctype html>
    <html></html>
    <script>
        window.location.href = './index.html';
    </script>
    

    For usersuserspage.html I need to rise one level:

    window.location.href = '../index.html';
    

    Second: I need a component (MenuComponent) to be loaded when there is no match. For this I configure my app-routing.module.ts file in this way:

    const routes: Routes = [
      { path: 'onepage.html', component: OneComponent },
      { path: 'otherpage.html', component: OtherComponent },
      { path: 'users/userspage.html', component: UsersComponent },
      // ...
      { path: '**', component: MenuComponent }
    ];
    

    Third: I've added to MenuComponent.html all my urls as routerLinks:

    <a id="onepage" routerLink="/onepage.html" [queryParams]="oneParams"></a>
    <a id="otherpage" routerLink="/otherpage.html" [queryParams]="otherParams"></a>
    ...
    <a id="users-userspage" routerLink="/users/usersPage.html" [queryParams]="usersParams"></a>
    

    And my MenuComponent.ts forward the document.referrer params using propertys and force the click event using the routeLink of the page requested:

    oneParameters = {
      size: '',
      color: '',
      // ...
    }
    // other properties ...
    
    ngOnInit() {
      const paramString = document.referrer.substring(document.referrer.indexOf('?') + 1);
      const pairs = paramString.split('&');
      // fill properties with params ...
    }
    
    ngAfterViewInit() {
      this.loadScript();
    }
    
    loadScript() {
      if (document.referrer.includes('/onepage.html')) {
        let el = (document.getElementById("onepage") as HTMLAnchorElement);
        el.click();
      }
      else if (document.referrer.includes('/otherpage.html')) {
        let el = (document.getElementById("otherpage") as HTMLAnchorElement);
        el.click();
      }
      else if (document.referrer.includes('/users/userspage.html')) {
        let el = (document.getElementById("users-userspage") as HTMLAnchorElement);
        el.click();
      }
      // ...
    }
    

    I am quite new to Angular and I am sure that it can be done better, especially the mapping of parameters to the properties. I hope nobody is forced to use this method.


  2. The other choice when you not available to setup rewrite rules on the server (specially when you are hosting the app in a third part host), is to use a old resource in Angular. Add {useHash: true} parameter in forRoot method:

    @NgModule({
      imports: [ RouterModule.forRoot(routes, {useHash: true}) ],
      exports: [ RouterModule ]
    })
    

    Automatically, any url pointed to http://yoururl.com/products, for example, will be rewrite to http://yoururl.com/#/products. You will just need to review for your menu and links to point to #/products, instead of /products.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search