Home > front end >  Angular external script is loaded only on first page open
Angular external script is loaded only on first page open

Time:08-15

Me loading an external script in a project in angular, through the file angular.json

"scripts": [
              "src/assets/js/mask.js"
            ],

It is a script to apply a mask to some form fields. When the page is first loaded the script works, if I navigate to another page without refreshing and go back to the page containing the form it no longer works.

Is there another way to load this script whenever that component is accessed?

Remembering that the site works as a SPA (Single Page Application), so navigation between pages occurs without the need for new requests.

There are several masks, I run them through a function, see:

function id(el) {
    return document.getElementById(el);
}
window.onload = function() {
    id('nome')?.addEventListener("keyup", function() {
        inicialMaiuscula(this);
    });
    id('telefone')?.addEventListener("keyup", function() {
        mascara(this, mtel);
    });
    id('celular')?.addEventListener("keyup", function() {
        mascara(this, mtel);
    });
    id('cep')?.addEventListener("keyup", function() {
        mascara(this, cepm);
    });
    id('cep')?.addEventListener("change", function() {
        getEndereco(this);
    });
    id('cpf')?.addEventListener("keyup", function() {
        mascara(this, cpf_mask);
    });
    id('cpf')?.addEventListener("blur", function() {
        validarCPF(this.value);
    });
    id('cpf')?.addEventListener("paste", function() {
        return false;
    });
    id('rg')?.addEventListener("keyup", function() {
        mascara(this, soNumeros);
    });
    id('nascimento')?.addEventListener("keyup", function() {
        mascara(this, data);
    });
    id('usuario')?.addEventListener("keyup", function() {
        letrasNumeros(event);
    });
    id('senha')?.addEventListener("blur", function() {
        validaSenha(this);
    });
    id('confSenha')?.addEventListener("blur", function() {
        validaSenha(this);
    });
    id('estado')?.addEventListener("input", function() {
        tudoMaiuscula(event);
    });
}

Full mask.js: https://jsfiddle.net/m50o6fn8/

CodePudding user response:

Lets first understand, why does it work in the beginning?

The way JS/jQuery code would work is, your script is getting into action after DOM Ready(DOMContentLoaded). Suppose you've written a line $('input[mask]').mask(...) to apply masking. So when this line executes, it queries, and finds elements that match the selector, and applies the mask function to them. That's why it worked at page load.

Why did it not work later?

Of course, as we have seen, the script already ran. Its an SPA. So the static script resource you mentioned in angular.json's scripts option. It loads once on page load, so the next page visit won't re-execute or download the script. Cool.

How to make it work?

The most recommended way here is using Angular Directive. WHY? because we wanted to add behavior(masking) on top of the DOM. Excellent. So what happens is when you write a directive, you will be mentioning the selector like input[mask], so angular make sure that whenever any content is loaded on pages. and it matches the selector, it applies the behavior return inside directive class.

Simple Example

@Directive({
  selector: 'input[mask]',
})
export class MaskInputDirective {

  constructor(private el: ElementRef) {}

  @Input() format = 'dd/mm/yyyy';

  ngAfterViewInit() {
    $(this.el.nativeElement).mask(this.format);
  }
}

An interesting fact to note in directive is ngAfterViewInit lifecycle hook should be used to get hold of elements it is acting upon. And you can easily get hold of element by asking for dependency inside constructor like private el: ElementRef


But why re-invent the wheel? when things are already in a place. I would recommend you to use ngx-mask npm library instead.

CodePudding user response:

First, you should find out the code snippet that is applying the mask to the form field from mask.js file. It should look like $('input').mask(...).

And then you should add that code snippet to OnInit or AfterContentInit lifecycle of each component you want to use it.

Btw it would be better to use a npm library instead of JS assets, i.e. https://www.npmjs.com/package/ngx-mask

  • Related