Angular 指令创建重复元素

Posted

技术标签:

【中文标题】Angular 指令创建重复元素【英文标题】:Angular Directive creating duplicate elements 【发布时间】:2020-03-17 20:19:52 【问题描述】:

我有一个大部分工作的 Angular 指令,但它在我的元素之后创建按钮和 ul class="dropdown" 的重复注入。谁能明白为什么这会重复?在纯 js 中工作正常。

我的指令:

 import  Directive, ElementRef, Renderer2, HostListener, OnInit  from '@angular/core';

@Directive(
  selector: '.dropdown-container'
)
export class DropdownDirective implements OnInit 

  constructor(private el: ElementRef, private _renderer: Renderer2) 

  

  ngOnInit()

    var dropdown = document.querySelectorAll('.customization-option');
    // /////// Adding li's for each option ////////
    for (var i = 0; i < dropdown.length; i++) 
      var option = dropdown[i].querySelectorAll('option');
      var options = [];
      var drop;
      for (var x = 0; x < option.length; x++) 
        options.push(option[x].innerhtml);
      

      drop = "<button>" + options[0] + "</button><ul class='dropdown'>";
      options.forEach(addOptions);
      drop += "</ul>";
      console.log(drop);
      dropdown[i].insertAdjacentHTML('afterend', drop)
    

    function addOptions(value) 
      drop += "<li>" + value + "</li>";
    


  

  @HostListener('click') onClick(e) 

    var thisDrop = this.el.nativeElement;
    var opt = thisDrop.querySelector('.dropdown').children;
    var buttonDrop = thisDrop.parentElement.parentElement.querySelector('button');
    thisDrop.classList.toggle("active");


    for (var i = 0; i < opt.length; i++) 
      opt[i].addEventListener('click', function () 
        var optValue = this.innerHTML;
        buttonDrop.innerHTML = optValue;
        this.parentElement.classList.remove('active');
      );
    

  


在我的模板中:

<form [formGroup]="storeRequest">
  <div class="container">
    <h4>What can we do for you?</h4>

    <div class="col-2-container">
      <div class="fieldset">
        <div class="dropdown-container" appDrop>
          <label for="topic">Choose a Topic*</label>
          <select name="topic" id="topic" class="customization-option" (change)="toggleForm($event)">
            <option value="Become a Sponsor" selected>Become a Sponsor</option>
            <option value="Host a Fundraising Event">Host a Fundraising Event</option>
            <option value="Give a Donation">Give a Donation</option>
            <option value="General Information">General Information</option>
          </select>
        </div>
      </div>
    </div>


    <div class="col-2-container">
      <div class="fieldset">
        <label for="stCompany" appFocus>Company</label>
        <input type="text" name="company" id="stCompany" autocomplete="on" appFocus />
      </div>
    </div>

    <div class="col-2-container">
      <div class="fieldset">
        <label for="stFirstname" appFocus>First Name*</label>
        <input type="text" name="firstname2" id="stFirstname" autocomplete="on" appFocus formControlName="stFirstname" />
        <span *ngIf="!storeRequest.get('stFirstname').valid && storeRequest.get('stFirstname').touched" class="validation-error">Please enter your first name.</span>
      </div>
      <div class="fieldset">
        <label for="stLastname" appFocus>Last Name*</label>
        <input type="text" name="stLastname" id="stLastname" autocomplete="on" appFocus formControlName="stLastname" />
        <span *ngIf="!storeRequest.get('stLastname').valid && storeRequest.get('stLastname').touched" class="validation-error">Please enter your last name.</span>
      </div>
    </div>

    <div class="col-2-container">
      <div class="fieldset">
        <label for="stAddress1" appFocus>Address Line 1*</label>
        <input type="text" name="stAddress1" id="stAddress1" autocomplete="on" appFocus formControlName="stAddress1" />
        <span *ngIf="!storeRequest.get('stAddress1').valid && storeRequest.get('stAddress1').touched" class="validation-error">Please enter your address.</span>
      </div>
      <div class="fieldset">
        <label for="stAddress2" appFocus>Address Line 2</label>
        <input type="text" name="stAddress2" id="stAddress2" autocomplete="on" appFocus formControlName="stAddress2" />
      </div>
    </div>

    <div class="col-2-container">
      <div class="fieldset city">
        <label for="stCity" appFocus>City*</label>
        <input type="text" name="stCity" id="stCity" autocomplete="on" appFocus formControlName="stCity" />

      </div>



        <div class="fieldset zip">

          <label for="stZip" appFocus>Zip Code*</label>
          <input type="text" name="stZip" id="stZip" autocomplete="on" appFocus formControlName="stZip" />
          <span *ngIf="!storeRequest.get('stZip').valid && storeRequest.get('stZip').touched" class="validation-error">Please enter your zip code.</span>

        </div>
      </div>

    </div><!--Col-2 end-->

    <div class="col-2-container">
      <div class="fieldset">
        <label for="stEmail" appFocus>Email*</label>
        <input type="email" name="stEmail" id="stEmail" autocomplete="on" appFocus formControlName="stEmail" />
        <span *ngIf="!storeRequest.get('stEmail').valid && storeRequest.get('stEmail').touched" class="validation-error">Please enter your valid email.</span>
      </div>
      <div class="fieldset">
        <label for="stPhone" appFocus>Phone Number*</label>
        <input type="tel" name="stPhone" id="stPhone" autocomplete="on" appFocus formControlName="stPhone" />
        <span *ngIf="!storeRequest.get('stPhone').valid && storeRequest.get('stPhone').touched" class="validation-error">Please enter your valid phone.</span>
      </div>

    </div>

    <h4>Best time to contact you?*</h4>

    <div class="col-2-container">
      <div class="fieldset">
        <div class="dropdown-container" appDrop>
          <label for="bestTime">Select a Time*</label>
          <select name="bestTime" id="bestTime" class="customization-option">
            <option value="Morning" selected>Morning</option>
            <option value="Afternoon">Afternoon</option>
            <option value="Evening">Evening</option>
          </select>
        </div>
      </div>
    </div>

    <h4 *ngIf="!general">Does the organization have a 501 (c)3 Status?</h4>
    <div *ngIf="!general" class="col-2-container">
      <div class="radios-container">
        <div class="radio-round">
          <input type="radio" checked class="radio" name="c3" id="yes501" />
          <label for="yes501">Yes</label>
        </div>
        <div class="radio-round">
          <input type="radio" class="radio" name="c3" id="no501" />
          <label for="no501">No</label>
        </div>
      </div>
    </div>





    <h4>What makes your organization a great fit for Zaxby's?</h4>

    <div class="">
      <textarea rows="8"></textarea>
    </div>

    <br />
    <div class="required">*Required</div>
    <div class="button-container">
      <button class="button gray">Cancel</button>
      <button class="button red">Submit</button>
    </div>

  </div>
</form>

它在大多数情况下都有效,但我在每个下拉菜单后创建了 2 个按钮和 2 个 ul。有什么建议?提前致谢!

【问题讨论】:

【参考方案1】:

就我看到您的代码而言,您在两个&lt;select&gt; 选项中使用了.customization-option 类。因此,当您遍历 querySelectorAll('.customization-option') 时,它会使用 dropdown.length 重复两次,从而创建您的值的副本。

在这种情况下,如果您只需要专门访问第二个 &lt;select&gt; 选项的类,则只需传递索引并访问元素。

document.querySelectorAll('.customization-option')[1];

【讨论】:

【参考方案2】:

谢谢安吉拉。你为我指明了正确的方向。我换了

document.querySelectorAll('.customization-option');

var dropdown = this.el.nativeElement.querySelectorAll('.customization-option');

将el定义为ElementRef后

constructor(public el: ElementRef, private _renderer: Renderer2) 
    this.el = el;
  

【讨论】:

以上是关于Angular 指令创建重复元素的主要内容,如果未能解决你的问题,请参考以下文章

html #angular.js:创建元素指令

Angular2指令,构造函数与onInit [重复]

动态更改 Angular 指令元素属性

为 Angular 指令添加多个“要求”选项

具有范围的 Angular2 指令

angular 指令 要点解析