当我尝试迭代 ngFor 循环时,Angular 2+ attr.disabled 不适用于 div

Posted

技术标签:

【中文标题】当我尝试迭代 ngFor 循环时,Angular 2+ attr.disabled 不适用于 div【英文标题】:Angular 2+ attr.disabled is not working for div when I try to iterate ngFor loop 【发布时间】:2017-12-28 14:13:15 【问题描述】:

我正在开发一个预约应用程序,我正在使用 *ngFor 循环显示预约时间段。

html

<div *ngFor="let item of allTimeSlots">
    <div class="col-sm-3">
        <div class="choice" data-toggle="wizard-slot" [attr.disabled]="item.status" (click)="slotSelected($event)">
            <input type="radio" name="slot" value="item.timeSlot">
            <span class="icon">item.timeSlot</span> item.status
        </div>
    </div>
</div>

打字稿

for (var index = 0; index < this.totalMinutes; index += 15, i++) 
  this.allTimeSlots[i] = new allTimeSlots("", false);

  this.allTimeSlots[i].timeSlot = (hour <= 12 ? hour : hour - 12) + ":" + (minute <= 9 ? ("0" + minute) : minute) + " " + ampm;
  this.bookedTimeSlots.forEach(element => 
    if (this.allTimeSlots[i].timeSlot == element) 
      this.allTimeSlots[i].status = true;
    
  );

这是时间段的屏幕截图,如果时间段已预订,则显示 true,如果可用于调试目的,则显示为 false。

当我运行此代码时,它不会抛出任何错误,但由*ngFor 创建的所有div 元素都被禁用。我尝试使用*ngIf 而不是禁用,它工作得很好。但问题是我想显示时隙是否可用。

【问题讨论】:

你能检查一下时间段的所有状态是否都是真的吗? (console.log(this.allTimeSlots) 在 for 循环之后),如果是,那么问题在于您如何检查时隙 我检查了它,即使 item.status 仅用于调试目的。它打印出我给它的正确值 true 和 false。但它在 [attr.disabled] 中不起作用 好的,我创建了一个plunker here 来演示您描述的问题,我现在会尝试看看如何解决它:) 是的,完全一样的事情发生在我身上,我已经编辑了问题并在其中添加了我的截图,从中可以更好地理解它。 @0mpurdy 你可以试试this answer给出的语法。 【参考方案1】:

使用[disabled] 而不是[attr.disabled]

这是因为[attr.disabled]="false" 会将disabled="false" 添加到 html 中的元素中,仍然会禁用该元素

不会禁用元素的语法

<button>Not Disabled</button>
<button [disabled]="false">Not Disabled</button>

禁用元素的语法

<button disabled></button>
<button disabled="true"></button>
<button disabled="false"></button>
<button [attr.disabled]="true"></button>
<button [attr.disabled]="false"></button>
<button [disabled]="true"></button>

disabled 将禁用一个元素,无论它是真还是假,它的存在意味着该元素将被禁用。如果variable 为假,Angular 将根本不会为[disabled]="variable" 添加disabled 元素。

正如您在评论中提到的,您使用的是 div 元素而不是按钮,其中 angular 2 无法识别禁用的元素。如果您要捕获 click 事件,我建议您使用按钮,但如果不是,您可以执行以下操作:

<div [ngClass]=" 'disabled': item.status "></div>

并有一个 CSS 类来显示预订的时间段。

有关[ngClass] 的更多信息,请访问the documentation

【讨论】:

@user2136053 那么你肯定也会喜欢这个: [attr.disabled]="isDisabled ? '' : null" (注意内部的 '' 是 2 个单引号) 派对迟到了,但我认为 [disabled]="false" 不会禁用该元素。但是 [attr.disabled]="false" 确实如此。【参考方案2】:

正如 0mpurdy 回答的那样,您应该使用 [disabled] 属性。变量不必是布尔值,但表达式应该是。

在您的代码中,它确定 item.status 是虚假的还是真实的。因此,如果它不是 null/NaN/undefined,您将获得“true”并且 div 将被禁用。

改为插入表达式:

[disabled]="item.status === 'occupied'"


编辑

对不起,我错过了。 由于您无法禁用 div,因此请将 disabled 属性放在输入标签内。

<input type="radio" [disabled]="item.status === 'occupied'" name="slot" value="item.timeSlot">

由于您想将选择显示为禁用,您需要将其直接放在输入中。单选按钮将无法点击,并且会显示“光标:不允许”。

希望有帮助

【讨论】:

我尝试了所有这些方法。但 [disabled] 不适用于 div 元素。 感谢您的贡献!截至目前,我正在使用div 元素来完成radio 的工作,我只需要禁用div。上面批准的答案对我来说很有效。【参考方案3】:

Disabled 不能用于 div 元素,仅适用于以下元素

<button>    
<fieldset>  
<input> 
<keygen>    
<optgroup>  
<option>    
<select>    
<textarea>  

See this

因此,对于您的问题,您可以使用以下方法处理:

<div 
  class="choice" 
  data-toggle="wizard-slot" 
  [class.disabled]="item.status" 
  (click)="slotSelected($event)">
  <input 
    type="radio" 
    name="slot" 
    value="item.timeSlot" 
    [disabled]="item.status">
  <span class="icon">item.timeSlot</span> item.status
</div>

你应该添加样式

.disabled 
  cursor: not-allowed;

【讨论】:

不适合我。给出错误 => 未捕获的错误:模板解析错误:无法绑定到“已禁用”,因为它不是“div”的已知属性。 (" 应该指出,该解决方案不会像通常使用 disabled 属性的情况那样阻止在该元素上触发 click 事件? @Jacques 如果你不希望点击事件触发添加pointer-events:none【参考方案4】:

这样使用:

[attr.disabled]="isDisabled ? '' : null"

只读也是如此。

【讨论】:

如果你已经有 Reactive Forms 的逻辑,那将会覆盖。 这就是我想要的。角度不同【参考方案5】:

CSS

.disabled-contenct 
  pointer-events: none;
  opacity: 0.4;

HTML

<div [class.disabled-contenct]="!isDisabledContent"></div>

TS

isDisabledContent: boolean;

那么您可以随时切换 isDisabledContent。

【讨论】:

【参考方案6】:

Attribute 指令肯定会帮助您禁用或启用 div 或任何其他 HTML 元素及其子元素。

禁用指令

首先,创建一个属性指令,它将一个参数 (appDisable) 作为输入。它将根据输入禁用/启用 DOM 元素及其子 DOM 元素。

import  AfterViewInit, Directive, ElementRef, Input, OnChanges, Renderer2  from '@angular/core';

const DISABLED = 'disabled';
const APP_DISABLED = 'app-disabled';
const TAB_INDEX = 'tabindex';
const TAG_ANCHOR = 'a';

@Directive(
  selector: '[appDisable]'
)
export class DisableDirective implements OnChanges, AfterViewInit 

  @Input() appDisable = true;

  constructor(private eleRef: ElementRef, private renderer: Renderer2)  

  ngOnChanges() 
    this.disableElement(this.eleRef.nativeElement);
  

  ngAfterViewInit() 
    this.disableElement(this.eleRef.nativeElement);
  

  private disableElement(element: any) 
    if (this.appDisable) 
      if (!element.hasAttribute(DISABLED)) 
        this.renderer.setAttribute(element, APP_DISABLED, '');
        this.renderer.setAttribute(element, DISABLED, 'true');

        // disabling anchor tab keyboard event
        if (element.tagName.toLowerCase() === TAG_ANCHOR) 
          this.renderer.setAttribute(element, TAB_INDEX, '-1');
        
      
     else 
      if (element.hasAttribute(APP_DISABLED)) 
        if (element.getAttribute('disabled') !== '') 
          element.removeAttribute(DISABLED);
        
        element.removeAttribute(APP_DISABLED);
        if (element.tagName.toLowerCase() === TAG_ANCHOR) 
          element.removeAttribute(TAB_INDEX);
        
      
    
    if (element.children) 
      for (let ele of element.children) 
        this.disableElement(ele);
      
    
  

不要忘记在 AppModule 中注册 DisableDirective

如何在组件中使用指令? 在组件的指令中传递布尔值(true/false)。

<div class="container" [appDisable]="true">
</div>

您可以参考完整的帖子HERE

在Stackblitz上运行示例

【讨论】:

【参考方案7】:

有一种方法可以使用attribute binding。这是一个简单的方法。实现方法见the docs。

【讨论】:

以上是关于当我尝试迭代 ngFor 循环时,Angular 2+ attr.disabled 不适用于 div的主要内容,如果未能解决你的问题,请参考以下文章

如何使用包含键作为字符串和值作为映射迭代的ngFor循环映射进行迭代

*ngFor 在 angular2 中运行无限循环

Angular2中嵌套ngFor循环的计数器

Angular 2. *ngFor 的问题,当我使用 Pipe 时

在 ngFor 中计数 - Angular 2

Angular 2 - 异步管道中的无限循环