Creating boxes in Angular via *ngFor - html

I'm new to Angular, Bootstrap and front-end programming.
I'd like to create several boxes.
After clicking on the box, detailed view of it should display above all boxes section.
This is what I'm trying to create:
and then after clicking on box number 1:
But now it looks like this:
I'm creating these boxes via Angular *ngFor loop like this:
<div class="container text-center" id="cryptocontainer">
<div class="row" *ngIf="coins">
<div *ngFor="let coin of objectKeys(coins); let i = index" id="currencybox" class="col-md-2" (click)="coinDetails(coin,i)">
<img id="image" [src]="getImage(coin)" class="img-responsive">
<div class="cryptoname">{{ coin }}</div>
<div class="cryptoprice">{{ coins[coin].USD | currency:'USD':true}}</div>
<div class="details" *ngIf="detailToggle[i]" no-lines>
<div class="row">
<div class="col">
<div class="label">CHANGE(30 dni)</div>
<canvas id="canvas{{i}}">{{ chart[i] }}</canvas>
</div>
</div>
<div class="row" id="details">
<div class="col-sm">
<div class="label">MARKET CAP</div>
<div class="answer">{{details.MKTCAP}}</div>
</div>
<div class="col-sm">
<div class="label">CHANGE(24h)</div>
<div class="answer">{{ details.CHANGE24HOUR }} ({{ details.CHANGEPCT24HOUR }}%)</div>
</div>
<div class="col-sm">
<div class="label">MAX (24h)</div>
<div class="answer">{{ details.HIGH24HOUR }}</div>
</div>
</div>
</div>
</div>
</div>
</div>

It's difficult to answer specifically without seeing your component code, but what you are probably missing, conceptually, is an understanding of how to break a UI like this into components and then pass data between those components in the "Angular" way. There are several ways to attack this. Ideally, I think you would move the details div to a separate component that has an input that receives the details, then create a separate component for the clickable divs that have an output that fires a custom event when clicked. These would both be instantiated in the template of a parent component, which would hold the current state of the clicked detail.
So, when you click a clickable component, it passes its details data back up to the parent, where it's set on the details property. Since the input on the display/canvas component is bound to that property, angular change detection will handle updating that component for you.
Here is a stackblitz with a simplified example of the communication pattern I am describing. You could also do something like create a shared service that you inject into both and then update that when a component is clicked.
https://angular-azmcxt.stackblitz.io
Stackblitz Editor Link

Related

Angular dynamically insert HTML that contains cdkDropListGroup, cdkDropList, and cdkDrag so that the cdkDrag items are draggable

I need to insert HTML that is created by the user of the application.
The HTML has several "sections" where content can be dragged into those "sections".
This is an example of the HTML that the user can create:
<div cdkDropListGroup>
<div cdkDropList>
<div cdkDrag>
item #1
</div>
<div cdkDrag>
item #2
</div>
<div cdkDrag>
item #3
</div>
</div>
</div>
I have attempted to do this using a Directive, ViewChild, Injectable, but nothing seems to be getting close to solving the problem. Is this even possible in Angular? Could someone direct me towards a method that should work?

Using a conditional in HTML/Typescript?

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.

How to paginate with NG-ZORRO in Angular

I want to use NG-ZORRO pagination in the Html page, it's working but fine but how do I link content with the pagination?
This is my Html code
<div class="row card-group-row">
<div class="col-md-6 col-lg-4 col-xl-3" *ngFor="let course of draftCourses"> //I want to paginate this data
<div class="card-blog">
<a href="#">
<img src="../assets/images/image.jpg" alt="" class="img-blog" />
</a>
<div class="card-blog-wrap">
<a href="#">
<h4 class="title-blog">{{course.course_title}}</h4>
</a>
</div>
</div>
</div>
<nz-pagination [nzPageIndex]="1" [nzTotal]="500" [nzPageSize]="2" id="demo"> </nz-pagination>
</div>
I am getting pagination in HTML but it's not linked with the content. I have used ngx-pagination before but I want to use nz-pagination in my code, so can someone help me how to do it.
This is the official link for NG-ZORRO Click here for link
Thanks in advance.
You need to implement event which will trigger on page index change.
For binding use (nzPageIndexChange):
<nz-pagination [nzPageIndex]="1" [nzTotal]="500" [nzPageSize]="2" (nzPageIndexChange)="onPageIndexChange($event)" id="demo"></nz-pagination>
Then in your component you can implement like below:
export class YourAngularComponent{
onPageIndexChange($event) {
//do something here to go to next page
}
.
.
}

Create component template to use it multiple times - Angular

This question might sound dumb, but I'll try it anyways:
Is it possible to use a component multiple times, but with different content? Something like a template.
To be exact, I want to write the component only once, but then use it in different places with different content - e.g. (I don't know whether that makes any sense and if so, how to realize it) by getting some text from an allocated model to fill a div, so that I can solely add a further model instead of editing the component itself?
Make use of the <ng-content>. Illustration:
app.component.html
<my-component>
<p>I'm getting projected into a component from outside because of ng-content</p>
</my-component>
my.component.html
<p>Data from my own component</p>
<ng-content></ng-content>
<p>Data from my own component</p>
By use of the <ng-content> you can project data from outside to within your component. You can make use of this in multiple ways, without changing the original component.
One way you can pass data to a component using input.
<my-component [text]="myText"></my-component>
And then in the component you can get the text using:
#Input() text: Person;
And display it in your template
You can use ng-content for this. Please find the below pseudo code
<!-- card.component.html -->
<div class="card">
<div class="card-header">
{{ header }}
</div>
<!-- add the select attribute to ng-content -->
<ng-content select="[card-body]"></ng-content>
<div class="card-footer">
{{ footer }}
</div>
</div>
<!-- app.component.html -->
<h1>APP COMPONENT</h1>
<card header="my header" footer="my footer">
<div class="card-block" card-body><!-- We add the card-body attribute here -->
<h4 class="card-title">You can put any content here</h4>
<p class="card-text">For example this line of text and</p>
This button
</div>
<card>

Using bootstrap grid to display items from api call with ngFor

I do an api call to get data from The Movie Database.
I then want to display the data using the bootstrap grid system.
This is what it currently looks like using Angular Material Grid:
<mat-grid-list cols="5" rowHeight="2:3" gutterSize="10px">
<div *ngFor="let movie of movies.results">
<mat-grid-tile>
<mat-card>
<div
class="thumbnail"
[style.background-image]="getSafeStyle(movie.poster_path)"
>
-- id: {{ movie.id }} -- name: {{ movie.title }}
</div>
</mat-card>
</mat-grid-tile>
</div>
</mat-grid-list>
the problem starts when I change to mobile view.
Angular material's grid system doesn't resize the elements like Bootstrap would.
I am trying to change it to bootstrap but I do not know how assign column sizes and rows to elements because the results being returned can always change.
So basically what I'm trying to achieve is something like this but inside an ngFor
<div class="row">
<div class="col-md-4">
API RESULT
</div>
<div class="col-md-4">
API RESULT
</div>
<div class="col-md-4">
API RESULT
</div>
</div>
and if there are too many values returned to fit in one row, a whole new row is created with the same amount of columns.
Does anybody know how to achieve this?
Thanks in advance for taking the time to read and trying to help :)
Something like
<div class="row">
<div *ngFor="let movie of movies.results" class="col-xl-2 col-lg-3 col-md-4 col-sm-12">
<!-- contents here -->
Bootstrap classes for the columns arbitrary, pick what looks good dependent on the resolution.