Angular15+PrimeNG实现嵌套对象值变更时按表达式联动更新
实现Angular 15 + PrimeNG树形组件的数值联动计算
核心思路
要实现子节点数值变更后向上触发父节点表达式计算,关键是给每个节点添加父节点引用,这样能递归向上溯源;同时借助math.js解析表达式并计算,自动忽略非数值类型的节点。
步骤1:预处理树节点,添加父节点引用
在组件初始化时,递归遍历原始数据,给每个节点新增parent属性,方便后续向上遍历父节点:
import { Component, OnInit } from '@angular/core'; import { evaluate } from 'mathjs'; interface TreeNode { id: number; data: { value: string | number }; expression: string | null; subElements: TreeNode[]; parent?: TreeNode; // 新增父节点引用字段 } @Component({ selector: 'app-tree-calculator', templateUrl: './tree-calculator.component.html' }) export class TreeCalculatorComponent implements OnInit { treeData: TreeNode[] = []; // 你的原始嵌套数据 originalData = { id: 1, data: { value: "Lorem ipsum" }, expression: null, subElements: [ { id: 2, data: { value: 2 }, expression: "v0 / v1", subElements: [ { id: 4, data: { value: 100 }, expression: null, subElements: [] }, { id: 5, data: { value: 50 }, expression: "v0 + v1", subElements: [ { id: 6, data: { value: 20 }, expression: null, subElements: [] }, { id: 7, data: { value: 30 }, expression: null, subElements: [] } ] } ] }, { id: 3, data: { value: "Lorem ipsum" }, expression: null, subElements: [] } ] }; ngOnInit(): void { this.treeData = [this.addParentReferences(this.originalData)]; } private addParentReferences(node: TreeNode, parent?: TreeNode): TreeNode { node.parent = parent; if (node.subElements.length > 0) { node.subElements = node.subElements.map(child => this.addParentReferences(child, node)); } return node; } }
步骤2:编写联动计算核心函数
当输入框数值变化时,先更新当前节点值,再递归向上遍历父节点,依次计算每个有表达式的父节点数值:
calculateExpression(event: any, node: TreeNode): void { // 跳过非数值类型的节点 if (typeof node.data.value !== 'number') return; // 从当前节点的父节点开始向上遍历 let currentParent = node.parent; while (currentParent) { // 跳过无表达式或非数值类型的父节点 if (typeof currentParent.data.value !== 'number' || !currentParent.expression) { currentParent = currentParent.parent; continue; } // 收集子节点数值:v0对应第一个子节点,v1对应第二个,以此类推 const variables: Record<string, number> = {}; currentParent.subElements.forEach((child, index) => { if (typeof child.data.value === 'number') { variables[`v${index}`] = child.data.value as number; } }); try { // 用math.js计算表达式,保留两位小数 const result = evaluate(currentParent.expression, variables); currentParent.data.value = Number(result.toFixed(2)); } catch (error) { console.error('表达式计算失败:', error); } // 继续向上处理父节点的父节点 currentParent = currentParent.parent; } }
步骤3:修改模板,控制输入框显示
在p-tree模板中,仅对数值类型的节点渲染p-inputNumber,非数值节点直接显示文本:
<p-tree [value]="treeData"> <ng-template pTemplate="default" let-node> <div class="flex align-items-center"> <!-- 仅数值类型节点显示输入框 --> <ng-container *ngIf="typeof node.data.value === 'number'"> <p-inputNumber [(ngModel)]="node.data.value" (onInput)="calculateExpression($event, node)" [minFractionDigits]="2" [maxFractionDigits]="2" ></p-inputNumber> </ng-container> <!-- 非数值类型节点显示文本 --> <span *ngIf="typeof node.data.value !== 'number'">{{ node.data.value }}</span> </div> </ng-template> </p-tree>
前置准备
确保已安装math.js,执行命令:
npm install mathjs
内容的提问来源于stack exchange,提问作者Death Dog
相关产品推荐
相关产品推荐

