angular - 与依赖于 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 看到的元素;(如果我能让它发挥作用,这可能是我最喜欢的方法。)
我试过的:
只需调用 searchForLot() 函数 ngOnInit;
不顺利,我的 this.ordersElements = Array.from(document.getElementsByClassName('OrderItem')); 变量将返回空值,因为列表中的离子项尚未创建。
在我的 order.service.ts getOrders() 函数中添加 await/.promise();
没有做任何不同的事情。老实说,有点像冰雹玛丽。
使用生命周期钩子;
一开始看起来很有希望,但与 ngOnInit 相同的问题,列表项最后加载,因为页面上的所有内容在 API 可以传递信息之前加载。
使用指令?和/或使用@ViewChildren/@ViewChild?;
非常神秘的文档,可能需要阅读更多关于它们的信息,无法真正找到与我的用例相关的任何示例。
在我的 production.page.ts 中动态生成 HTML 元素;
这就是我目前正在做的事情。
等等......我已经尝试了很多我只是不记得了。
想我会把这个发布在 Stack Overflow 上,并从比我更好的人那里获得一些反馈(第一个 angular/ionic 网站)。
欢迎任何反馈,完全改变我调用数据的方式是可能的,我之前曾与 ngOnInit 一起工作,但我决定不直接使用我的 Observable(使用 *ngFor="Let order of Observable variable "),因为它导致双倍API 调用。所以我选择用 Observable 的数据填充一个数组,然后将它绑定到我的列表,我们就到了。
我宁愿一个完整的答案,而不仅仅是代码。我必须为工作中的其他项目学习理论。
如果您需要更多信息,请告诉我。
谢谢你的时间!非常感谢。
解决方案
尝试使用 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>
如果我正确理解了您的代码应该如何工作,那么这应该可以为您解决问题。:)
推荐阅读
- git - 如何在git中合并分支?
- javascript - 如何在javascript的单元测试用例中覆盖setInterval
- google-app-maker - Appmaker面板和画布高度
- python - 重新采样 Pandas 时间序列,以便日期表示每个月的 1 日
- c - 递归遍历目录时C中的gmtime不一致
- mysql - 使用给定的日期期间检查动态到期日期
- javascript - Config.get() 没有从文件中获取配置:“custom-environment-variables.json”Nodejs,JavaScript
- r - na.interpolation(data[, i], option) 中的错误:输入 x 不是数字
- solidity - 即使我的代码中没有构造函数,但我收到错误,如果您发送值,则应该支付构造函数
- node.js - NodeJs/Electron:如何在 ipcMain 发回他的答案之前等待函数完成?