【问题标题】:Trouble relating to DOM manipulation that is dependant on API data与依赖于 API 数据的 DOM 操作相关的问题
【发布时间】:2021-09-05 06:26:43
【问题描述】:

我目前正在使用带有 Angular 的 Ionic 框架,我遇到了与“着色”相关的问题(因为缺乏更好的术语)我的应用程序开始屏幕中的这些小状态栏。

例子:

This is an example of the status bars working correctly

And this is what it looks like on page load, this is the problem

如图所示,我们有 5 个部门。如果部门完成了部分订单的工作,那么他们的小方块就会变成绿色。如果不是,则为红色。

作为参考,这是 HTML 的样子:

<ion-content>
 <ion-list>
  <div class="OrderItem" *ngFor="let order of orderResults">
   <ion-item button id="{{ order.OrderID }}"  [routerLink]="['order-details/', order.OrderID]">
    <ion-label text-wrap>
     <h1 class="OrderIdentifier" style="text-align: center;">{{ order.OrderID }}</h1>
     <h3 style="text-align: center;">Lot: {{ order.productionLotNumber }} --- Stop: {{ order.StopNumber }}</h3>

     <div style="display: inline-flex; margin-left: 25%; width: 50%;">
      <p class="Desk" id="{{ order.DeskStatus }}" style="width: 20%;text-align: center;">Desk</p>
      <p class="Cabinets" id="{{ order.CabinetStatus }}" style="width: 20%; text-align: center;">Cabinets</p>
      <p class="Hutch" id="{{ order.HutchStatus }}" style="width: 20%;text-align: center;">Hutch</p>
      <p class="Table" id="{{ order.TableStatus }}" style="width: 20%;text-align: center;">Table</p>
      <p class="Wallunit" id="{{ order.WallunitStatus }}" style="width: 20%;text-align: center;">Wallunit</p>
     </div>
    </ion-label>
   </ion-item>
  </div>
 </ion-list>
</ion-content>

请原谅我的 CSS,这些天我将不得不将所有这些都转储到样式表中。

如您所见,它是一个包含所有订单的离子列表,由 orderResults 数组填充,该数组本身由 Observable 填充。通过对 Python API 的 HTTP 调用填充 Observable。

production.page.ts:

export class ProductionPage implements OnInit {
 ordersElements: Array<any>;

 lotResults: any;
 orderResults: any;

 constructor(private orderService: OrderService) { }

 ngOnInit() {
  this.orderService.getLots().subscribe(data =>
  {
    this.lotResults = data;
  });

  this.orderService.getOrders().subscribe(data => {
    this.orderResults = data;
  });
 }
}

 searchForLot() {
let tempOrderResults = this.orderResults;
this.ordersElements = Array.from(document.getElementsByClassName('OrderItem'));

this.searchLot = (document.getElementById('selectLot') as HTMLSelectElement).value;
this.searchOrder = parseInt((document.getElementById('inputOrder') as HTMLInputElement).value);
this.searchStop = parseInt((document.getElementById('inputStop') as HTMLInputElement).value);

if (!(this.searchLot === undefined) || !(isNaN(this.searchOrder)) || !(isNaN(this.searchStop))) {

  if (this.searchLot === undefined) {
    this.searchLot = '0';
  }

  if (isNaN(this.searchOrder) || (this.searchOrder.toString()).length > 6) {
    this.searchOrder = 0;
  }

  if (isNaN(this.searchStop) || (this.searchStop.toString).length >= 3) {
    this.searchStop = 0;
  }

  if (this.searchLot !== '0') {
    tempOrderResults = tempOrderResults.filter(item => item.productionLotNumber === this.searchLot);
  }

  if (this.searchOrder !== 0) {
    tempOrderResults = tempOrderResults.filter(item => item.OrderID === String(this.searchOrder));
  }

 if (this.searchStop !== 0) {
    tempOrderResults = tempOrderResults.filter(item => item.StopNumber === this.searchStop);
  }
  const matches: Array<any> = [];

  //For each Order that is left after the filters
  tempOrderResults.forEach(result => {
    //For each element's from the original API call (which are drawn)
    this.ordersElements.forEach(orders => {
      const divElement = (orders as HTMLDivElement);

      //Hide all elements, easier to hide everything and selectively choose which elements to show in a different function
      divElement.style.display = 'none';

      if(result.OrderID === divElement.children[0].id) {
        //Filling array with DOM elements that match filtered orders, by order identifier
        matches.push(divElement);
      }
    });
  });

  //for each order, send div element to the function for proper "coloring"
  matches.forEach(div => {
   (div as HTMLDivElement).style.display = 'inline';
   this.colorStatus(div);
  });
 }
}

colorStatus(statusElement) {
    //This will have to be modified to take an element, then change that element status
    //statusElement is the element object itself

 const eDesk = (statusElement as HTMLDivElement).getElementsByClassName('Desk')[0];
 const eCabinets = (statusElement as HTMLDivElement).getElementsByClassName('Cabinets')[0];
 const eHutch = (statusElement as HTMLDivElement).getElementsByClassName('Hutch')[0];
 const eTable = (statusElement as HTMLDivElement).getElementsByClassName('Table')[0];
 const eWallunit = (statusElement as HTMLDivElement).getElementsByClassName('Wallunit')[0];

 console.log(eDesk);

 if(eDesk.id === '0')
 {
   (eDesk as HTMLParamElement).style.backgroundColor = 'Red';
 } else {
   (eDesk as HTMLParamElement).style.backgroundColor = 'Green';
 }

 if(eCabinets.id === '0')
 {
   (eCabinets as HTMLParamElement).style.backgroundColor = 'Red';
 } else {
   (eCabinets as HTMLParamElement).style.backgroundColor = 'Green';
 }

 if(eHutch.id === '0')
 {
   (eHutch as HTMLParamElement).style.backgroundColor = 'Red';
 } else {
   (eHutch as HTMLParamElement).style.backgroundColor = 'Green';
 }

 if(eHutch.id === '0')
 {
   (eTable as HTMLParamElement).style.backgroundColor = 'Red';
 } else {
   (eTable as HTMLParamElement).style.backgroundColor = 'Green';
 }

 if(eHutch.id === '0')
 {
   (eWallunit as HTMLParamElement).style.backgroundColor = 'Red';
 } else {
   (eWallunit as HTMLParamElement).style.backgroundColor = 'Green';
 }
}

至于 this.orderResults,它由 OrderService 服务填充。

像这样:

order.service.ts

@Injectable({
providedIn: 'root'
})

export class OrderService {
baseUrl = 'This is an ip, removed it for reasons, just imagine something like 192.168.***.***';

getOrders() {
const url = this.baseUrl + 'GetProductionOrders';
return this.http.get(url);
}

现在我们已经了解了情况。

如何在每个离子项目上调用一个函数来为我的小状态方块着色?

或者,调用一个函数来检索所有元素并为它们着色?

或者,或者,在 ngOnInit 上为它们全部着色并过滤元素数组,仅显示那些需要使用 display:none; 看到的元素; (如果我能让它发挥作用,这可能是我最喜欢的方法。)

我尝试过的:

  1. 只需调用searchForLot()函数ngOnInit;

    不顺利,我的 this.ordersElements = Array.from(document.getElementsByClassName('OrderItem'));变量将返回空值,因为列表中的 ion-item 尚未创建。

  2. 在我的 order.service.ts getOrders() 函数中添加 await/.promise();

    没有做任何不同的事情。老实说,有点像冰雹玛丽。

  3. 使用生命周期钩子;

    起初看起来很有希望,但与 ngOnInit 的问题相同,列表项最后加载,因为页面上的所有内容在 API 可以传递信息之前加载。

  4. 使用指令?和/或使用@ViewChildren/@ViewChild?;

    非常神秘的文档,可能需要阅读更多关于它们的信息,找不到任何与我的用例相关的示例。

  5. 在我的 production.page.ts 中动态生成 HTML 元素;

    这是我目前正在做的事情。

等等……我已经尝试了很多我只是想不起来了。

我想我会在 Stack Overflow 上发布这篇文章,并从比我更好的人那里获得一些反馈(第一个 angular/ionic 网站)。

欢迎任何反馈,完全改变我调用数据的方式是可能的,我之前曾与 ngOnInit 一起工作,但我决定不直接使用我的 Observable(使用 *ngFor="Let order of Observable 变量"),因为它导致 API 调用翻倍。所以我选择用 Observable 的数据填充一个数组,然后将它绑定到我的列表中,我们就在这里。

我宁愿一个完整的答案,而不仅仅是代码。我必须为正在进行的其他项目学习理论。

如果您需要更多信息,请告诉我。

感谢您的宝贵时间! 非常感谢。

【问题讨论】:

  • 是否可以将您的代码复制到 Stackblitz 上?这可以通过使用 ViewChildren 而不是 getElementById 和 ngStyle/ngClass 来设置颜色等以更 Angular 的方式完成。:)
  • @LarsRodal 以前从未使用过 Stackblitz,但我可能可以用静态数据复制它。在我的午餐自动取款机上,大约一个小时后回来
  • 不幸的是,Stackblitz 不起作用,由于某种原因,IDE 不明白 是什么,我怀疑他们可能使用的是旧版本的 Ionic。不过不确定。
  • 那么您能为您的数据模型提供接口吗?我看到它们被设置为任何,知道这些会更容易给出解决方案????
  • 添加了一个我认为应该对你有用的答案,我对你当前代码的理解:)

标签: angular typescript ionic-framework dom


【解决方案1】:

尝试使用 ngStyle。它有两种类型的语法,对于您的用例,我认为绑定单个属性 ([style.attr]=value) 是最简单的方法:

 <div style="display: inline-flex; margin-left: 25%; width: 50%;">
  <p class="Desk" [style.backgroundColor]="order?.deskStatus == '0' ? 'red' : 'green" id="{{ order.DeskStatus }}" style="width: 20%;text-align: center;">Desk</p>
  <p class="Cabinets" [style.backgroundColor]="order?.CabinetStatus == '0' ? 'red' : 'green" id="{{ order.CabinetStatus }}" style="width: 20%; text-align: center;">Cabinets</p>
  <p class="Hutch" [style.backgroundColor]="order?.HutchStatus == '0' ? 'red' : 'green" id="{{ order.HutchStatus }}" style="width: 20%;text-align: center;">Hutch</p>
  <p class="Table" [style.backgroundColor]="order?.TableStatus == '0' ? 'red' : 'green" id="{{ order.TableStatus }}" style="width: 20%;text-align: center;">Table</p>
  <p class="Wallunit" [style.backgroundColor]="order?.WallunitStatus == '0' ? 'red' : 'green" id="{{ order.WallunitStatus }}" style="width: 20%;text-align: center;">Wallunit</p>
 </div>

如果我正确理解了您的代码应该如何工作,那么这应该可以为您解决问题。 :)

【讨论】:

  • 效果很好!能够在我的打字稿文件中删除一堆现在多余的代码!不知道你可以像这样将逻辑嵌入到 HTML 中。谢谢
  • 您对类 (ngClass) 也有相同的方法,其工作方式相同 ([class.myClassName]=condition) ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 2020-12-01
  • 2011-09-07
  • 2016-09-05
  • 1970-01-01
  • 2021-05-16
  • 1970-01-01
相关资源
最近更新 更多