Angular JS——将ng-repeat应用于异步添加到DOM的东西
Posted
技术标签:
【中文标题】Angular JS——将ng-repeat应用于异步添加到DOM的东西【英文标题】:Angular JS -- Applying ng-repeat to things added to the DOM asyncronously 【发布时间】:2016-06-04 08:17:37 【问题描述】:我正在开发一个“小部件”库,它创建一个带有可拖动、动态加载的小部件的仪表板。整体解决方案是使用 Angular。每个小部件都有一个 javascript 文件和一个 Jade 文件。对于我们的一些小部件,结果使用 ng-repeat 等角度指令。这是一个特定小部件生成的代码:
<tr ng-repeat="account in vmAccountList">
<td ng-click="showTransactions(account)">account.account.accountNumber</td>
<td ng-click="showTransactions(account)">account.account.accountDisplayName.defaultNormalAccountName</td>
<td ng-click="showTransactions(account)" ng-if="account.account.acctTypeId==1">account.account.runningBalance.amount | currency</td>
<td ng-click="showTransactions(account)" ng-if="account.account.acctTypeId==3">account.account.currentBalance.amount | currency</td>
<td ng-click="showTransactions(account)" ng-if="account.account.acctTypeId==4">account.account.currentBalance.amount | currency</td>
<td><a ng-click="deleteAccount(account.itemId);" class="btn btn-default btn xs">X</a></td>
</tr>
问题是 ng-repeat 永远不会被处理——生成的小部件只是呈现一个带有上面所有合并标签的单行,完全不知道数据。我尝试了许多不同的 $scope.$apply 和 $scope.$digest 组合——它们都不起作用。我收集到这个问题是因为当我的小部件被下载时,JADE 渲染和 JS 应用它可能在页面的生命周期中太“晚”了,无法使用 Angular 进程指令。
是否有一个命令可以手动告诉 Angular 去查找所有的 ng-repeats 并渲染它们?如果做不到这一点,有没有办法将东西插入到加载 aync 的 DOM 中并让 Angular 应用这些命令?
加载小部件和填充 DOM 的代码:
$.get('/v1/widget/' + name, (data) =>
var jadeCode = data;
$.get('/v1/widget/js/' + name, (data) =>
if(!w)
w = 2;
if(!h)
h = 1;
if(that._lastX + w > SDB.NumberOfVerticalLanes)
that._lastX = 0;
that._lastY += h;
var retVal = new Widget(name, domId, that._lastX, that._lastY, w, h, '');
var processedWidget = eval(data + "(retVal)");
processedWidget._jadeFN = jade.compile(jadeCode);
var content = processedWidget._jadeFN(processedWidget.JadeScope);
//The 'content variable contains the markup I posted above at this point, and SetContent applies it to the DOM
processedWidget.SetContent(content);
);
);
上面sn-p中注释高亮的SetContent方法,就是简单的用jquery插入新的内容:
this.SetContent = (cnt) =>
this.Content = cnt;
$("#" + this.Id).html(cnt);
;
如果我的一些术语(特别是关于 Angular)不正确,我深表歉意,我只是对它有点熟悉,坦率地说,我不是一个忠实的粉丝。但是该项目使用它,所以我必须找到一种方法来让它工作。谢谢!
【问题讨论】:
据我了解,当您有 ng-repeat 时,它会在您的案例“vmAccountList”中为数组值设置一个观察者,因此当您更改它时它应该更新。如果由于某些奇怪的原因它没有,您可以在获取数据后尝试 $apply。 我都试过了——看来 Angular 根本不知道我的 ng-repeat,即使我更新 vmAccountList 或调用 $apply 它根本不会更新我的组件。我们知道,如果代码没有异步加载,它就可以工作——但是一旦我们加载它并将其动态添加到 DOM 中,ng-repeat 就会停止工作。 尝试在 processesWidget.SetContent 行之后添加 $scope.$apply()。如果这不起作用,那么我猜您的 html 替换正在删除该过程中的角度链接。需要完整的页面代码才能深入挖掘。 【参考方案1】:解决方案最终是使用 Angular 的 $compile 来创建一个数据感知 DOM 节点,如下所示:
//Step 1: Create empty widget
var retVal = new Widget(name, domId, that._lastX, that._lastY, w, h, '');
//Step 2: Process Widget Javascript
var processedWidget = eval(data + "(retVal)");
//Step 3: Process the Jade and set the content
processedWidget._jadeFN = jade.compile(jadeCode);
var content = processedWidget._jadeFN(processedWidget.JadeScope);
content = window.compile(content)(processedWidget.JadeScope);
//Angular Black Magic:
if(processedWidget.JadeScope.$apply)
processedWidget.JadeScope.$apply();
SDB.AddWidget(processedWidget);
processedWidget.SetContent(content);
注意 $apply 调用和添加的 window.compile,它只是对注入 Angular CTOR 中的 $compile 函数的引用。
【讨论】:
以上是关于Angular JS——将ng-repeat应用于异步添加到DOM的东西的主要内容,如果未能解决你的问题,请参考以下文章
Angular js - 如果 ng-repeat 为空则显示消息
Angular.js - ng-repeat 不显示更新的数组
使用Angular JS时如何在ng-repeat内的img标签中显示图像?