Abdur Rahim
Abdur Rahim

Reputation: 4041

Angular Bootstrap Modal value setting inconsistency

Update 2

<div *ngFor="let c of uiVideos;let i= index" class="row curriculum-single">
    <button style="display:none" data-toggle="modal" data-target="#videoReplace"></button>
  <app-upload-modal [id]="i" ></app-upload-modal>
</div>

Update 1: Here is my upload-modal.ts

export class UploadModalComponent implements OnInit {

  constructor() { }
  @Input()
  id:number;

  @ViewChild('toggleButton') 
  private toggleButton : ElementRef;     
 
  ngOnInit() {
  }

  clickToggleButton() {
     this.toggleButton.nativeElement.click(); //trigger button click
  }

}

And upload-Modal.html

<div class="add-popup modal fade" id="videoReplace{{index}}" #videoModal tabindex="-1" role="dialog" aria-labelledby="videoReplace">
  <button #toggleButton  style="display:none" data-toggle="modal" data-target="#videoReplace{index}"></button>
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header gredient-bg">
        <ul class="card-actions icons right-top">
          <li>
            <a href="javascript:void(0)" class="text-white" data-dismiss="modal" aria-label="Close" #closeModal (click)="hideModal">
              <i class="ti-close"></i>
            </a>
          </li>
        </ul>
        <h4 class="modal-title text-center">Replace Video</h4>
      </div>
      <div class="modal-body">
        <div class="package_summary text-center">
          <p>Please upload a MP4 file you want to replace with the existing one. This will replace <strong>{{videosToBeReplaced?.video?.title}}</strong>
          </p>
          <p-fileUpload mode='advanced' #replaceFile name="replace1[]" [url]="getReplaceUrl(videosToBeReplaced?.video?.itemId)"
            accept="video/mp4" maxFileSize="100000000" (onBeforeSend)="onBeforeSend($event)" (onProgress)="onProgressReplace($event)"
            (onSelect)="onFileSelect($event)" (onUpload)="onReplaceVideo($event)" chooseLabel="Select Video">
          </p-fileUpload>
        </div>

      </div>
    </div>
  </div>
</div>

Old Code : First Question

Here is my component.html

At the lower part of the code, there is a modal. Modal value is set when

<i (click)="OpenUploaderAndBindContent(c)" title="Replace" *ngIf="c.isEditing">

this method is clicked. As you see, there is a list drawn here uiVideos. For each element of this list, there is a row generating with edit, move and several actions. I have specified the action in above line code.

Problem : for the first row binded from uiVideos are being shown in Modal. But for the next rows of the uiVideos are not binding to the Modal.

As you can see, I have checked the value in this.videosToBeReplaced.video.itemId, And they absolutely are correct for any of the rows of uiVideos list. but after triggering the modal, The value becomes empty.

And below, there is the code to show the modal.

<div class="row m-3 pb-3">
  <div class="border border-success col-sm-12 p-4">
    <p-fileUpload mode="advanced" multiple='true' #fileInput name="demo[]"  accept="video/mp4" [url]="getUploadUrl()"
    (onUpload)="onBasicUploadAuto($event)" customUpload="true"
    (onBeforeSend)="onBeforeSend($event)"      
    (onSelect)="onFileSelect($event)" (uploadHandler)="uploadFilesTemp($event)"
    chooseLabel="Select Videos" uploadLabel="Upload">
      <!--
         <ng-template pTemplate="toolbar">
        <div>Upload 3 Files</div>
      </ng-template>
      <ng-template let-file pTemplate="file">
        <div>Custom UI to display a file</div>
      </ng-template>
      <ng-template pTemplate="content">
        <div>Custom UI to manage uploaded files</div>
      </ng-template> -->
    </p-fileUpload>
     <p-progressBar  *ngIf="progress > 0" [value]="progress" showValue="false" mode="{{getProgressBarMode()}}"></p-progressBar> 
  </div>
</div>
<div *ngFor="let c of uiVideos;let i= index" class="row curriculum-single">
  <div class="col-sm-12">
    <div class="row border border-secondary rounded p-2 m-1">
      <div *ngIf="!c.isEditing" class="col-sm-12 p-1">
        <div class="lecture float-left">
          <span class="">
            <i class="fa fa-video-camera"></i>{{c.video.title}}</span>
        </div>
      </div>
      <div *ngIf="c.isEditing" class="col-sm-12">
        <div class="row">
          <input [(ngModel)]="c.video.title" type="text" class="form-control col-sm-12" *ngIf="c.isEditing">
        </div>
        <p-progressBar  *ngIf="c.progress > 0" [value]="progress" showValue="false" mode="{{getSingleProgressBarMode(c)}}"></p-progressBar>
      </div>


      <div class="col-sm-12 p-1">
        <div class="row">
          <app-content-status-updater [item]="c.video" itemType="video" [isEditing]="c.isEditing" class="col-sm-4"></app-content-status-updater>
          <div class="col-sm-4"></div>
          <div class="col-sm-4 p-1">
            <select [(ngModel)]="c.video.order">
              <option *ngFor="let item of uiVideos;let i=index" value="{{i+1}}">{{i+1}}</option>
            </select>
            <i (click)="onMove(c)" *ngIf="!c.isEditing" class="fa fa-arrows p-1"></i>
            <i (click)="OpenUploaderAndBindContent(c)" title="Replace" *ngIf="c.isEditing"
            class="fa fa-upload p-1"></i>
            <i (click)="onEdit(c)" *ngIf="!c.isEditing" class="ti ti-pencil-alt p-1"></i>
            <i (click)="onSave(c)" *ngIf="c.isEditing" class="fa fa-floppy-o p-1"></i>
            <i (click)="onCancel(c)" *ngIf="c.isEditing" class="fa fa-times-circle p-1"></i>

            <i (click)="onDelete(c)" *ngIf="!c.isEditing" class="fa fa-trash p-1"></i>
          </div>
        </div>


      </div>
    </div>


  </div>
</div>

<button id="videoReplaceTrigger" style="display:none" data-toggle="modal" data-target="#videoReplace"></button>
<div class="add-popup modal fade" id="videoReplace" #videoModal tabindex="-1" role="dialog" aria-labelledby="videoReplace"  >
  
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header gredient-bg">
        <ul class="card-actions icons right-top">
          <li>
            <a href="javascript:void(0)" class="text-white" data-dismiss="modal" aria-label="Close" #closeModal (click)="hideModal">
              <i class="ti-close"></i>
            </a>
          </li>
        </ul>
        <h4 class="modal-title text-center">Replace Video</h4>
      </div>
      <div class="modal-body">
        <div class="package_summary text-center">
          <p>Please upload a MP4 file you want to replace with the existing one. This will replace <strong>{{videosToBeReplaced?.video?.title}}</strong>
          </p>
          <p-fileUpload mode='advanced' #replaceFile name="replace1[]" [url]="getReplaceUrl(videosToBeReplaced?.video?.itemId)"
            accept="video/mp4" maxFileSize="100000000" 
            (onBeforeSend)="onBeforeSend($event)" 
            (onProgress)="onProgressReplace($event)"
            (onSelect)="onFileSelect($event)" 
            (onUpload)="onReplaceVideo($event)" 
            chooseLabel="Select Video">
          </p-fileUpload>
        </div>

      </div>
    </div>
  </div>
</div>

In component ts following code determines the modals videosToBeReplaced value

OpenUploaderAndBindContent(c: UIVideo) {
    console.log('before c: ' + c.video.itemId + ' - ' + c.video.title);
    
    this.videosToBeReplaced = new UIVideo();
    this.videosToBeReplaced = c;

    console.log(this.videosToBeReplaced.video.itemId + ' - ' + this.videosToBeReplaced.video.title);
    document.getElementById('videoReplaceTrigger').click();
  }

Upvotes: 1

Views: 80

Answers (1)

Sunil
Sunil

Reputation: 11241

Issue

Your problem is related to the operating on the same DOM element for each iteration of for loop.

See your OpenUploaderAndBindContent function.

OpenUploaderAndBindContent(c: UIVideo) {
    console.log('before c: ' + c.video.itemId + ' - ' + c.video.title);

    this.videosToBeReplaced = new UIVideo();
    this.videosToBeReplaced = c;

    console.log(this.videosToBeReplaced.video.itemId + ' - ' + this.videosToBeReplaced.video.title);
    document.getElementById('videoReplaceTrigger').click(); <-- ISSUE 1
  }

You are trigger the same button for each video and eventually this will try to open the same modal. Because button is target the same modal id=videoReplace. Refer below snippet. button is targeting videoReplace.

<button id="videoReplaceTrigger" style="display:none" data-toggle="modal" data-target="#videoReplace"></button>
<div class="add-popup modal fade" id="videoReplace" #videoModal tabindex="-1" role="dialog" aria-labelledby="videoReplace"  >

Solution

The solution of your problem is -

  1. Do not target the same button and modal by id.
  2. You should create the multiple modal for each video so create new modal component say modal-component
  3. Move the following modal content in it.

Make the set the button and model id dynamic by using @Input.

  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header gredient-bg">
        <ul class="card-actions icons right-top">
          <li>
            <a href="javascript:void(0)" class="text-white" data-dismiss="modal" aria-label="Close" #closeModal (click)="hideModal">
              <i class="ti-close"></i>
            </a>
          </li>
        </ul>
        <h4 class="modal-title text-center">Replace Video</h4>
      </div>
      <div class="modal-body">
        <div class="package_summary text-center">
          <p>Please upload a MP4 file you want to replace with the existing one. This will replace <strong>{{videosToBeReplaced?.video?.title}}</strong>
          </p>
          <p-fileUpload mode='advanced' #replaceFile name="replace1[]" [url]="getReplaceUrl(videosToBeReplaced?.video?.itemId)"
            accept="video/mp4" maxFileSize="100000000" 
            (onBeforeSend)="onBeforeSend($event)" 
            (onProgress)="onProgressReplace($event)"
            (onSelect)="onFileSelect($event)" 
            (onUpload)="onReplaceVideo($event)" 
            chooseLabel="Select Video">
          </p-fileUpload>
        </div>

      </div>
    </div>
  </div>
</div>

4.Use the modal-component inside the for loop

<div *ngFor="let c of uiVideos;let i= index" class="row curriculum-single">
   <modal-component [id]="i" ></modal-component>
</div>

note : modal-component has the input id. This will generate the dynamic id for modal and button.

5.Finally your method will look like -

OpenUploaderAndBindContent(c: UIVideo, index:number) {
    console.log('before c: ' + c.video.itemId + ' - ' + c.video.title);

    this.videosToBeReplaced = new UIVideo();
    this.videosToBeReplaced = c;

    console.log(this.videosToBeReplaced.video.itemId + ' - ' + this.videosToBeReplaced.video.title);
    document.getElementById('videoReplaceTrigger'+index).click(); <-- ID IS GENERATED BY INDEX
  }

Here is the id is generated dynamically.

Upvotes: 1

Related Questions