2014-02-27 32 views
5

我正在編寫一個自定義的Angular過濾器,它隨機大寫傳遞給它的輸入。Angular:過濾器中的無限摘要循環

下面的代碼:

angular.module('textFilters', []).filter('goBananas', function() { 
    return function(input) { 

    var str = input; 
    var strlen = str.length; 

    while(strlen--) if(Math.round(Math.random())) { 
     str = str.substr(0,strlen) + str.charAt(strlen).toUpperCase() + str.substr(strlen+1); 
    } 

    return str; 
    }; 
}); 

我把它在我看來,像這樣:

<a class='menu_button_news menu_button' ng-href='#/news'> 
     {{"News" | goBananas}} 
    </a> 

它的工作原理,但在我的控制檯我看到一個rootScope:infdig(infinite digest)環。

我很難理解爲什麼會發生這種情況,我可以做些什麼來解決它。如果我理解正確,這是由於這個函數調用了超過5個摘要動作。但輸入只被過濾器調用一次,對吧?

任何幫助表示讚賞。

+0

你有沒有檢查過我的答案?它根本沒有幫助,我想刪除它。但是,我覺得這是非常好的信息,我們應該「記憶」這樣的過濾器,以保持數據轉換與修復無限摘要錯誤的邏輯分離。代碼非常乾淨。我真的很感激你的反饋。請注意我的解決方案不涉及更改您的代碼,這很好。 – m59

回答

4

由於摘要將繼續運行,直到達到模型的一致狀態或將會運行10次迭代,您需要使用自己的算法來生成僞隨機數,這些僞隨機數將返回相同字符串的相同數字以避免無限的摘要循環。如果算法將使用字符值,字符位置和一些可配置的種子來生成數字,那將會很好。避免在這種算法中使用日期/時間參數。這裏是一個可能的解決方案之一:

HTML

<h1>{{ 'Hello Plunker!' | goBananas:17 }}</h1> 

的JavaScript

angular.module('textFilters', []). 
    filter('goBananas', function() { 
    return function(input, seed) { 
     seed = seed || 1; 
     (input = input.split('')).forEach(function(c, i, arr) { 
     arr[i] = c[(c.charCodeAt(0) + i + Math.round(seed/3)) % 2 ? 'toUpperCase' : 'toLowerCase'](); 
     }); 
     return input.join(''); 
    } 
    }); 

你可以seed參數發揮改了一下的算法。例如,它可能是ngRepeat

Plunker的$indexhttp://plnkr.co/edit/oBSGQjVZjhaIMWNrPXRh?p=preview

+0

太好了,這件作品很有魅力。難道不可能定義$ scope.random = Math.random()* 10;在控制器中,並在視圖中使用過濾器{{'Hey there'| goBananas:random}}? – Squrler

+0

@Squrler是的,只要看看這個plunk http://plnkr.co/edit/ee0mRPMhfFsDZMzZv9iE?p=preview – Vadim

+0

真棒,那就是訣竅。謝謝@Vadim – Squrler

0

的選擇,如果你想要的行爲是真正隨機的,是通過創建一個種子鏈接過程中做處理隨機性只有一次,然後在實際的過濾器中使用seeded random number generator

angular.module('textFilters', []).filter('goBananas', function() { 
    var seed = Math.random() 
    var rnd = function() { 
    var x = Math.sin(seed++) * 10000; 
    return x - Math.floor(x); 
    } 

    return function(input) { 

    var str = input; 
    var strlen = str.length; 

    while(strlen--) if(Math.round(rnd())) { 
     str = str.substr(0,strlen) + str.charAt(strlen).toUpperCase() + str.substr(strlen+1); 
    } 

    return str; 
    }; 
}); 
5

的問題是,該過濾器將在每次調用時產生一個新的結果和角度將其稱之爲一次以上,以確保該值進行改變,這它永遠不會。例如,如果對單詞'stuff'使用uppercase過濾器,則結果爲'STUFF'。當Angular再次調用過濾器時,結果是'STUFF',所以摘要循環可以結束。例如,使用返回Math.random()的過濾器進行對比。

技術方案是在控制器中應用轉換,而不是在視圖中。不過,我更喜歡使用過濾器來轉換視圖中的數據,即使過濾器應用了像您的那樣不穩定的轉換(每次返回不同)。

在大多數情況下,可以通過記憶過濾器功能來修復不穩定的過濾器。下劃線和腰部有一個memoize功能。你只會圍繞這樣的過濾功能:

.filter('myFilter', function() { 
    return _memoize(function(input) { 
    // your filter logic 
    return result; 
    }); 
}); 
+0

可以請直接我這裏有什麼問題 - http://stackoverflow.com/questions/30435382/aborting-watchers-fired-in-the-last-5-iterations – codebased

+1

@codebased我在這裏的答案解釋了這個問題你有最簡單的解決方案。將你的過濾器包裹在記憶功能中。 – m59