I have a filter that changes filtered object. But when I'm using ng-style="item.gridSize"
My Filter: (The Algorithm for size Grid was taken (changed for my needs) from Here
angular.module("custom.modules.photoGrid", []).filter('photoSearch', [function () {
function getGrid(photos){
var output = [];
var HEIGHTS = [];
var COLUMN_WIDTH = 227;
var MARGIN = 6;
var DELTA = 20;
var size = window.innerWidth - 50;
var n_columns = Math.floor(size / (2 * (COLUMN_WIDTH + MARGIN)));
create_columns(n_columns);
var small_images = [];
function create_columns(n) {
HEIGHTS = [];
for (var i = 0; i < n; ++i) {
HEIGHTS.push(0);
}
}
function get_min_column() {
var min_height = Infinity;
var min_i = -1;
for (var i = 0; i < HEIGHTS.length; ++i) {
if (HEIGHTS[i] < min_height) {
min_height = HEIGHTS[i];
min_i = i;
}
}
return min_i;
}
function gridSize(i, is_big) {
var size = {
'margin-left': (MARGIN + (COLUMN_WIDTH + MARGIN) * i)+'px',
'margin-top': (HEIGHTS[Math.floor(i / 2)] * (COLUMN_WIDTH + MARGIN))+'px',
'width': is_big ? (COLUMN_WIDTH * 2 + MARGIN)+'px' : COLUMN_WIDTH+'px',
'height': is_big ? (COLUMN_WIDTH * 2 + MARGIN)+'px' : COLUMN_WIDTH+'px'
};
return size;
}
function createGrid(data){
if (data.length >= 2) {
for(var i = 0; i < data.length; i++){
var column = get_min_column();
if (Math.random() > 0.8) {
data[i]['gridSize'] = gridSize(column * 2, true);
HEIGHTS[column] += 2;
} else {
small_images.push(i);
if (small_images.length === 2) {
data[small_images[0]]['gridSize'] = gridSize(column * 2, false);
data[small_images[1]]['gridSize'] = gridSize(column * 2 + 1, false);
HEIGHTS[column] += 1;
small_images = [];
}
}
}
if (small_images.length) {
column = get_min_column();
data[(data.length-1)]['gridSize'] = gridSize(column * 2, false);
}
}
return data;
}
var grid = createGrid(photos);
return grid;
}
return function(photos, search) {
var filtered = [];
if(!!search){ /**@case1 if only search query is present**/
search = search.toLowerCase();
for(var i = 0; i < photos.length; i++){
if(photos[i].photo_name.toLowerCase().indexOf(search) !== -1){
filtered.push(photos[i]);
}
}
}else {
/**@case2 no query is present**/
filtered = photos;
}
filtered = getGrid(filtered);
return filtered;
}
}]);
HTML:
<input type="text" ng-model="input.value"> <span>{{ results.length }}</span> Photo Found
<div ng-repeat='photo in photos | photoSearch:input.value as results track by photo.id' class="photo-item" ng-style="photo.gridSize">
<img ng-src="/photos/{{photo.url}}">
</div>
一个小解释:
每次ng-model
input.value
更改过滤器都会被修改,并为过滤后的照片数组创建不同的网格。所有维度都写在gridSize
内,这会导致摘要循环。
到目前为止我尝试过的内容:我已将ng-repeat
移至指令中,但这样我就无法访问result.length
和input.value
。
我还尝试了bindonce
指令,但是像bo-style="photo.gridSize"
一样使用它并不会在用户搜索后更改网格(并且在逻辑上是正确的,因为只出价一次,但值已更改。
所以我的问题是如何在不在摘要循环中运行的情况下ng-repeat
分配新的grdiSize
属性。
更新: JSFiddle
工作小提琴: JSFiddle
答案 0 :(得分:1)
有几个问题。这不是一个ng-style
问题,而是在每个摘要周期中,您的照片计算不同的样式对象,导致另一个摘要周期运行。
我发现了一些问题:
NaN
和失败时导致大小给出margin-top
。为了解决这个问题,我在1列中添加了一个默认值。Math.random() > 0.8
在每次执行过滤器功能时都会给出不同的结果。在每个摘要周期中,由于Math.random()
给出了不同的结果,它正在强制另一个摘要循环(您正在更新gridSize对象 - 因为$watch
中的每个元素都有ng-repeat
它会检测到更改并强制一个消化周期),等等。那是控制台中的错误日志。我创建了这个有效的fiddle。主要变化是
在声明数组后为每张照片定义了固定的随机值
$scope.photos.forEach(function(onePhoto){
onePhoto.randomValue = Math.random();
});
然后在过滤器中,您将检查此值
if (data[i].randomValue > 0.8) {
}
并在创建列时设置至少1列
var n_columns = Math.max(1, Math.floor(size / (2 * (COLUMN_WIDTH + MARGIN))));
另外(但我相信这只发生在你的小提琴中),没有photo_name
来过滤,所以我使用id
代替。
您可能希望使用其他默认值修复NaN
问题,但至少现在您知道控制台错误的问题。
如果您想在每次执行搜索时更新randomValue,可以在$watch
上放置input.value
,移动迭代照片的代码并在函数中创建随机值,然后使用在该监视功能的回调中。因此,每当您在搜索中更新结果时,您的网格都会使用不同的随机值,而不会干扰摘要周期。
像this
var updateRandomValues = function() {
$scope.photos.forEach(function(onePhoto){
onePhoto.randomValue = Math.random();
});
};
updateRandomValues();
$scope.$watch('input.value', function(newVal, oldVal) {
if (newVal !== oldVal) {
updateRandomValues();
}
});
但是,如果你想获得不同的css样式只有当你得到不同的结果时(请记住,如果你输入和得到的结果一样,它会更新你的网格布局),你应该{{1}而是结果变量。像this
一样$watch