2014-09-03 77 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