When the *ngFor directive disrupts the CSS Grid Layout, resulting in all items being displayed in a single column

I am a beginner in the world of programming and web development. Currently, I am working on building my own personal website.

My goal is to arrange boxes in a grid with 4 columns, similar to the layout you can find at this link:

Each box represents an object, and I would like to display some data within the box while showing additional details in a popup dialog upon clicking the box.

I have been experimenting with CSS grid layouts, which are gaining popularity nowadays (I highly recommend watching this video: https://www.youtube.com/watch?v=7kVeCqQCxlk).

I have managed to achieve the desired layout by hardcoding a set of div elements inside a wrapper div for each box. However, when trying to use *ngFor on the wrapper containing an array of data and passing the data from each iteration to an inner div element, the grid layout breaks and all items appear in a single column.

Manually inputting the data using multiple div elements (item2) works as intended:

.wrapper {
            margin-left: 1em;
            margin-right: 1em;
            display: grid;
            grid-template-rows: auto;
            grid-template-columns: repeat(4, 1fr);
            grid-row-gap: 1em;
            grid-column-gap: 1em;
        }
<div class="wrapper">

            <div class="item2" style="background-color: deepskyblue;">
                <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
                <p>more text here.</p>
            </div>

            <div class="item2" style="background-color: deepskyblue;">
                <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
                <p>more text here.</p>
            </div>

            <div class="item2" style="background-color: deepskyblue;">
                <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
                <p>more text here.</p>
            </div>

            <div class="item2" style="background-color: deepskyblue;">
                <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
                <p>more text here.</p>
            </div>

            <div class="item2" style="background-color: deepskyblue;">
                <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
                <p>more text here.</p>
            </div>
            
        </div>

However, when using *ngFor... it loops through the "stickyNotes" array's length but aligns the boxes underneath each other instead of side by side in rows.

<div class="wrapper" *ngFor="let s of stickyNotes; let i = index" >
            <div class="item2" style="background-color: deepskyblue;">
                <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
                <p>more text here.</p>
                <p>{{s.title}}</p>
            </div>
        </div>

One workaround I tried was having this div element repeated 4 times by incrementing i with *ngIf (i+1, i+2, etc.). The issue is that at the start of a new row, the grid-row-gap defined in CSS is not applied.

<div class="item2" style="background-color: deepskyblue;" *ngIf="i < stickyNotes.length && i%4 === 0">
              <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
              <p>more text here.</p>
              <p>{{stickyNotes[i].title}}</p>
        </div>

        <div class="item2" style="background-color: deepskyblue;" *ngIf="i+1 < stickyNotes.length && i%4 === 0">
              <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test" >
              <p>more text here.</p>
              <p>{{stickyNotes[i+1].title}}</p>
        </div>

        <!--Repeat two more times until i+3-->

I am exploring the possibility of creating a custom iterable directive without compromising the grid setup or duplicating the item2 class multiple times.

I have also experimented with Bootstrap's row and col attributes, but the responsiveness did not match up to the neatness of the grid layout with 4 columns.

Any assistance or pointers in the right direction would be greatly appreciated!

Answer №1

An easy way to repeat an element is by using *ngFor. Just place it on div.item2, like this:

<div class="wrapper">
    <div class="item2" *ngFor="let s of stickyNotes; let i = index" style="background-color: deepskyblue;">
        <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test">
        <p>Adding more text here.</p>
        <p>{{s.title}}</p>
   </div>
</div>

Vega's solution works as well, but you can skip using <ng-container>. It's not necessary unless you're adding another structural directive to div.item2. The asterisk in *ngFor is just shorthand and can be expanded to something similar:

<div class="wrapper">
  <ng-template ngFor let-s [ngForOf]="stickyNotes" let-i="index">
    <div class="item2" style="background-color: deepskyblue;">
      <img class="img-responsive img-rounded" src="assets/Logo/square_filler.png" alt="pic-test">
      <p>Adding more text here.</p>
      <p>{{s.title}}</p>
    </div>
  </ng-template>
</div>

The rule of allowing only one structural directive per element is explained here:

Sometimes, you may want to repeat a block of HTML based on a condition. Attempting to use both *ngFor and *ngIf on the same element won't work in Angular. Only one structural directive is allowed on each element.

This limitation exists for simplicity. When multiple structural directives claim the same host element, it raises questions about precedence and behavior. Prohibiting this scenario simplifies directive implementation.

To handle multiple conditions, place the *ngIf on a container elements wrapping the *ngFor content. You can use an ng-container to minimize impact on your HTML structure.

Answer №2

Give this code a shot:

<div class="container">
  <ng-container *ngFor="let item of items; let i = index">
    <div class="box2" style="background-color: skyblue;">
      <img class="image-responsive image-rounded" src="assets/images/sample.jpg" alt="sample-image">
      <p>Additional text goes here.</p>
      <p>{{item.name}}</p>
    </div>
  </ng-container>
</div>

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

PHP is causing disruptions to HTML

Every time PHP code is present in my file, the page appears blank and upon checking the source code, there are no tags visible on the page. However, once I remove the PHP code, the form displays correctly without any issues. <?php $title = $_POST[&apos ...

Incorporating jQuery to Load Content into a DIV while preserving the original JavaScript

I am attempting to implement the following <script> $(document).ready( function() { var data = 'testing' $("#about").on("click", function() { $("#main-content").load("/about.html"); ...

Issue with toggling JS checkboxes selection

Seeking assistance in expanding my knowledge of Javascript. I have a form with checkboxes and a JavaScript function that allows toggling between selecting and deselecting all the boxes. Everything is functioning as intended so far. The challenge arises f ...

Ways to activate a function onInit in Angular version 9

Currently, I have a function that is activated by clicking a button: export class ExhibitorDetailsComponent implements OnInit { @ViewChild(MapInfoWindow, { static: false }) infoWindow: MapInfoWindow openInfo(marker: MapMarker, content) { this.in ...

How to emphasize a portion of an expression in AngularJS using bold formatting

I have a specific goal in mind: to emphasize part of an angular expression by making it bold. To achieve this, I am working with an object obj which needs to be converted into a string str. obj = $scope.gridOptions1.api.getFilterModel(); for (var pr ...

Does every controller page need to verify the Login Function?

In my PHP pages, I have implemented the MVC Pattern by creating a controller page for each view page to interact with the Model page. However, I have only checked user login at the top of every view page and not in the controller page. This leaves a potent ...

Tips for positioning bootstrap dropdowns side by side in a row

I'm having trouble aligning my li items in a Bootstrap dropdown next to each other. I've tried everything but nothing seems to work. Here's my code: <nav class="navbar navbar-expand-lg navbar-light bg-light"> < ...

Clicking on the initial link will in turn prompt clicks on the subsequent links

Can you please provide instructions on how to correctly simulate a click on the remaining links if a click is made on the first link? jQuery('a.one_num').click(function() { jQuery('a.two_num').click(); jQuery('a.three_num&ap ...

How can I incorporate a custom icon into the <i> tag in HTML like Bootstrap does with its icons?

When working with Bootstrap, you can easily add an icon using the following syntax: <i class="bi bi-arrow-right-square-fill fs-1"></i> One great feature is that you can adjust the size of the icon by simply adding the fs-1 class. If ...

Is it possible to modify the value on the src img tag prior to scraping the data

Hey everyone, check out this piece of code I have: foreach ($image as $snimka){ $url = $snimka->src; $ch = curl_init($snimka->src); $fp = fopen('images/' . basename($url), 'wb'); curl_setopt($ch, CURLOPT_FILE, $fp ...

Are there any solutions to refresh a page by clicking a button in next.js?

I am currently learning how to work with next.js and I'm facing an issue where I need to reload my page to make a new API request. As a beginner, I'm not sure how to achieve this. I've tried a few methods but none of them seem to work. Below ...

Retrieve the value of the textarea only if it exceeds 15 characters

Could you please explain why in this example: <div id="comment-form"> <h3>Comment on this story:</h3> <form method="post" id="story-comment-form" action="#"> <textarea name="comment" id="story-comment-text"></textarea& ...

Using Angular to convert JSON data to PDF format and send it to the printer

Currently, I am retrieving JSON data from an API and now need to convert this data into a PDF format for printing. I am encountering an issue where the CSS styling for page breaks is not rendering properly within my Angular component. When I test the same ...

I'm encountering an issue with my CSS image slider as it does not seem to be functioning properly on Google Chrome, yet

CSS: @-moz-keyframes slidy { 0% { left: 0%; } 20% { left: 0%; } 25% { left: -100%; } 45% { left: -100%; } 50% { left: -200%; } 70% { left: -200%; } 75% { left: -300%; } 90% { left: -300%; } 95% { left: -400%; } 10 ...

JavaScript code that moves the active link to the top of the navigation when the window width is less than or equal to 800px

I'm working on a responsive navigation that is fixed at the top and switches from horizontal to vertical when the screen size is less than or equal to 800 pixels wide. However, I'm facing an issue with moving the active link to the top of the na ...

How to Filter, Sort, and Display Distinct Records in an HTML Table with jQuery, JavaScript, and

In the HTML page, there will be a total of 6 tabs labeled A, B, C, D, E, and F along with 2 dropdowns. The expected behavior is as follows: The user will choose a value from the 2 dropdown menus. Based on the selected value, filtering should be applied to ...

Tips for resolving an Angular 504 Error Response originating from the backend layer

I am currently facing an issue with my setup where I have an Angular application running on localhost (http) and a Spring Boot application running on localhost (https). Despite configuring the proxy in Angular to access the Spring Boot APIs, I keep receivi ...

Different ways to automatically trigger a function in JavaScript

There are various ways to trigger a function automatically in javascript when a page loads. I am interested in knowing which method is considered the most effective and reliable. If you have a unique approach that differs from others, please share it here ...

The z-index overlapping problem in webkit browsers is a result of Angular 7 animations

I have implemented staggered animations in my Angular 7 application to bring elements to life upon page load. However, I am facing a strange z-index problem with one of my components. Here is the animation code: @Component({ selector: 'track-page& ...

What to do when IE6/IE7 margins disappear after moving a relatively positioned floated div using jQuery's .hover()?

Sharing my code with you: http://jsbin.com/uhera3/edit Encountered an issue where the relatively positioned floated divs move to the left in IE7 when using jQuery's .hover() function. Any insights on how to resolve this problem? ...