2014-09-03 60 views
0

我有以下角度的代码:重新评估从NG-重复内控制器的功能

<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中完成此操作的正确方法是什么?

回答

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> 
+0

正如我上面提到我所做的尝试,但该函数只会在初始渲染时调用一次,并且只会在'vm'本身发生变化时才会被评估,但查找函数可以根据其他外部条件更改其结果。 – Ivan 2014-09-03 10:21:36

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> 

and def在控制器上检测VM值并返回文本的功能getVmText。我相信这是最好的方法。

+0

第二种情况适用于简单情况,在我的情况下实际的内容更加完善,包括调用自定义指令等(此处未显示)。所以我想我会尝试你的第一个方法。看起来很骇人,但可能没有更好的办法。如果只有像ng-assign这样的东西,它会像ng-init一样行事,但每次都会评估。不知道,也许编写这样的指令会很简单 – Ivan 2014-09-03 10:42:24

0

使用数据模型并在必要时进行更新(即使发生“外部事件”时也是如此)。这样,您不必再为“重新评估控制器功能”而烦恼,它只是纯粹的角度数据绑定。

例子:

$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

+0

因此在你的例子中有更新数据的外部异步进程。但是,如何匹配原始情况,每次评估都必须发生,然后html被呈现? – Ivan 2014-09-03 11:02:22

+0

@Ivan每次呈现HTML时都不想运行'myLookupFunc(vm)',是吗?如果是这种情况,那么我们需要知道'myLookupFunc'正在做什么来优化它。 – bmleite 2014-09-03 12:40:55

+0

是的,是这样。查找功能必须以有效的方式完成。在我的情况下,这是内存查找结合两个数组 – Ivan 2014-09-03 13:52:53

0

确定,考虑了上述建议后,我发现了什么,我认为是最简单的解。

我们只需要运行

{{lookupData = myLookupFunc(vm)}} 

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

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> 

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

+0

这样你每次UI渲染时都会评估'myLookupFunc(vm)',这是一种不好的做法。它会减慢你的应用程序。不要这样... – bmleite 2014-09-03 13:17:10

+0

但是,这是目标,每次渲染UI时评估一次,而不是原始示例的4倍。当然查找函数必须高效 – Ivan 2014-09-03 13:51:39

+0

此函数不允许返回非基元对象的数组。如果确实如此,则会遇到一个众所周知的'10 $ digest()迭代。中止!”问题。 – Ivan 2014-09-03 18:27:18