Home > Net >  Angular: How to bind an array model attribute to a copy able div element
Angular: How to bind an array model attribute to a copy able div element

Time:02-15

First of all I apologize for the bad title, I wasn't sure exactly how to describe it.

I have this div for the user to enter contact information pertaining to a "program" for which the user also entered data. Right now you can only enter 1 set of contact information in this div:

<div id="programContactContainer" >

      <div id="programContact">
        <div >
          <label>Name</label>
          <input type="text"  id="contactName"
                 required
                 [(ngModel)]="model.contact.name" name="contactName">
        </div>

        <div >
          <label>Email</label>
          <input type="text"  id="contactEmail"
                 required
                 [(ngModel)]="model.contact.email" name="contactEmail">
        </div>

        <div >
          <label>Phone</label>
          <input type="text"  id="contactPhone"
                 required
                 [(ngModel)]="model.contact.phone" name="contactPhone">
        </div>
        <br>
        <hr/>
      </div>
    </div>

    <input  type="button" value="Add another contact" (click)="cloneContactDiv()">

If you click that button it adds an identical div below the existing one so the user can enter multiple contacts.

Code for copying div:

  cloneContactDiv(){
    const myDiv = document.getElementById(('programContact'));
    const divClone = myDiv.cloneNode(true);
    document.getElementById('programContactContainer').append(divClone);
  }

This is the model for both the program and the contact info (I know that not all of this is used in the question but I thought it might help):

export class ContactModel {
  name: string;
  email: string;
  phone: string;
}

export class ProgramModel {
  category: string;
  name: string;
  description: string;
  shortDescription: string;
  support: string [];
  address: string;
  location: [];
  areaServed: string;
  baseLocation: string;
  website: string;
  topic: string [];
  ownerLid: string;
  keywords: string[] = [];
  startDate: Date;
  endDate: Date;
  notification: boolean;
  daysForNotice: number;
  filter: string [];
  active: boolean;
  /// Contacts
  contact = new ContactModel();
  /// Departments
  departmentContact = new ContactModel();
}

If I change contact = new ContactModel(); to contact: ContactModel[] = []; then I can save an array of them, but I have no idea how to handle this in the html page. As you can see, the contact info was bound like this: [(ngModel)]="model.contact.name", but how do I handle that when there is more than 1 and an unknown number of how many?

I have added pics for clarity:

enter image description here

CodePudding user response:

I finally figured it out. This may or may not be what @Chris Hamilton was trying to explain, but this is what I did:

Changed contact = new ContactModel(); to contact: ContactModel[] = [];.

Then in the html page:

<div *ngFor="let item of model.contact" id="programContactContainer" >

      <div id="programContact">
        <div >
          <label>Name</label>
          <input type="text"  id="contactName"
                 required
                 [(ngModel)]="item.name" name="contactName">
        </div>

        <div >
          <label>Email</label>
          <input type="text"  id="contactEmail"
                 required
                 [(ngModel)]="item.email" name="contactEmail">
        </div>

        <div >
          <label>Phone</label>
          <input type="text"  id="contactPhone"
                 required
                 [(ngModel)]="item.phone" name="contactPhone">
        </div>
        <br>
        <hr/>
      </div>
    </div>
 <input  type="button" value="Add another contact" (click)="cloneContactDiv()">

And the funciton:

  cloneContactDiv(){
    this.model.contact.push(new ContactModel());
  }

CodePudding user response:

You should never need a function like this in angular:

  cloneContactDiv(){
    const myDiv = document.getElementById(('programContact'));
    const divClone = myDiv.cloneNode(true);
    document.getElementById('programContactContainer').append(divClone);
  }

In fact, you should never need to use the document object at all.

Just put your models in an array and use the *ngFor directive to repeat them in the html. Let's call the array models in your component.ts. Then in your component.html:

<div *ngFor="let model of models" >
<div id="programContact">
        <div >
          <label>Name</label>
          <input type="text" 
                 required
                 [(ngModel)]="model.name">
        </div>
<div >
          <label>Email</label>
          <input type="text" 
                 required
                 [(ngModel)]="model.email">
        </div>

        <div >
          <label>Phone</label>
          <input type="text" 
                 required
                 [(ngModel)]="model.phone">
        </div>
        <br>
        <hr/>
      </div>
    </div>

    <input  type="button" value="Add another contact" (click)="addContact()">
</div>

Angular will loop through the array and repeat the programContactContainer div for each model. You can access all properties of the model within the div. If you add another element to the array, the html will be updated automatically.

Since you never need to use getElementById() you generally don't need to add id's either.

To be more clear

models: ContactModel[] = [{name: "", email: "", phone: ""}];

addContact() {
  this.models.push({name: "", email: "", phone: ""})
}
  • Related