So, in my angular project Im using fxFlex in many places. I imported fxFlex in the module but in one place it is not working and I dont know why. This is my template code:
<div fxLayout="row" *ngIf="elementDescription$ | async as root">
<div fxFlex="20%" *ngFor="let page of root.elements; index as i" >
<app-card [elementDescription]="page" [index]="i" ></app-card>
</div>
</div>
Am I missing here something? I am using NG Bootstrap in my project if thats relevant
Related
I would like to use DragDropModule for my angular application so I can move panels that are stored inside templates (for practical purposes as well as for recursive plotting of child elements).
The problem that I have is that cdkDrag can't find the correct cdkDropList to drop into if cdkDrag is hidden within a template and is not directly nested under the HTML element. Example:
<div
cdkDropList
[cdkDropListData]="expanded.activities"
(cdkDropListDropped)="dropActivity($event)">
<div *ngFor="let activity of expanded.activities">
<ng-container [ngTemplateOutlet]="orangeProgramActivity"></ng-container>
</div>
</div>
<ng-template #orangeProgramActivity>
<div cdkDrag>This is just a test</div>
</ng-template>
With this code example, the orangeProgramActivity can be dragged anywhere but doesn't drop into the correct dropList as cdkDrag keyword can't find any droplist within its own template.
In the second example, everything works correctly and the item gets dropped into correct dropList:
<div
cdkDropList
[cdkDropListData]="expanded.activities"
(cdkDropListDropped)="dropActivity($event)">
<div *ngFor="let activity of expanded.activities">
<div cdkDrag>This is just a test</div>
</div>
</div>
I would like to achieve the same functionality as in the second example, but with the use of templates because I really need them for recursion. Unfortunately, I can't reveal the whole code as my employer wouldn't be happy with that.
All I need is some static reference for my cdkDrag that is inside a template, to point onto a correct element with dropList that is outside of the template.
These are the only solutions that I found on the internet and they don't seem to work for me:
Material 7 Drag and Drop ng-template incompatibility
CdkDragDrop and ngTemplateOutlet
This is my first question on Stack Overflow and I'm new to angular, so I'm sorry for any confusion in my post, and thanks for any help in advance!
This might not work for all use cases, but you could just write it like this:
<div
cdkDropList
[cdkDropListData]="expanded.activities"
(cdkDropListDropped)="dropActivity($event)">
<div *ngFor="let activity of expanded.activities" cdkDrag>
<ng-container [ngTemplateOutlet]="orangeProgramActivity"></ng-container>
</div>
</div>
<ng-template #orangeProgramActivity>
<div>This is just a test</div>
</ng-template>
I was lucky that I only need to reorder elements inside an array in which they are and I don't need to transfer them into other containers. So for my "root" activities, I used your simple solution to wrap it all in a draggable element.
<div cdkDropList [cdkDropListData]="expanded.activities" (cdkDropListDropped)="dropActivity($event)">
<!-- For every object in array make a container with template and an icon that will serve as a handle -->
<div *ngFor="let activity of expanded.activities">
<div cdkDrag>
<div cdkDragHandle>
<!-- Handle icon from FontAwesome -->
<i class="fas fa-grip-vertical"></i>
</div>
<!-- Container with a template that we need -->
<ng-container [ngTemplateOutlet]="orangeProgramActivity" [ngTemplateOutletContext]="{act: activity}"></ng-container>
</div>
<!-- Recursive template for children -->
<ng-container [ngTemplateOutlet]="childActivitiesRecursion" [ngTemplateOutletContext]="{act: activity}"></ng-container>
</div>
And for my recursion, I created a droplist inside a template that serves only for reordering these children activities.
(I had problems with pasting template so the ng-template tag is not terminated at the end of the code)
<ng-template let-act="act" #childActivitiesRecursion>
<!-- Droplist inside a template for reordering child activites -->
<div cdkDropList [cdkDropListData]="act.childActivities" (cdkDropListDropped)="dropActivity($event)">
<!-- Iterates through all child activities -->
<div *ngFor="let childActivity of act.childActivities">
<div cdkDrag>
<div cdkDragHandle>
<i class="fas fa-grip-vertical"></i>
</div>
<!-- Different template for child activities -->
<ng-container [ngTemplateOutlet]="blueProgramActivity" [ngTemplateOutletContext]="{act: childActivity}"></ng-container>
</div>
<!-- Recursion for even deeper child activites -->
<ng-container [ngTemplateOutlet]="childActivitiesRecursion" [ngTemplateOutletContext]="{act: childActivity}"></ng-container>
</div>
</div>
I will accept Richard's answer as a solution because if you are able to solve it like this, it's definitely the most elegant solution you can do. But there would be still an issue if you needed to transfer items into different containers after using templates for recursion!
I'm trying to close and open a new div in a ng-template element. When I try this my code breaks.
<div class="row">
<ng-template ngFor let-i="index" let-data [ngForOf]="dataArray">
<app-user-dashboard-gauge [gaugeData]="data" class="col"></app-user-dashboard-gauge>
<ng-template [ngIf]="i === 3">
</div>
<div class="row">
</ng-template>
</ng-template>
</div>
I'm trying to do this inside a ngFor to preserve my bootstrap rows. Does anyone know how to fix this or maybe another solution?
Edit: Ok I think I want that clear on what I wanted to happen. I update my code block and will try to explain it better. On the third iteration of my for loop I want the row div to be closed and a new one to open. And the rest of the <app-user-dashboard-gauge> to go in the second row div.
Okay I fixed it. It might not be the best or the nicest looking but i split the incomming data into two parts and made another for loop for the secend group of data.
<div style="background-color: #202020">
<div class="row">
<ng-template ngFor let-data [ngForOf]="dataArray1">
<app-user-dashboard-gauge [gaugeData]="data" class="col"></app-user-dashboard-gauge>
</ng-template>
</div>
<div class="row">
<ng-template ngFor let-data [ngForOf]="dataArray2">
<app-user-dashboard-gauge [gaugeData]="data" class="col"></app-user-dashboard-gauge>
</ng-template>
</div>
</div>
Im still open for feedback if someone knows a better solution but this fix will suffice for now.
<ng-container *ngIf="i !== 3">
<div class="row">
</div>
</ng-container>
In my project I'm using a mat-dialog to display a description of an object. The objects are generated through ngFor, like this:
<mat-card id="CARDBOX" *ngFor="let box of box">
<img class="logoy" src="{{box.image}}" height=35px>
{{box.button_name}}
<input type="image" id="info" title="Click for description" src="{{box.info}}" (click)="openDialog()" height=20px/>
</mat-card>
It's a basic card object that has an info icon that when clicked, opens the dialog, which looks like this:
<title mat-dialog-title></title>
<div mat-dialog-content *ngFor="let box of box">
{{box.description}}
</div>
<div mat-dialog-action>
<button mat-button (click)="onNoClick()">Close</button>
</div>
This works. However, it is displaying EVERY description in box, rather than just the corresponding one. I know this is because of the ngFor running through every item. Is there a way so that it will only display the one correct description, perhaps through use of some kind of conditional? I would ideally like to keep everything as abstracted as possible, I figured using some kind of conditional in the HTML would make the most sense but I'm not sure if that exists? Please let me know if you need more detail.
<div mat-dialog-content *ngFor="let box of box">
{{box.description}}
</div>
Your ngFor directive is looping through with an element whose name (and thus its reference if I'm not making a mistake here) is equal to its container.
Have you tried this?
<div mat-dialog-content *ngFor="let boxEl of box">
{{boxEl.description}}
</div>
Your code might not be able to differentiate a "box" (element) from a "box" iterable.
I develop a small angular material application. My objective is to obtain the following design for a card, that fit on every kind of media (desktop, mobile, tablette)
my "app.component.html" is the following
<mat-toolbar color="primary">
<div style="width:100%;" class="md-toolbar-tools" >
Liste des annonces
<span flex></span>
</div>
</mat-toolbar>
<div fxLayout="row">
<div fxFlex="20%"></div>
<div fxFlex="60%">
<mat-card *ngFor="let annonce of annonces; let i = index" style="border:red">
<mat-card-content style="border:blue">
<img src="./../assets/image/image{{i+1}}.jpg" alt="Avatar" style="position:absolute;top:0px;left:0px;width:40%;height:100%">
<div class="container" style="left: 45%; top:10px;">
<div style="left:70%;">{{annonce.dateConstruction | date:'dd MMMM yyyy'}}</div>
<div>
<span>{{annonce.type}}</span>
<span style="float:right">{{annonce.prix}}</span>
</div>
<h4>{{annonce.surface}}</h4>
<h4>{{annonce.adresse}}</h4>
<div style="left:45%;">
<p>{{annonce.description}}</p>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
<div fxFlex="20%"></div>
</div>
<router-outlet></router-outlet>
I am terrible in placing elements and text in html pages, and therefore in a material card. I obtain the following output in the browser
Furthermore when I shrink my browser, I can't see the element and text on the rigth of the image placed correctly. I tried to reproduce the same on stackblitz (https://stackblitz.com/edit/angular-pexq15?file=package.json), but I got trouble with the angular material tags that are not taken in account.
So could you help me and tell me what is going wrong and comment the correct code so I improve myself in html/css. Thanks a lot
You should try leveraging the #angular/flex-layout Library for this. Additionally, you should consider moving your styles to your CSS File, since this will make your HTML File a lot cleaner and the styles more reusable. In your stackblitz you missed to include the styles for #angular/material in your SCSS File and you did not import the #angular/flex-layout module, which is why your stylings were messed up.
I tried to fix your example on Stackblitz. To get the desired spacings for your text, simply add paddings or margins to the left of those elements. Also beware of your image: You have to add a fitting height property, or it will become cropped/stretched.
I used to be able to create a grid with line break in angular flex-layout using fxLayoutWrap.
Seems that it doesn't work anymore. Whatever number I put in fxFlex, the div doesn't go to the next line. I saw the example Angular flex-layout with ngFor, but I can't make it work on my side.
<div fxLayout="row" fxLayout.xs="column" fxLayoutWrap="wrap">
<div
fxFlex.gt-xs="50%"
[fxFlex.gt-md]="regularDistribution"
*ngFor="let country of countries">{{ country }}
</div>
</div>
I downgraded "#angular/flex-layout": "2.0.0-beta.10-4905443",
in package.json and it's working again...