Angular: ExpressionChangedAfterItHasBeenCheckedError child component & FormControl










0















I've seen, read and tried a lot of questions, answers and blogs about this topic. I understand why it is happening in my code, I just don't know how to fix it.



(Simplification of real code; If I made mistakes or forgot something important, please let me know in the comments)



I have parent component A with an input and child component B.



<form [formgroup]="modalForm">
<input type="text" formControlName="text"></input>
<componentB
[formControl]="modalForm.controls['componentB']
[firstProperty]="foo"
[secondProperty]="bar">
</componentB>
</form>


ComponentB has an input as well, and a custom message component:



<div>
<input type="text" [formControl]="formControl"></input>
<message
[message]="firstProperty"
[secondMessage]="secondProperty">
</message>
</div>


ComponentA:



export class ComponentA implements OnInit

public foo: string;
public bar: string;
public modalFrom: FormGroup;

public constructor(private componentBValidatorFactory: ComponentBValidatorFactory)

public ngOnInit(): void
this.modalForm = new FormGroup(
text: new FormControl(null),
componentB: new FormControl(null,
validators: Validators.required,
asyncValidatiors: [this.componentBValidatorFactory.asyncValidatorFn()],
updateOn: 'blur'
)
);
this.modalForm.controls['text'].valueChanges(subscribe( () => this.textChanged());
this.modalForm.controls['componentB'].valueChanges(subscribe( () => this.componentBChanged());


private textChanged(): void
this.foo = this.modalForm.controls['text'].value;


private componentBChanged(): void
this.bar = this.modalForm.controls['componentB'].value + 'somestring';




ComponentB (simplified):



export class ComponentB

@Input()
public formControl: FormControl;

@Input()
public firstProperty: string;

@Input()
public secondProperty: string;




The issue (as I understand it):
When text changes (user input), it updates foo with a value. This means that ComponentB changes, so valueChanges of ComponentB is triggered. ComponentBChanged is fired and it updates bar.
When text changes again, bar is changed again, but as it is different from the earlier value when foo is processed the second time, I get the well known ExpressionChangedAfterItHasBeenCheckedError (values are processed correctly though).
As I understand it:
ComponentB was already updated (foo), which triggers another change in a binding of this same component (bar). Which does not make Angular happy.
Directly putting input in ComponentB (which also has an input field) works fine, it updates bar correctly without problems.



What can I do to be able to update bar without issues? I can't update bar in textChanged in my code as the update should also happen if ComponentB is manipulated directly.










share|improve this question
























  • Can't seem to reproduce the issue here: stackblitz.com/edit/angular-fqxu5j. Though it doesn't include the async validator, or the message component.

    – Alex K
    Nov 15 '18 at 18:01











  • It's possible I forgot something in my simplification, or the problem is not what I think it is... I'm a little clueless atm. It seems that bar is not updated at all in the example?

    – Century
    Nov 15 '18 at 18:54











  • bar does get updated, but only on blur. Can you add more code to the stackblitz until the issue reappears?

    – Alex K
    Nov 15 '18 at 19:04











  • I tried to update the stackblitz, but I realized that the problem is probably in directives added do the input of componentB. Which are too complicated to put up here. The question helped me to get this insight, but it is rather useless for others I'm afraid :(

    – Century
    Nov 16 '18 at 10:38















0















I've seen, read and tried a lot of questions, answers and blogs about this topic. I understand why it is happening in my code, I just don't know how to fix it.



(Simplification of real code; If I made mistakes or forgot something important, please let me know in the comments)



I have parent component A with an input and child component B.



<form [formgroup]="modalForm">
<input type="text" formControlName="text"></input>
<componentB
[formControl]="modalForm.controls['componentB']
[firstProperty]="foo"
[secondProperty]="bar">
</componentB>
</form>


ComponentB has an input as well, and a custom message component:



<div>
<input type="text" [formControl]="formControl"></input>
<message
[message]="firstProperty"
[secondMessage]="secondProperty">
</message>
</div>


ComponentA:



export class ComponentA implements OnInit

public foo: string;
public bar: string;
public modalFrom: FormGroup;

public constructor(private componentBValidatorFactory: ComponentBValidatorFactory)

public ngOnInit(): void
this.modalForm = new FormGroup(
text: new FormControl(null),
componentB: new FormControl(null,
validators: Validators.required,
asyncValidatiors: [this.componentBValidatorFactory.asyncValidatorFn()],
updateOn: 'blur'
)
);
this.modalForm.controls['text'].valueChanges(subscribe( () => this.textChanged());
this.modalForm.controls['componentB'].valueChanges(subscribe( () => this.componentBChanged());


private textChanged(): void
this.foo = this.modalForm.controls['text'].value;


private componentBChanged(): void
this.bar = this.modalForm.controls['componentB'].value + 'somestring';




ComponentB (simplified):



export class ComponentB

@Input()
public formControl: FormControl;

@Input()
public firstProperty: string;

@Input()
public secondProperty: string;




The issue (as I understand it):
When text changes (user input), it updates foo with a value. This means that ComponentB changes, so valueChanges of ComponentB is triggered. ComponentBChanged is fired and it updates bar.
When text changes again, bar is changed again, but as it is different from the earlier value when foo is processed the second time, I get the well known ExpressionChangedAfterItHasBeenCheckedError (values are processed correctly though).
As I understand it:
ComponentB was already updated (foo), which triggers another change in a binding of this same component (bar). Which does not make Angular happy.
Directly putting input in ComponentB (which also has an input field) works fine, it updates bar correctly without problems.



What can I do to be able to update bar without issues? I can't update bar in textChanged in my code as the update should also happen if ComponentB is manipulated directly.










share|improve this question
























  • Can't seem to reproduce the issue here: stackblitz.com/edit/angular-fqxu5j. Though it doesn't include the async validator, or the message component.

    – Alex K
    Nov 15 '18 at 18:01











  • It's possible I forgot something in my simplification, or the problem is not what I think it is... I'm a little clueless atm. It seems that bar is not updated at all in the example?

    – Century
    Nov 15 '18 at 18:54











  • bar does get updated, but only on blur. Can you add more code to the stackblitz until the issue reappears?

    – Alex K
    Nov 15 '18 at 19:04











  • I tried to update the stackblitz, but I realized that the problem is probably in directives added do the input of componentB. Which are too complicated to put up here. The question helped me to get this insight, but it is rather useless for others I'm afraid :(

    – Century
    Nov 16 '18 at 10:38













0












0








0


0






I've seen, read and tried a lot of questions, answers and blogs about this topic. I understand why it is happening in my code, I just don't know how to fix it.



(Simplification of real code; If I made mistakes or forgot something important, please let me know in the comments)



I have parent component A with an input and child component B.



<form [formgroup]="modalForm">
<input type="text" formControlName="text"></input>
<componentB
[formControl]="modalForm.controls['componentB']
[firstProperty]="foo"
[secondProperty]="bar">
</componentB>
</form>


ComponentB has an input as well, and a custom message component:



<div>
<input type="text" [formControl]="formControl"></input>
<message
[message]="firstProperty"
[secondMessage]="secondProperty">
</message>
</div>


ComponentA:



export class ComponentA implements OnInit

public foo: string;
public bar: string;
public modalFrom: FormGroup;

public constructor(private componentBValidatorFactory: ComponentBValidatorFactory)

public ngOnInit(): void
this.modalForm = new FormGroup(
text: new FormControl(null),
componentB: new FormControl(null,
validators: Validators.required,
asyncValidatiors: [this.componentBValidatorFactory.asyncValidatorFn()],
updateOn: 'blur'
)
);
this.modalForm.controls['text'].valueChanges(subscribe( () => this.textChanged());
this.modalForm.controls['componentB'].valueChanges(subscribe( () => this.componentBChanged());


private textChanged(): void
this.foo = this.modalForm.controls['text'].value;


private componentBChanged(): void
this.bar = this.modalForm.controls['componentB'].value + 'somestring';




ComponentB (simplified):



export class ComponentB

@Input()
public formControl: FormControl;

@Input()
public firstProperty: string;

@Input()
public secondProperty: string;




The issue (as I understand it):
When text changes (user input), it updates foo with a value. This means that ComponentB changes, so valueChanges of ComponentB is triggered. ComponentBChanged is fired and it updates bar.
When text changes again, bar is changed again, but as it is different from the earlier value when foo is processed the second time, I get the well known ExpressionChangedAfterItHasBeenCheckedError (values are processed correctly though).
As I understand it:
ComponentB was already updated (foo), which triggers another change in a binding of this same component (bar). Which does not make Angular happy.
Directly putting input in ComponentB (which also has an input field) works fine, it updates bar correctly without problems.



What can I do to be able to update bar without issues? I can't update bar in textChanged in my code as the update should also happen if ComponentB is manipulated directly.










share|improve this question
















I've seen, read and tried a lot of questions, answers and blogs about this topic. I understand why it is happening in my code, I just don't know how to fix it.



(Simplification of real code; If I made mistakes or forgot something important, please let me know in the comments)



I have parent component A with an input and child component B.



<form [formgroup]="modalForm">
<input type="text" formControlName="text"></input>
<componentB
[formControl]="modalForm.controls['componentB']
[firstProperty]="foo"
[secondProperty]="bar">
</componentB>
</form>


ComponentB has an input as well, and a custom message component:



<div>
<input type="text" [formControl]="formControl"></input>
<message
[message]="firstProperty"
[secondMessage]="secondProperty">
</message>
</div>


ComponentA:



export class ComponentA implements OnInit

public foo: string;
public bar: string;
public modalFrom: FormGroup;

public constructor(private componentBValidatorFactory: ComponentBValidatorFactory)

public ngOnInit(): void
this.modalForm = new FormGroup(
text: new FormControl(null),
componentB: new FormControl(null,
validators: Validators.required,
asyncValidatiors: [this.componentBValidatorFactory.asyncValidatorFn()],
updateOn: 'blur'
)
);
this.modalForm.controls['text'].valueChanges(subscribe( () => this.textChanged());
this.modalForm.controls['componentB'].valueChanges(subscribe( () => this.componentBChanged());


private textChanged(): void
this.foo = this.modalForm.controls['text'].value;


private componentBChanged(): void
this.bar = this.modalForm.controls['componentB'].value + 'somestring';




ComponentB (simplified):



export class ComponentB

@Input()
public formControl: FormControl;

@Input()
public firstProperty: string;

@Input()
public secondProperty: string;




The issue (as I understand it):
When text changes (user input), it updates foo with a value. This means that ComponentB changes, so valueChanges of ComponentB is triggered. ComponentBChanged is fired and it updates bar.
When text changes again, bar is changed again, but as it is different from the earlier value when foo is processed the second time, I get the well known ExpressionChangedAfterItHasBeenCheckedError (values are processed correctly though).
As I understand it:
ComponentB was already updated (foo), which triggers another change in a binding of this same component (bar). Which does not make Angular happy.
Directly putting input in ComponentB (which also has an input field) works fine, it updates bar correctly without problems.



What can I do to be able to update bar without issues? I can't update bar in textChanged in my code as the update should also happen if ComponentB is manipulated directly.







angular






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 '18 at 17:47







Century

















asked Nov 15 '18 at 17:40









CenturyCentury

1771113




1771113












  • Can't seem to reproduce the issue here: stackblitz.com/edit/angular-fqxu5j. Though it doesn't include the async validator, or the message component.

    – Alex K
    Nov 15 '18 at 18:01











  • It's possible I forgot something in my simplification, or the problem is not what I think it is... I'm a little clueless atm. It seems that bar is not updated at all in the example?

    – Century
    Nov 15 '18 at 18:54











  • bar does get updated, but only on blur. Can you add more code to the stackblitz until the issue reappears?

    – Alex K
    Nov 15 '18 at 19:04











  • I tried to update the stackblitz, but I realized that the problem is probably in directives added do the input of componentB. Which are too complicated to put up here. The question helped me to get this insight, but it is rather useless for others I'm afraid :(

    – Century
    Nov 16 '18 at 10:38

















  • Can't seem to reproduce the issue here: stackblitz.com/edit/angular-fqxu5j. Though it doesn't include the async validator, or the message component.

    – Alex K
    Nov 15 '18 at 18:01











  • It's possible I forgot something in my simplification, or the problem is not what I think it is... I'm a little clueless atm. It seems that bar is not updated at all in the example?

    – Century
    Nov 15 '18 at 18:54











  • bar does get updated, but only on blur. Can you add more code to the stackblitz until the issue reappears?

    – Alex K
    Nov 15 '18 at 19:04











  • I tried to update the stackblitz, but I realized that the problem is probably in directives added do the input of componentB. Which are too complicated to put up here. The question helped me to get this insight, but it is rather useless for others I'm afraid :(

    – Century
    Nov 16 '18 at 10:38
















Can't seem to reproduce the issue here: stackblitz.com/edit/angular-fqxu5j. Though it doesn't include the async validator, or the message component.

– Alex K
Nov 15 '18 at 18:01





Can't seem to reproduce the issue here: stackblitz.com/edit/angular-fqxu5j. Though it doesn't include the async validator, or the message component.

– Alex K
Nov 15 '18 at 18:01













It's possible I forgot something in my simplification, or the problem is not what I think it is... I'm a little clueless atm. It seems that bar is not updated at all in the example?

– Century
Nov 15 '18 at 18:54





It's possible I forgot something in my simplification, or the problem is not what I think it is... I'm a little clueless atm. It seems that bar is not updated at all in the example?

– Century
Nov 15 '18 at 18:54













bar does get updated, but only on blur. Can you add more code to the stackblitz until the issue reappears?

– Alex K
Nov 15 '18 at 19:04





bar does get updated, but only on blur. Can you add more code to the stackblitz until the issue reappears?

– Alex K
Nov 15 '18 at 19:04













I tried to update the stackblitz, but I realized that the problem is probably in directives added do the input of componentB. Which are too complicated to put up here. The question helped me to get this insight, but it is rather useless for others I'm afraid :(

– Century
Nov 16 '18 at 10:38





I tried to update the stackblitz, but I realized that the problem is probably in directives added do the input of componentB. Which are too complicated to put up here. The question helped me to get this insight, but it is rather useless for others I'm afraid :(

– Century
Nov 16 '18 at 10:38












1 Answer
1






active

oldest

votes


















0














Instead of passing FormControl to child Use then assign the foo and bar property to null



formControlDirective




This directive accepts an existing FormGroup instance. It will then
use this FormGroup instance to match any child FormControl, FormGroup,
and FormArray instances to child FormControlName, FormGroupName, and
FormArrayName directives.




Parent.component.html



<form [formGroup]="form">
<label >Text</label>
<input formControlName="text">
<app-component-a
[firstProperty]="foo"
[secondProperty]="bar"
></app-component-a>
</form>


app-component-a.ts



import Component, OnInit, Input from '@angular/core';
import FormGroup, FormControl, ControlContainer, FormGroupDirective, Validators from '@angular/forms';
@Component(
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css'],
viewProviders:[provide: ControlContainer,useExisting:FormGroupDirective]
)
export class ComponentAComponent implements OnInit

@Input('firstProperty') firstProperty:string;
@Input('secondProperty') secondProperty:string;

constructor(private fgd:FormGroupDirective)



ngOnInit()
this.fgd.form.addControl('componentA',new FormControl('',updateOn: 'blur'))





Example:https://stackblitz.com/edit/angular-65nmvr






share|improve this answer























  • Why is this a better option? I'm not familiar with the FormGroupDirective. However, I'm afraid I'm stuck with the way the formControl is set, due to other dependencies I did not incorporate in my example.

    – Century
    Nov 15 '18 at 18:52










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53325117%2fangular-expressionchangedafterithasbeencheckederror-child-component-formcontr%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














Instead of passing FormControl to child Use then assign the foo and bar property to null



formControlDirective




This directive accepts an existing FormGroup instance. It will then
use this FormGroup instance to match any child FormControl, FormGroup,
and FormArray instances to child FormControlName, FormGroupName, and
FormArrayName directives.




Parent.component.html



<form [formGroup]="form">
<label >Text</label>
<input formControlName="text">
<app-component-a
[firstProperty]="foo"
[secondProperty]="bar"
></app-component-a>
</form>


app-component-a.ts



import Component, OnInit, Input from '@angular/core';
import FormGroup, FormControl, ControlContainer, FormGroupDirective, Validators from '@angular/forms';
@Component(
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css'],
viewProviders:[provide: ControlContainer,useExisting:FormGroupDirective]
)
export class ComponentAComponent implements OnInit

@Input('firstProperty') firstProperty:string;
@Input('secondProperty') secondProperty:string;

constructor(private fgd:FormGroupDirective)



ngOnInit()
this.fgd.form.addControl('componentA',new FormControl('',updateOn: 'blur'))





Example:https://stackblitz.com/edit/angular-65nmvr






share|improve this answer























  • Why is this a better option? I'm not familiar with the FormGroupDirective. However, I'm afraid I'm stuck with the way the formControl is set, due to other dependencies I did not incorporate in my example.

    – Century
    Nov 15 '18 at 18:52















0














Instead of passing FormControl to child Use then assign the foo and bar property to null



formControlDirective




This directive accepts an existing FormGroup instance. It will then
use this FormGroup instance to match any child FormControl, FormGroup,
and FormArray instances to child FormControlName, FormGroupName, and
FormArrayName directives.




Parent.component.html



<form [formGroup]="form">
<label >Text</label>
<input formControlName="text">
<app-component-a
[firstProperty]="foo"
[secondProperty]="bar"
></app-component-a>
</form>


app-component-a.ts



import Component, OnInit, Input from '@angular/core';
import FormGroup, FormControl, ControlContainer, FormGroupDirective, Validators from '@angular/forms';
@Component(
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css'],
viewProviders:[provide: ControlContainer,useExisting:FormGroupDirective]
)
export class ComponentAComponent implements OnInit

@Input('firstProperty') firstProperty:string;
@Input('secondProperty') secondProperty:string;

constructor(private fgd:FormGroupDirective)



ngOnInit()
this.fgd.form.addControl('componentA',new FormControl('',updateOn: 'blur'))





Example:https://stackblitz.com/edit/angular-65nmvr






share|improve this answer























  • Why is this a better option? I'm not familiar with the FormGroupDirective. However, I'm afraid I'm stuck with the way the formControl is set, due to other dependencies I did not incorporate in my example.

    – Century
    Nov 15 '18 at 18:52













0












0








0







Instead of passing FormControl to child Use then assign the foo and bar property to null



formControlDirective




This directive accepts an existing FormGroup instance. It will then
use this FormGroup instance to match any child FormControl, FormGroup,
and FormArray instances to child FormControlName, FormGroupName, and
FormArrayName directives.




Parent.component.html



<form [formGroup]="form">
<label >Text</label>
<input formControlName="text">
<app-component-a
[firstProperty]="foo"
[secondProperty]="bar"
></app-component-a>
</form>


app-component-a.ts



import Component, OnInit, Input from '@angular/core';
import FormGroup, FormControl, ControlContainer, FormGroupDirective, Validators from '@angular/forms';
@Component(
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css'],
viewProviders:[provide: ControlContainer,useExisting:FormGroupDirective]
)
export class ComponentAComponent implements OnInit

@Input('firstProperty') firstProperty:string;
@Input('secondProperty') secondProperty:string;

constructor(private fgd:FormGroupDirective)



ngOnInit()
this.fgd.form.addControl('componentA',new FormControl('',updateOn: 'blur'))





Example:https://stackblitz.com/edit/angular-65nmvr






share|improve this answer













Instead of passing FormControl to child Use then assign the foo and bar property to null



formControlDirective




This directive accepts an existing FormGroup instance. It will then
use this FormGroup instance to match any child FormControl, FormGroup,
and FormArray instances to child FormControlName, FormGroupName, and
FormArrayName directives.




Parent.component.html



<form [formGroup]="form">
<label >Text</label>
<input formControlName="text">
<app-component-a
[firstProperty]="foo"
[secondProperty]="bar"
></app-component-a>
</form>


app-component-a.ts



import Component, OnInit, Input from '@angular/core';
import FormGroup, FormControl, ControlContainer, FormGroupDirective, Validators from '@angular/forms';
@Component(
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css'],
viewProviders:[provide: ControlContainer,useExisting:FormGroupDirective]
)
export class ComponentAComponent implements OnInit

@Input('firstProperty') firstProperty:string;
@Input('secondProperty') secondProperty:string;

constructor(private fgd:FormGroupDirective)



ngOnInit()
this.fgd.form.addControl('componentA',new FormControl('',updateOn: 'blur'))





Example:https://stackblitz.com/edit/angular-65nmvr







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 15 '18 at 18:17









ChellappanChellappan

5,7812421




5,7812421












  • Why is this a better option? I'm not familiar with the FormGroupDirective. However, I'm afraid I'm stuck with the way the formControl is set, due to other dependencies I did not incorporate in my example.

    – Century
    Nov 15 '18 at 18:52

















  • Why is this a better option? I'm not familiar with the FormGroupDirective. However, I'm afraid I'm stuck with the way the formControl is set, due to other dependencies I did not incorporate in my example.

    – Century
    Nov 15 '18 at 18:52
















Why is this a better option? I'm not familiar with the FormGroupDirective. However, I'm afraid I'm stuck with the way the formControl is set, due to other dependencies I did not incorporate in my example.

– Century
Nov 15 '18 at 18:52





Why is this a better option? I'm not familiar with the FormGroupDirective. However, I'm afraid I'm stuck with the way the formControl is set, due to other dependencies I did not incorporate in my example.

– Century
Nov 15 '18 at 18:52



















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53325117%2fangular-expressionchangedafterithasbeencheckederror-child-component-formcontr%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Barbados

How to read a connectionString WITH PROVIDER in .NET Core?

Node.js Script on GitHub Pages or Amazon S3