【问题标题】:Using Typescript/Angular to hide HTML elements with RXJS使用 Typescript/Angular 通过 RXJS 隐藏 HTML 元素
【发布时间】:2021-07-01 00:50:00
【问题描述】:

有显示食谱的 div(来自对象数组中组件的属性 - 'Recipes','Recipes' 包括一个属性'Recipes.diet',它是一串饮食),我有一个 filterf 组件发送饮食订阅(目前为“素食”、“无麸质”、“素食”)。我想隐藏包含饮食关键字的食谱,例如'Vegetarian' 的 observable 隐藏了所有在其 'diet' 属性中不包含 'Vegetarian' 关键字的食谱。

目前我没有发现差异。
我尝试使用 angular ngClass、ngStyle 来动态过滤类列表以包含“.hide”(将显示设置为无)。

当我将显示静态设置为“无”时,它是成功的,我目前正在尝试一种直接通过 HTML 元素对象操作 Dom 的方法,但这也不起作用。

我检查了关键字是否通过,并且它们与正确的 div 匹配成功。我尝试通过打字稿设置样式属性并添加类类型(这是我在下面尝试的方法)。

我知道这将是一个非常简单的问题,但我已经没有办法检查了,我在网上和 StackOverflow 上进行了搜索,并尝试了我能想到的各种 DOM/Angular 变化。

HTML:

 <div *ngFor="let recipe of recipes" id="{{recipe.title}}-card" (click)="recipeWasChosen(recipe)">
    <app-recipe-title class="recipe-card" [recipe]="recipe">
    </app-recipe-title>
</div>

打字稿:

this.recipeService.recipeRestrictions.subscribe((restrictions: string[]) => {
      this.recipes.forEach((recipe: Recipe) => {
        let hide = false;
        for (const restriction of restrictions) {
          if (!recipe.diet.includes(restriction)) {
            hide = true;
          }
        }
        if (hide) {
          this.hideCardWithHTMLElement(recipe.title);
        } else this.hideCardWithHTMLElement(recipe.title);
      });
    });

  hideCardWithHTMLElement(title: string) {
    let card = document.getElementById(`${title}card`);
    if (card.classList.contains('hidden')) {
      card.className = '';
    } else card.className = 'hidden';
  }

CSS:

.hidden {
  display: none;
}

【问题讨论】:

    标签: html angular typescript dom rxjs


    【解决方案1】:

    如果您只想按限制类型过滤列表,您不需要隐藏元素,但您可以过滤掉一般包含限制的元素。您可以这样做

    this.recipes$ = this.recipeService.recipeRestrictions
    .pipe(
       map((restrictions: string[]) => {
          return this.recipes.filter((recipe) => restrictions.every((restriction) => !recipe.diet.includes(restriction)))
       })
    )
    

    在模板中

    <div *ngFor="let recipe of recipes$ | async">
    ...
    </div>
    

    【讨论】:

    • 我喜欢这背后的概念,我之前使用的是 async 和模板。但这不起作用,然后我尝试使用 'of' 运算符将 'recipes' 转换为 'recipes$' ,但仍然没有显示。要将“recipes”的初始订阅与“recipes$”的异步子集结合起来,然后使用“restrictions”进行操作,在模板上显示时,它可能会起作用,但这超出了我对 RxJs 的理解。
    • 我的尝试,但不起作用。 this.recipeService.getCurrentRecipesWithinPriceRange(this.tier).subscribe((recipes: Recipe[]) =&gt; this.recipes = recipes); this.recipeService.recipeRestrictions.subscribe((restrictions) =&gt; { this.recipes.filter((recipe) =&gt; { restrictions.every((restriction) =&gt; !recipe.diet.includes(restriction)) }); });
    • 检查您的条件。我在stackblitz 上为您创建了一个示例
    • 谢谢!我发现至少 Stackblitz 没有在我的 Firefox 上正常运行,所以这是一个改进,我还改进了我的帖子以更好地传达我想要的解决方案。有两种订阅,一种是食谱:根据杂项方面(例如价格范围)更新的食谱,以及限制之一:字符串 [] 应该在限制发出时影响显示的食谱。
    • 以下代码没有一个订阅影响另一个订阅,即使通过日志记录我可以看到“限制”订阅之后是第二次订阅食谱
    【解决方案2】:

    您是否尝试过使用 *ngIf 根据隐藏状态动态隐藏食谱? 由于您不能在同一个容器上添加 *ngFor 和 *ngIf,您可以像这样使用 ng-container

    <div *ngFor="let recipe of recipes" id="{{recipe.title}}-card" (click)="recipeWasChosen(recipe)">
        <ng-container *ngIf="isFiltered(receipe)">
            <app-recipe-title class="recipe-card" [recipe]="recipe"></app-recipe-title>
        </ng-container>
    </div>
    

    isFiltered(receipe) 方法是您的过滤器,它根据配方是否被过滤返回 true 或 false。

    还要确保避免通过 java 脚本操作 DOM(最好使用 ngIf 指令),因为这会导致问题。

    【讨论】:

    • 试过了,虽然使用 divs 而不是 ng-container(我不知道的更好的选择,谢谢!),我希望这会有所作为,但它没有,过滤仍然没有效果。这是我尝试过的: HTML:&lt;div *ngFor="let recipe of recipes" id="{{recipe.title}}-card" (click)="recipeWasChosen(recipe)"&gt; &lt;ng-container *ngIf="hideCard(recipe.title)"&gt; &lt;app-recipe-title class="recipe-card" [recipe]="recipe"&gt; &lt;/app-recipe-title&gt; &lt;/ng-container&gt; &lt;/div&gt; TS:pastebin link
    猜你喜欢
    • 2018-06-14
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 2014-05-10
    • 2011-12-28
    • 1970-01-01
    • 2019-06-12
    • 2023-03-19
    相关资源
    最近更新 更多