Angular Digest Loop for Dynamic Photo Grid Styling

I have a special filter that alters the objects being filtered. However, when I apply ng-style="item.gridSize", it triggers my custom grid algorithm. This algorithm was adapted for my requirements from a source found at this link.

angular.module("custom.modules.photoGrid", []).filter('photoSearch', [function () {
    // Custom grid algorithm here
}]);

HTML:

<input type="text" ng-model="input.value"> <span>{{ results.length }}</span> Photos 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>

A brief explanation: Whenever ng-model input.value changes, the filter is triggered to create a new grid layout for the filtered photos array. The dimensions are specified within gridSize, which may lead to digest loop issues.

Attempts made so far: I attempted moving the ng-repeat into a directive, but this hindered accessing result.length and input.value.

Another experiment involved using the bindonce directive with bo-style="photo.gridSize". However, this didn't update the grid post-user search due to its one-time binding nature.

Hence, my question remains: How can I adjust ng-repeat to assign a new gridSize property without causing a digest loop?

UPDATE: See the JSFiddle here.

Working Fiddle: Check out the functional version on JSFiddle here.

Answer №1

There were a few issues that needed addressing. It wasn't specifically a problem with ng-style, but rather the fact that your photos were calculating different style objects in each digest cycle, triggering additional cycles.

Here are some of the problems I identified:

  • An error in logic resulted in 0 columns being generated, causing the size calculation to yield NaN for margin-top and failing. To resolve this, I set a default value of 1 column.
  • The usage of Math.random() > 0.8 produced varying results every time the filter function ran. As Math.random() generates different outcomes in each cycle, it led to consecutive digest loops triggered by updates to the gridSize object (due to individual $watch elements in the ng-repeat). This resulted in the error log displayed in the console.

I have prepared a working fiddle that addresses these issues. The primary modifications made include:

Assigning a consistent random value to each photo item after initializing the array

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

Utilizing this value within the filter condition

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

Ensuring a minimum of 1 column is established during column creation

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

In addition (though likely only relevant to your fiddle), there was no photo_name field to filter by, so I utilized id instead.

You may consider addressing the NaN issue with an alternative default value, but at least now the console errors are understood.

If you wish to update random values each time the search is performed, you can implement a $watch on the input.value, encapsulate the code for generating random values into a function, and call it within the watch callback. In this way, the grid will utilize different random values on each search without impacting the digest cycle. A sample implementation can be found here.

var updateRandomValues = function() {
    $scope.photos.forEach(function(onePhoto){
        onePhoto.randomValue = Math.random();
      });
  };
  updateRandomValues();
  $scope.$watch('input.value', function(newVal, oldVal) {
    if (newVal !== oldVal) {
        updateRandomValues();
    }
  });

Alternatively, if you aim to adjust the CSS styles only when obtaining different search results (as typing the same query will still update the layout), you should $watch the "results" variable instead. An example of this approach can be viewed here.

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 1: Handling Multiple Conditions and Exclusions Based on Other Conditions

I have currently added an additional span to accommodate one condition. <div ng-repeat="(key, resultLinks) in resultGroup.resultLinks"> <div ng-if="key < 4 || viewMore" ng-repeat="(subKey, linksWrap) in resultLinks.linksWrap"> & ...

Having trouble viewing the page of a new package you published on the NPM Website?

Today, I officially released an NPM package called jhp-serve. It can be easily installed using npm install or run with npx. You can even find it in the search results here: https://www.npmjs.com/search?q=jhp. However, when attempting to view its page by cl ...

Issue with element alignment using CSS increments

I'm confident that this code should be functioning properly, but for some reason it's not. I feel like there must be a small detail that I'm overlooking: Markup: <section id="content"></section> Styling: #content { positi ...

Expandable Grid Sections in React MUI

Is there a way to create a grid layout where items with showDefault: true are always displayed at the top, and then users can click an arrow button to expand the grid and also show the items with showDefault: false? Any suggestions on how to achieve this? ...

What are the steps for generating a diagram using Chart.js?

I'm attempting to use Chart.js to create a specific diagram. Current Challenges: The point on the x-axis should be centered within the categories. I would like the value to appear above the point. https://i.sstatic.net/FFFr1.png This is what my co ...

Dark opaque background image with Material-UI styling

I'm enclosing all the widgets within a CardMedia component, and adding an image. return ( <CardMedia image={bg} className={classes.bg}> <main className={classes.content}> <div className={classes.toolbar} /> <Grid contai ...

Create a JavaScript array containing all the elements from a MySQL table

I am attempting to store my mysql table data in a JavaScript array. My goal is to push each element of the table into the array so that it looks like this: array[0] = [question: information01, answer: information02...] array[1] = [question: information11, ...

Node.js seems to be having trouble with emitting events and catching them

I'm having trouble troubleshooting my code. // emitter.js var EventEmitter = require('events').EventEmitter; var util = require('util'); function Loadfun(param1, param2, db){ function __error(error, row){ if(error){ ...

How to retrieve cookie value from callback response in Angular?

There are two domains: Angular Application: samlapp.domain.com Node Application: samlapi.domain.com When Node calls the callback with the cookie, it redirects to the samlapp application (samlapp.domain.com/landing) Concern: How can I retrieve the cook ...

Tabs within the AutoComplete popup in Material-UI

Would it be feasible to showcase the corresponding data in the AutoComplete popover using Tabs? There could be potentially up to three categories of data that match the input value, and my preference would be to present them as tabs. Is there a way to in ...

Incorporating a delete button onto an image using JavaScript

I am currently developing a BlogApp and facing difficulty in attempting to include a button on an image. The image is being retrieved from the Django database in JavaScript (HTML). My goal is to have a clickable button overlaid on the image. views.py def ...

Troubleshooting Asynchronous Code in JavaScript

I was experimenting with creating a brute force poll voting script. $('#vote').click(function(e) { var votes = 0; var attempts = 0; var failures = 0; for(var i = 0; i < 500; i++){ ...

Is there a way to store JSON data in a constant variable using Node Fetch without encountering the error TypeError [ERR_INVALID_URL]: Invalid URL?

In my current NodeJS project, I am working on extracting data from a JSON file and then sending it to a constant variable in my app2.mjs. The goal is to organize this data into an array of objects and eventually save it into a database. However, when tryin ...

How to Apply CSS Styles to Input When it is in Focus Using Angular.js

Is there a way to achieve the following functionality: If a user clicks inside the "name" field - How can we set the CSS Class to XYZ on the corresponding DIV element? <div ng-class="???">Enter your Name here</div> <input type="text" ng-m ...

The nodes on a 2-dimensional grid overlap each other when the browser window is resized

In my project, I have set up a grid with 24 rows and 64 columns, totaling to 24x64 nodes. However, I am facing an issue where the nodes overlap when I open the console window. I am looking for a solution to automatically resize all nodes based on changes ...

Determine whether a component is linked to an event listener

If a <Form> component is called with a @cancel event listener attached to it, the cancel button that triggers this event should be visible. If no @cancel event is present, the cancel button should not be displayed. Is there a method to verify if a c ...

Exploring Checkbox Limiting with jQuery

Is there a more efficient approach to restrict the selection of checkboxes? I want the script to be adaptable depending on the applied class, which will always indicate the maximum allowed value (e.g., "limit_1" or "limit_2"). Currently, I'm creatin ...

Unravel the JSON structure

Here is the JSON response I received from an AJAX call: [{"id":null,"period":null,"until":null,"agent_id":"15","agent_zlecajacy_id":"15","offer_id":null,"status":"1","tytul":"Pobranie ksi\u0105g","tresc":"Pobranie ksi\u0105g","data_aktualizacji" ...

Blur function not performing as anticipated

I am attempting to achieve a blur effect on a dialog pop-up. Currently, I am using the primeng p-dialog component for this purpose. <p-panelMenu [model]="items" [style]="{'width':'300px'}"></p-panelMenu> <p-dialog head ...

What causes the border to trigger the appearance of a scrollbar due to an overflow?

The first image display a scrollbar, while the second one does not. It all comes down to the .tabulator CSS class and specifically the border property. How come only a 1px border impacts the scroll feature instead of affecting the entire content? https: ...