Angular-cli: "location.hostname" is resolved to [Object%20Object] in production build

Created on 12 Feb 2017  Â·  6Comments  Â·  Source: angular/angular-cli

Please provide us with the following information:

OS?

Mac OSX (El Capitan)

Versions.

>
@angular/cli: 1.0.0-beta.30
node: 7.5.0
os: darwin x64
@angular/common: 2.4.6
@angular/compiler: 2.4.6
@angular/core: 2.4.6
@angular/forms: 2.4.6
@angular/http: 2.4.6
@angular/platform-browser: 2.4.6
@angular/platform-browser-dynamic: 2.4.6
@angular/router: 3.4.6
@angular/compiler-cli: 2.4.6

Repro steps.

The issue occurred when I tried to retrieve the current url scheme/protocol and hostname dynamically using "window.location object".

let url = location.protocol +'//api.' + location.hostname + '/';
console.log(url);

When ng build is called in development mode, code works as expected, however, while compiling for production (ng build --prod --aot; which safely compiles) I receive an unexpected "[Object Object]" in console while attempting to retrieve the url. Why does this happen and how do i resolve this problem.

I had set this up as part of a config file. Please see below

my config file

import { OpaqueToken } from "@angular/core";

export let APP_CONFIG = new OpaqueToken("app.config");
export interface IAPPCONFIG{
    apiUrl: string,...}
export const config: IAPPCONFIG = {
    apiUrl: window.location.protocol +'//api.' + window.location.hostname + '/',
...
}

where config is used

import {  APP_CONFIG, IAPPCONFIG } from './common/config';

export class AuthorizationService {
    constructor(private authHttp: AuthHttp, @Inject( APP_CONFIG ) private config: IAPPCONFIG) {
    }

getAuth(loginDetail: Login): Observable<Response> {
        let url = this.config.apiUrl + 'oauth';
   ...........
        let response = this.http.post(url, body, {headers: contentHeader});
        return response;
    }

The log given by the failure.

POST http://www.example.com/[object%20Object]//api.[object%20Object]/oauth 404 (Not Found) polyfills.db0a652….bundle.js:30 
e @ polyfills.db0a652….bundle.js:30
t.scheduleTask @ polyfills.db0a652….bundle.js:37
n.scheduleMacroTask @ polyfills.db0a652….bundle.js:37
(anonymous) @ polyfills.db0a652….bundle.js:30
send @ VM959:3
(anonymous) @ vendor.f3f572f….bundle.js:782
t._trySubscribe @ vendor.f3f572f….bundle.js:1
t.subscribe @ vendor.f3f572f….bundle.js:1
t.call @ vendor.f3f572f….bundle.js:346
t.subscribe @ vendor.f3f572f….bundle.js:1
e.submitForm @ main.1a773e9….bundle.js:1
t.handleEvent_24 @ main.1a773e9….bundle.js:8
e.object.i @ vendor.f3f572f….bundle.js:388
e.__tryOrUnsub @ vendor.f3f572f….bundle.js:2
e.next @ vendor.f3f572f….bundle.js:2
e._next @ vendor.f3f572f….bundle.js:2
e.next @ vendor.f3f572f….bundle.js:2
e.next @ vendor.f3f572f….bundle.js:52
e.emit @ vendor.f3f572f….bundle.js:388
e.onSubmit @ vendor.f3f572f….bundle.js:171
e.handleEvent @ main.1a773e9….bundle.js:1
t.handleEvent_24 @ main.1a773e9….bundle.js:8
(anonymous) @ vendor.f3f572f….bundle.js:614
t.invokeTask @ polyfills.db0a652….bundle.js:37
onInvokeTask @ vendor.f3f572f….bundle.js:451
t.invokeTask @ polyfills.db0a652….bundle.js:37
n.runTask @ polyfills.db0a652….bundle.js:37
invoke @ polyfills.db0a652….bundle.js:37

Mention any other details that might be useful.

using window.location object directly (without importing value from config file) in the component/class works as expected in both production and development builds:

import { APP_CONFIG, IAPPCONFIG } from './common/config';

export class AuthorizationService {
constructor(private authHttp: AuthHttp, @Inject( APP_CONFIG ) private config: IAPPCONFIG) {
}

getAuth(loginDetail: Login): Observable {

// used window.location directly
let url = location.protocol +'//api.' + location.hostname + '/' + 'oauth';
console.log(url);
...........
let response = this.http.post(url, body, {headers: contentHeader});
return response;
}

however it means i'd have to lose the benefits defining the url once and using it where needed via the config file definition.


Thanks! We'll be in touch soon.

Most helpful comment

This approach returns null on production builds as the AOT compilation cannot access the window.location.host value. Any better fix?

All 6 comments

Hi @byteworksng ,

A better approach would be to import your environments file like:

import { environment } from '../environments/environment';

Where environment.prod.ts looks like:

export const environment = {
  production: true,
  productionApi: "https://"+ window.location.hostname +"/api/"
};

This returns a string rather than an object with just location.hostname

I understand that this is happening to you, but I'm not too sure it's a CLI bug... it looks like it's an AOT thing even. Something about how providers work, I'd wager. Try to use a factory instead of an object, I remember some similar problems with window were solved that way.

This approach returns null on production builds as the AOT compilation cannot access the window.location.host value. Any better fix?

I am facing the same issue in Aug 2018 .. did not find any fix for a while. does anyone have a solution for this ?

We made a getter function to retrieve it at runtime. Something like this:

export function getHostLocation() {
  return window.location.protocol +  '//' + window.location.host + '/' ;
}

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings