Use of jQuery code in Angular app.component.ts

Viewed 257

I am working on Angular app. I imported jQuery package using following code.

$ npm install jquery --save

I am trying to transfer my .js data of html web page to app.component.ts of angular. My setup for JQuery is done in angular app and I even tested it. I am having checkbox in my web page, which will be selected to remove file using button click. To achieve this, I used the following code in JS.

function RemoveFile() {
  var files = document.getElementById("files").children;
  for (var i = 1; i < files.length; i++) {
    if (files[i].children[0].children[0].checked) {
      files[i].remove();
      i--;
    }
  }
}

It is working fine in normal html page but when I used it in app.component.ts. It is giving me the following

Property 'checked' does not exist on type 'Element'

How can I rectify it or used something like this?

selectedFile.children[4].children[0].checked = $(this)[0].checked;
2 Answers

jQuery should only be used in Angular in the most exceptional of cases. Angular is a javascript framework for managing the DOM dynamically based on your model. If you manage the DOM outside of Angular you will more than likely suffer unexpected results.

In your case, I'm going to assume you've got some array of files in your component.

component.ts

export class MyComponent {
  files: any[] = [];

  ngOnInit() {
    // somehow get the files
    this.files = [];
  }
}

And I'm going to assume that in your HTML you've built some kind of list containing a nested checkbox for each file.

The user will check some checkboxes, and then press a button to remove those files from the list (and probably perform some other action).

component.html

<div id="files">
  <div *ngFor="let file of files">
    <input type="checkbox" />
  </div>
</div>
<button (click)="RemoveFile()">Remove files</button>

So you have used Angular to build the list, but now you want to use jQuery to "unbuild" the list? Why would you do that?

The power of Angular is in its simplicity - the HTML will reflect whatever's in your files array. So if you want to "unbuild" your list, then simply remove items from the array.

Admittedly, it's a little trickier when you have to consider things like an array of checkboxes, but that's no excuse to resort to using jQuery.

Since you are effectively going to build a form with a dynamic array, the best way to do handle this would be to use a reactive form with a form array.

Import the reactive forms module in your app module:

app.module.ts

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    FormsModule,
    ReactiveFormsModule 
  ]
}

In your component you will need to inject FormBuilder from @angular/forms. Then build a form once you have your model (which might be inside a service subscription).

You will then delete the files in the form's submit handler. You do have to splice two arrays, but the form array is built from the files array, so they have matching indexes.

component.ts

import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
// ... other imports

export class MyComponent {

  constructor(private formBuilder: FormBuilder) {}

  files: any[] = [];
  form: FormGroup;

  private filesFormArray: FormArray;

  ngOnInit(): void {
    // somehow get the files
    this.files = [];

    // Build an array of form groups if you want each file to have multiple controls.
    // Build an array of form controls if you want each file to have a single control
    // I will just add one control per file - an unchecked checkbox,
    // but use a form group per file to show how it is done

    const filesFormGroups = this.files.map(x => this.formBuilder.group({
      delete: this.formBuilder.control(false)
    }));

    // Build the form array. Store a reference to it for easy access later
    this.filesFormArray = this.formBuilder.array(filesFormGroups);

    // Build the whole form. At the moment there will only be files.
    this.form = this.formBuilder.group({
      files: this.filesFormArray
    });
  }

  onSubmit(): void {
    // start at the end of the array and work backwards
    for (let i = this.files.length - 1; i >= 0; i--) {
      // get the checkbox from the form array
      const checkBox = this.filesFormArray.controls[i].get('delete') as FormControl;
      if (checkbox.value) {
        // remove the item from the model and the form
        this.files.splice(i, 1);
        this.filesFormArray.controls.splice(i, 1);
      }
    }
  }
}

In your HTML, you still build from your files, but also bind to the form. You use the directives formGroupName, formArrayName, and formControlName to match the structure of the form group you built in your component.

component.html

<form [formGroup]="form" (submit)="onSubmit()">
  <div formArrayName="files">
    <div *ngFor="let file of files; let i = index" [formGroupName]="i">
      <input type="checkbox" formControlName="delete" />
    </div>
  </div>
  <button>Remove files</button>
</form>

// First install jQuery npm install --save jquery

// and jQuery Definition npm install -D @types/jquery

add jquery path in angular.json script: [] array under build like

script: [ "node_modules/jquery/dist/jquery.min.js"]

then add declare var $:any; after import statement and jquery ready to use

Related