从ng-repeat中重新评估控制器功能

时间:2014-09-03 10:08:32

标签: angularjs

我有以下角度代码:

<tr ng-repeat="vm in ...">
    <span ng-if="myLookupFunc(vm)"> {{myLookupFunc(vm)).label}}, {{myLookupFunc(vm).uuid}}
    <span ng-if="!myLookupFunc(vm)">-</span>
</tr>

正如您所看到的,对于单个项目,myLookupFunc被调用4次。 如何对其进行优化,以便只为给定的“vm”实例调用一次? 我确实尝试在'tr'级别使用ng-init,但是在'vm'的属性发生变化之后它没有重新评估 - 并且它是预期的,根据文档ng-init不应该用于这种情况。

那么angularjs实现这个目标的正确方法是什么?

4 个答案:

答案 0 :(得分:0)

请检查以下代码以获得更好的优化。

<tr ng-repeat="vm in ..." ng-init="lookupData=myLookupFunc(vm)">
    <span ng-if="lookupData"> {{lookupData.label}}, {{lookupData.uuid}}
    <span ng-if="!lookupData">-</span>
</tr>

答案 1 :(得分:0)

ng-init将在ng-repeat开始时运行一次。这就是为什么它不会为你改变。

您必须使用控制器来获取变量数据,但可以改进它。

一种方法是在您的控制器上执行此操作:

function lookup(vm, firstRun) {

    if (firstRun) {
       $scope.lookupVar = myLookupFunc(vm);
    }
    else {
       return $scope.lookupVar;
    }
}

然后你可以保持你的HTML代码几乎相同:

<tr ng-repeat="vm in ...">
    <span ng-if="lookup(vm, true)"> {{lookup(vm)).label}}, {{lookup(vm).uuid}}
    <span ng-if="!lookup(vm)">-</span>
</tr>

更好的解决方案只是在HTML中保留一个范围然后执行:

<tr ng-repeat="vm in ...">
    <span>{{getVmText(vm)}}</span>
</tr>

在控制器上定义一个函数getVmText,用于检查VM值并返回文本。我相信这是更好的方式。

答案 2 :(得分:0)

使用数据模型并在必要时进行更新(即使发生&#34;外部事件&#34;)。通过这种方式,您不必费心去重新评估控制器功能&#34;它只是纯粹的角度数据绑定。

示例:

$scope.vms = ["id1", "id2", "id3"];

// this var will hold your data model (it could also be on the $scope, but for 
// demo let's leave it like this) 
var data = {
  "id1": {
    uuid: "123-123",
    label: "label 1"
  },
  "id2": {
    uuid: "456-456",
    label: "label 2"
  },
  "id3": {
    uuid: "abc-abc",
    label: "label 3"
  }
};

$scope.myLookupFunc = function(id) {
  return data[id];
};

然后你可以像这样使用它:

<div ng-repeat="vm in vms" ng-init="lookupData=myLookupFunc(vm)">
  <span ng-if="lookupData"> {{lookupData.label}}, {{lookupData.uuid}}</span>
  <span ng-if="!lookupData">-</span>
</div>

Plunker

答案 3 :(得分:0)

好的,在考虑了上述建议之后,我发现了我认为最简单的解决方案。

我们只需要运行

{{lookupData = myLookupFunc(vm)}}

之后我们可以引用'lookupData'变量。如果我们只是内联运行上面的代码,它也会评估并显示内联的结果(作为JSON字符串化文本),这不是我们想要的。所以我最终创建了一个专用指令,这是一个noop指令:

app.directive("ngAssign", function () {
    return {
        restrict: 'A'
    };
});

然后可以说:

<tr ng-repeat="vm in ..." ng-assign={{lookupData = myLookupFunc(vm)}}>
    <span ng-if="lookupData"> {{lookupData.label}}, {{lookupData.uuid}}
    <span ng-if="!lookupData">-</span>
</tr>

Full plunker:http://plnkr.co/edit/34DwCGR7Po8zg2mnCAtB?p=preview