Delete row from DIV table when button clicked - html

I have the following divTable:
<div class="divTable">
<div class="divTableBody">
<div class="divTableRow">
<div class="divTableCell">TagName</div>
<div class="divTableCell">Higher/Lower</div>
<div class="divTableCell">Threshold</div>
<div class="divTableCell">Delete Alert?</div>
</div>
<div class="divTableRow" *ngFor="let com of currentAlerts">
<div class="divTableCell">{{com.tagname}}</div>
<div class="divTableCell">{{com.symbol == 1 ? 'Higher than' : 'Lower than'}}</div>
<div class="divTableCell">{{com.threshold}}</div>
<div class="divTableCell">
<button mat-stroked-button color="primary" (click)="submit(com.ID)">
Delete
</button>
</div>
</div>
</div>
As you can see this table loops through the array currentAlerts and creates a row for each item found.
The array is popuplated within ngOnInit() by connecting to a web API.
this.alerts.getCurrentAlerts(this.loginEmail)
.subscribe
((data: CurrentAlerts[]) => {this.currentAlerts = data;
console.log(this.currentAlerts.length)
if(!this.currentAlerts || !this.currentAlerts.length){
this.alertsTitleMessage = "You have no alerts configured."
}else{
this.alertsTitleMessage = "Here are the Alerts you have set up "
}}
);
When the Delete button is clicked the a delete request is sent to the database.
submit(ID){
let isDeleted = null;
this.alerts.deleteCurrentAlert(ID).subscribe(result => isDeleted = result);
this.manageCurrentAlerts();
}
All the above works as expected and the data is deleted from the database.
Question
How do I get the table to remove the deleted row? I have read answers that state to delete the row from the arra using splice but I couldnt get that working.

Add index in ngFor, *ngFor="let com of currentAlerts;let i = index"
In delete button, pass index i.e i instead of com.ID
Use splice in TS function, this.currentAlerts.splice(index,1)
Try like this:
<div class="divTableRow" *ngFor="let com of currentAlerts;let i = index">
...
<div class="divTableCell">
<button mat-stroked-button color="primary" (click)="submit(i)">Delete</button>
</div>
</div>
TS
submit(index){
this.currentAlerts.splice(index,1)
...
}

After deletion from database delete it from array.
submit(ID){
let isDeleted = null;
this.alerts.deleteCurrentAlert(ID).subscribe(result => isDeleted = result);
this.manageCurrentAlerts();
for(var i = 0; i< this.currentAlerts.length ; i++) {
if(this.currentAlerts[i].ID === ID) {
this.currentAlerts.splice(i, 1);
}
}
}

In your response from the server you need to delete the item from the array so in your method:
this.alerts.deleteCurrentAlert(ID).subscribe(result => isDeleted = result);
you should apply the filter method. Splice could work too but Filter has better performance.
Your method should look like this :
this.alerts.deleteCurrentAlert(ID).subscribe(result => {
this.currentAlerts = this.currentAlerts.filter(item => item.ID != ID);
isDeleted = result;
});

Related

Array of calendars with ViewChildren?

I need to create a dynamic full-calendar array.
The idea is that the user can select one of "n" diaries, relating to different operators, which are shown to him at the same time.
I'm using Angular 9.
Of course... it doesn't seem to work...
My .ts file has this declaration...
#ViewChildren(FullCalendarComponent) fullCalendars: FullCalendarComponent[];
public calendarOptions: CalendarOptions = null;
...and I use the component in this way...
render() {
if (this.fullCalendars && this.fullCalendars.length > 0) {
this.fullCalendars.forEach(fc => fc.getApi().render());
}
}
... and this is the HTML part ...
<div class="card" *ngFor="let ag of agendas; let i = index">
<div class="card-header">
<b>{{ ag.description }}</b>
</div>
<div class="card-body">
<full-calendar #fullCalendars [options]="calendarOptions"> </full-calendar>
</div>
</div>
Is this correct? I'm trying to understand why I'm getting this error...
Cannot read properties of undefined (reading '0')
...but first I need to know if the above code is ok.
Thank you so much!

Issue with mapping an array and pushing object into another array based upon a condition Angular

I am trying to set up a cashier screen.. and basically I need an addToCart function.. pretty simple huh?!
am facing some weird logical error tho.. what I do is on click of an item, I capture it and pass it as a parameter to a function which in turn maps my Bill array to check whether or not the item already exists there.. and if it does it just increases the quantity by one, otherwise, it pushes the item into the array..
It all works well until I delete an item and re-add it into the array.. it keeps it's previous quantity, if it was 5 then it remains with 5 even after deletion.
For a better explanation, here is my code...
This is how I add my items to Bill (cart)...
TypeScript
addToCart(item: SalesScreenItemsModel) {
let itemExists = false;
// tslint:disable-next-line: variable-name
this.Bill.map((ele, _index) => {
if (item.itemId === ele.itemId) {
itemExists = true;
ele.itemQuantity = ele.itemQuantity + 1;
}
return ele;
});
if (itemExists === false) {
this.Bill.push(item);
}
HTML
<div class="col-xl-3 col-lg-4 col-md-4 col-sm-6 col-xs-12" *ngFor="let item of items">
<div class="card mb-3 widget-content bg-arielle-smile item-pic" style="overflow: hidden; padding: 0;">
<div class='box'>
<div class='content'>
<div class="widget-content-wrapper text-white content" style="justify-content: center;">
<div class="widget-content-left text-center">
<img src="{{ item.itemPicture}}" alt="Raised image" class="img-fluid" (click)="addToCart(item)">
</div>
</div>
</div>
</div>
delete function
deleteBillItem(itemIndex: number) {
this.Bill.splice(itemIndex, 1);
}
HTML
<tr *ngFor="let bill of Bill; let i = index">
<th scope="row" class="text-center">{{i + 1}}</th>
<td class="text-center">{{bill.itemName}}</td>
<td class="text-center">{{bill.itemQuantity}}</td>
<td class="text-center">{{ bill.itemPrice * bill.itemQuantity }}</td>
<td class="text-center">
<button class="btn-icon btn-icon-only btn btn-outline-danger" (click)="deleteBillItem(i)"
style="padding: 1px 6px;">
<i class="pe-7s-trash btn-icon-wrapper"> </i>
</button>
</td>
</tr>
Thing is when I log my items array the change to item quantity actually occurs to the main array as well as to the bill... I know this should be simple and that's why it's driving me nuts...
The problem is that you're missing the assignment in map:
this.Bill = this.Bill.map...
But, as a suggestion, you could write a more functional approach:
addToCart(item: SalesScreenItemsModel) {
const itemExists = this.Bill.some(element => element.itemId === item.itemId);
if (itemExists) {
this.Bill = this.Bill.map(element => ({
...element,
itemQuantity: element.itemQuantity + (element.itemId === item.itemId ? 1 : 0)
}));
} else {
this.Bill = [...this.Bill, item];
}
}
And for the remove:
deleteBillItem(itemIndex: number) {
this.Bill = this.Bill.filter((element, index) => index !== itemIndex);
}
Also, Bill isn't the best name for an array/list :)
Try setting the item.itemQuantity to 1 when you add the item
addToCart(item: SalesScreenItemsModel) {
// tslint:disable-next-line: variable-name
const itemIndex=this.Bill.find((billItem) => item.itemId == billItem.itemId);
if(itemIndex == -1){
item.itemQuantity=1;
this.Bill.push(item);
return;
}
this.bill[itemIndex].itemQuantity+=1;
}

How to access all the data in the API call

getNames(): Observable<bookmodel[]> {
const endpoints = 'https://api.nytimes.com/svc/books/v3/lists/current/hardcover-fiction.json?api-key=xxxxxxxx';
return this.http.get(endpoints).pipe(
map(this.extractData));
}
<h1 class="uk-flex uk-flex-center">Top Books{{bestsellers_date}}</h1>
<hr class="uk-divider-icon">
<div class="uk-child-width-1-5#s uk-grid-match" uk-grid>
<div *ngFor="let name of names; let i = index">
<div class="uk-card uk-card-hover uk-card-body">
<h3 class="uk-card-title">{{name.title}}</h3>
<img style="height:250px;" src="{{name.book_image}}"><br/><br/>
<span>Summary: {{name.description || ' NA' |characters:150}}</span><br />
<hr class="uk-divider-icon">
<span>Author {{name.author}}</span>
<br/>
<br/>Best Sellers Rank {{name.rank}}
<br />
<span>Weeks on List {{name.weeks_on_list}}</span>
<div class="uk-card-footer">
<span><a class="uk-button uk-button-primary" href="{{name.amazon_product_url}}">Buy On Amazon</a></span>
</div>
</div>
</div>
</div>
Okay so the code above makes a call to the api and the api returns an object with nested arrays in order to get the infomation I want Ive put defined the data as data.results.books but theres data that I want to access in the data.results Ive tryed just taking the .books part out but the the NGFOR doesn't work with objects is there a way to store or even get the data in data.results and how would I store it
service.ts
getNames(): Observable<bookmodel[]> {
const endpoints = 'https://api.nytimes.com/svc/books/v3/lists/current/hardcover-fiction.json?api-key=7W3E72BGAxGLOHlX9Oe2GQSOtCtRJXAt';
return this.http.get<bookmodel[]>(endpoints);
}
component.ts
this.service.getNames().subscribe(names => this.names = names);
HTML
<div *ngFor="let name of names; let i = index">
......
</div>
If you are not subscribing it use async pipe in html
<div *ngFor="let name of names | async; let i = index">
......
</div>
Try updating the *ngFor with an async pipe. You need to use async pipe because httpClient always returns Observable.
<div *ngFor="let name of names | async; let i = index"></div>
Also update the getNames and remove the .pipe from there
getNames(): Observable<bookmodel[]> {
const endpoints = 'https://api.nytimes.com/svc/books/v3/lists/current/hardcover-fiction.json?api-key=7W3E72BGAxGLOHlX9Oe2GQSOtCtRJXAt';
return this.http.get<bookmodel[]>(endpoints);
}

Generate dynamic table with div based on ngFor loop

The code below is in a view of main-category.component
<div>
<div *ngFor="let category of categories;">
<app-subcategory>
[name]="category.name">
</app-subcategory>
</div>
</div>
I'd like generate a table with 4 columns and x rows depending the number of items in categories. Each cell contain the component app-subcategory.
I don't see the right way to do this. Do you have idea ?
Thanks,
#Pipe({ name: columns })
export class ColumnsPipe implements PipeTransform {
transform(data, numColumns) {
if(!data || data.length == 0) {
return data;
}
var i,j,temparray,chunk = 10;
result = [];
for (i=0,j=data.length; i<j; i+=chunk) {
result.pop(array.slice(i,i+chunk));
}
return result;
}
}
see also https://stackoverflow.com/a/8495740/217408
<div>
<div *ngFor="let row of categories | columns:4">
<div *ngFor="let category of row">
<app-subcategory>
[name]="category.name">
</app-subcategory>
</div>
</div>
</div>
You might want to change the divs into <tr> and <td> to get real rows and columns.

How to use if statement into foreach in razor?

I try to use two if statement into foreach such as this but in second if statement get error.Please advice
#{
string path = System.Configuration.ConfigurationManager.AppSettings["ImageEdit"];
int i = 0;
}
#foreach (var item in Model.PhotoTables)
{
if (i < 1)
{ <div class="row">
}
<div class="col-xs-2 col-wrapper">
<div class="image-wrapper">
<img src="#Url.Content(path+item.PhotoName)" alt="" />
<img class="delimg" src="~/Content/Adminex/images/delete-icons.png" id="#item.Id" />
</div>
</div>
#if (i < 1 )
{
</div>}
</div>
i++;
}
You seem to have an extra closing div with no matching start tag.
Your code block can contain all of the logic. Try:
#{
string path = System.Configuration.ConfigurationManager.AppSettings["ImageEdit"];
int i = 0;
foreach ( var item in Model.PhotoTables )
{
if ( i < 1 )
{
<div class="row">
}
<div class="col-xs-2 col-wrapper">
<div class="image-wrapper">
<img src="#Url.Content(path + item.Name)" alt="" />
<img class="delimg" src="~/Content/Adminex/images/delete-icons.png" id="#item.Id" />
</div>
</div>
#if (i < 1 )
{
</div>
}
i++;
}
}
You only need the # symbol on the containing codeblock.
The # symbol is not required when you directly nest actual code blocks (not HTML), so the first foreach, and if are ok, but then we go into HTML, and then back to code for the second if - we need to use a #.
Manually manipulating a variable inside a foreach statement can possibly lead to trouble. Instead, take advantage of current framework method Select().
Model:
var model = new SampleViewModel
{
Items = new List<string>
{
"A",
"B",
"C"
}
};
return View(model);
}
Razor:
#foreach(var item in Model.Items
.Select((value, index) => new { Value = value, Index = index }))
{
if ( item.Index < 1 )
{
<div class="row">
}
<div>#item.Index #item.Value</div>
if ( item.Index < 1 )
{
</div>
}
}
Results:
0 A
1 B
2 C
DotNetFiddle MVC Example