首页 > 解决方案 > 与依赖于 API 数据的 DOM 操作相关的问题

问题描述

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

例子:

这是状态栏正常工作的示例

这就是页面加载时的样子,这就是问题所在

如图所示,我们有 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。

生产.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')); 变量将返回空值,因为列表中的离子项尚未创建。

  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 variable "),因为它导致双倍API 调用。所以我选择用 Observable 的数据填充一个数组,然后将它绑定到我的列表,我们就到了。

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

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

谢谢你的时间!非常感谢。

标签: angulartypescriptionic-frameworkdom

解决方案


尝试使用 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>

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


推荐阅读