本文介绍了ng样式/动态照片网格上的角度摘要循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个过滤器,它可以更改过滤的对象.但是当我使用ng-style="item.gridSize"我的筛选器:(根据我的需要(针对我的需要,对尺寸网格算法进行了更改)来自在这里

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内部,这会导致摘要循环.

A small explanation:Every time ng-model input.value changed filter is runed and creates different grid for filtered array of photos. all dimensions are written inside gridSize and this cause digest loop.

到目前为止,我一直在尝试以下操作:我已将ng-repeat移至指令中,但是通过这种方式,我无法访问result.lengthinput.value.

What I've tried until now: I've moved my ng-repeat in directive, but this way I can't access result.length and input.value.

我也尝试过使用bindonce指令,但是像bo-style="photo.gridSize"这样使用它不会在用户搜索后更改网格(从逻辑上来说是正确的,因为只出价一次,但是值却被更改了.

I've also tried a bindonce directive but using it like bo-style="photo.gridSize" doesn't change the grid after user search(and is logically right because is bidden only once, but values changed.

所以我的问题是如何使ng-repeat分配新的grdiSize属性而不在摘要循环中运行.

So my question is how to make ng-repeat assign new grdiSize property without running in digest loop.

更新: JSFiddle

工作小提琴: JSFiddle

推荐答案

有两个问题.这并非完全是ng-style问题,但不是在每个摘要循环中,您的照片都在计算不同的样式对象,从而导致另一个摘要循环运行.

There were a couple of issues. It was not exactly a ng-style problem, but rather than in each digest cycle your photos were calculating different style objects, causing another digest cycle to run.

我发现了一些问题:

  • 逻辑错误是给0列,因此导致在计算margin-top并失败时,尺寸会给出NaN.为了解决这个问题,我在1列中添加了默认值.
  • 每次执行过滤器功能时,
  • 您的Math.random() > 0.8都会给出不同的结果.在每个摘要循环中,由于Math.random()给出的结果不同,因此它会强制另一个摘要循环(您正在更新gridSize对象-因为ng-repeat中每个元素都有一个$watch,它会检测到更改并强制执行一个摘要循环) , 等等.那是控制台中的错误日志.
  • Error in logic was giving 0 colums, thus causing size to give NaN when calculating margin-top and failing. To fix this, I added a default value from 1 column.
  • your Math.random() > 0.8 was giving different results in each time your filter function was executing. In each digest cycle, since Math.random() gives different results, it was forcing another digest loop (you were updating gridSize object - since there's a $watch for each element in the ng-repeat it detects the changes and forces one digest cycle), and so on. That was the error log in console.

我创建了这个有效的小提琴.主要变化是

I created this fiddle that works. The main changes are

在声明数组后为每张照片定义一个固定的随机值

defined a fixed random value for each photo, after declaring your array

$scope.photos.forEach(function(onePhoto){
    onePhoto.randomValue = Math.random();
  });

然后在过滤器中根据此值进行检查

then in the filter you would check against this value

if (data[i].randomValue > 0.8) {
}

并在创建列时设置至少1列

and set a minimum of 1 column when creating columns

var n_columns = Math.max(1, Math.floor(size / (2 * (COLUMN_WIDTH + MARGIN))));

(但我相信这只发生在您的小提琴中),没有要过滤的photo_name,所以我改用了id.

Also (but I believe this occured only in your fiddle), there was no photo_name to filter for, so I used id instead.

您可能想用其他默认值修复NaN问题,但至少现在您知道控制台错误的问题.

you might want to fix the NaN problem with other default value, but at least now you know the problems with the console error.

如果您想在每次执行搜索时都更新您的randomValue,则可以在input.value上放置一个$watch,将迭代照片并创建随机值的代码移入函数,然后在回调函数中使用手表功能.因此,每次更新搜索结果时,网格都会使用不同的随机值,而不会干扰摘要周期.类似于

If you wanted to update your randomValue everytime you executed the search, you could place a $watch over your input.value, move the code that iterates photos and creates random values into a function, and use that in the callback for that watch function. So everytime you update results in search, your grid uses different random values without causing interfering with digest cycle.Something like 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样式(请记住,如果您键入并获得与以前相同的结果,则无论如何都会更新网格布局),您应该$watch是结果变量.像

However, if you want to get different css style only when you get different results (keep in mind that if you type and get same results as before, it will update your grid layout anyway), what you should $watch is the results variable instead. Like this

$scope.$watch('results', function(newVal, oldVal) {
    if (newVal !== oldVal) {
        updateRandomValues();
    }
  });

这篇关于ng样式/动态照片网格上的角度摘要循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-22 18:42