aspnetcore-angular-universal icon indicating copy to clipboard operation
aspnetcore-angular-universal copied to clipboard

SSR doesn't skip *ngIf=false and throw exception

Open ghost opened this issue 7 years ago • 4 comments

Hi guys. Got a problem... For phone validation try to use ng2-tel-input.

I added some code to app.browser.module.ts

import {Ng2TelInputModule} from 'ng2-tel-input';
....
@NgModule({
 imports: [
        ....
        Ng2TelInputModule
    ],
....
})

Also some code to my component

import {Component, Inject, OnInit, PLATFORM_ID} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Ng2TelInput } from 'ng2-tel-input';

@Component({
  selector: 'reg-event-form',
  templateUrl: './reg-event-form.component.html',
  styleUrls: ['./reg-event-form.component.scss']
})
export class RegEventFormComponent implements OnInit {

  public isPlatformBrowser = false;
  constructor(@Inject(PLATFORM_ID) private platformId: Object) { }

  ngOnInit() {
      this.isPlatformBrowser = isPlatformBrowser(this.platformId);
  }
}

And code to my view:

<div *ngIf="isPlatformBrowser">
          <input type="text"
                 ng2TelInput
                 [ng2TelInputOptions]="{initialCountry: 'in'}"
                 (hasError)="hasError($event)"
                 (ng2TelOutput)="getNumber($event)"
                 (intlTelInputObject)="telInputObject($event)"
                 (countryChange)="onCountryChange($event)" />
        </div>

And after starting I god the server rendering error:

Can't bind to 'ng2TelInputOptions' since it isn't a known property of 'input'.

image

On my plan - it should not try to render this, because it's a browser code.

Any ideas? Thanks!

ghost avatar May 30 '18 18:05 ghost

Some of the 3rd party components I've tried just don't work well with SSR, regardless of whether you gate them with IsBrowser, and not familiar with ng2-tel-input but, does it help if you move the setting of the IsBrowser boolean into the constructor? i.e :

export class RegEventFormComponent implements OnInit {

   public isBrowser: boolean;

  constructor(@Inject(PLATFORM_ID) private platformId: Object) { 
      this.isBrowser = isPlatformBrowser(this.platformId);
  }
}
<div *ngIf="isBrowser">
          <input type="text"
                 ng2TelInput
                 [ng2TelInputOptions]="{initialCountry: 'in'}"
                 (hasError)="hasError($event)"
                 (ng2TelOutput)="getNumber($event)"
                 (intlTelInputObject)="telInputObject($event)"
                 (countryChange)="onCountryChange($event)" />
</div>

?

peterdobson avatar May 31 '18 05:05 peterdobson

@peterdobson it dose not help :( How it possible to detect that component will not work with SSR? But anyway this error describe the case of try to render this on the server side... very strange.. I can not understand.

ghost avatar May 31 '18 06:05 ghost

Check out https://github.com/MarkPieszak/aspnetcore-angular2-universal#gotchas :

window, document, navigator, and other browser types - do not exist on the server - so using them, or any library that uses them (jQuery for example) will not work.

Don't manipulate the nativeElement directly. Use the Renderer2. We do this to ensure that in any environment we're able to change our view. constructor(element: ElementRef, renderer: Renderer2) { this.renderer.setStyle(element.nativeElement, 'font-size', 'x-large'); }

so if your 3rd party component is using these ( https://github.com/gauravsoni119/ng2-tel-input/blob/master/src/ng2-tel-input.ts imports jquery and also uses ElementRef.nativeElement as the component is initialised, so) that's probably where the issue is.

peterdobson avatar May 31 '18 06:05 peterdobson

From your error and from your snippet it seems you are not registering the Ng2TelInputModule in the app.module.server.ts, hence component is not available.

Even if you don't need its behaviour for SSR you need to register it. If you need it only on the browser, you have to mock the module/directive for the server. I wouldn't suggest using a component which depends on jquery, but obviously, that's up to you 😄

stephenlautier avatar Jun 01 '18 00:06 stephenlautier