Angular 4: deleteRow in table, splice error - html

I have a quick question regarding Angular 4 and splicing.
Below is my Typescript code:
delete(appIndex: number): void {
this.apps.splice(appIndex, 1);
}
Below is my HTML Code:
<tr *ngFor="let app of apps; let i = index">
<td><input type="text" [(contenteditableModel)]="text1" tabindex="1"> {{ text1 }}</td>
<td><input type="text" [(contenteditableModel)]="text2" tabindex="2">{{ text2 }}</td>
<td><input type="text" [(contenteditableModel)]="text2" tabindex="3">{{ text3 }}</td>
<td class="actions">
<input type="button" value="Delete" (click)="delete(i)">
</td>
</tr>
The issue I am running into is 'Cannot read property 'splice' of undefined. When I further researched into this, I found that in Angular 1, '$scope' was used in order to access within the DOM. How do I replicate this in Angular 4?
UPDATE:
I have edited my code to read like:
Typescript:
delete(appIndex: number) {
this.apps.splice(appIndex, 1);
this.changeDetectorRef.detectChanges();
}
HTML:
<tr class="odd">
<td class="status"><img src="../../../assets/images/Red_Circle_1.png" class="redcircle"></td>
<td><input type="text" [(contenteditableModel)]="text4"> {{ text4 }}</td>
<td><input type="text" [(contenteditableModel)]="text5">{{ text5 }}</td>
<td><input type="text" [(contenteditableModel)]="text6">{{ text6 }}</td>
<td class="actions">
<input type="button" value="Delete" *ngFor="let app of apps; let i = index" (click)="delete(i)">
</td>
</tr>
Here is the plunker: http://plnkr.co/edit/2KaXodEe2CbQdLXZtVaC?p=preview
I'm not getting any errors now, but the delete button is not displaying at all.
Any suggestions would be appreciated.
Thank you.

Your code should work without problem so long as you are executing delete from the component whose template you called it from.
Here is basically the same code working: Live demo

Related

Issue when Table with Inputs is inside of a Form

I'm building an Angular application with PrimeNG. I have a form that contains a p-table (list of products) with inputs (quantity and price), when I select the first product from a dialog and enter the inputs (quantity and price), then select a second product, I lose the first quantity and price that enter for the first product.
This issue only happened when putting the table with inputs inside of the form.
Is there a right way to resolve this? My code is below.
HTML:
<form #form="ngForm" (ngSubmit)="valider(form)">
<p-table [value]="object.produits" >
<ng-template pTemplate="header">
<tr>
<th>Code Produit</th>
<th>Quantité</th>
<th>Price</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-produit>
<tr [pSelectableRow]="produit">
<td>{{produit.codeProduit}}</td>
<td>
<input type="text" size="10" pInputText name="quantite" [readonly]="action=='show'" pKeyFilter="num" [ngModel]="produit.quantite" (ngModelChange)="produit.quantite = $event;">
</td>
<td>
<input type="text" size="10" pInputText name="prixUnitaire" [readonly]="action=='show'" pKeyFilter="num" [ngModel]="produit.prixUnitaire"(ngModelChange)="produit.prixUnitaire = $event;">
</td>
</tr>
</ng-template>
<ng-template pTemplate="summary">
<button type="button" (click)="showDialogProduit()" pButton label="Ajouter Produit"></button>
</ng-template>
</p-table>
</form>
<p-dialog header="Liste des produits" [(visible)]="dialogProduit" >
<p-table #dt_produits [value]="produits" selectionMode="multiple" [(selection)]="operationCommodities.produits" >
<ng-template pTemplate="header">
<tr>
<th>Code</th>
<th>Désignation</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-produit>
<tr [pSelectableRow]="produit">
<td>{{produit.codeProduit}}</td>
<td>{{produit.designation}}</td>
</tr>
</ng-template>
<ng-template pTemplate="summary">
<button pButton type="button" label="Terminer" (click)="closeDialogProduit()"></button>
</ng-template>
</p-table>
</p-dialog>
TS:
showDialogProduit() {
this.dialogProduit = true;
}
closeDialogProduit() {
this.dialogProduit = false;
}
Stackblitz Demo:
https://stackblitz.com/edit/primeng-tablebasic-demo-a7bdgm?file=src%2Fapp%2Fapp.component.html
The problem is that input fields don't have a unique name which messes up how ngModel directive works. When I updated the code as follows, it was fixed. Note that the [name] attributes of both input fields are dynamic values based on produit.codeProduit
<tr [pSelectableRow]="produit">
<td>{{produit.codeProduit}} </td>
<td>
<input type="text" size="10" pInputText [name]="'quantite_' + produit.codeProduit" [readonly]="action=='show'" pKeyFilter="num" [ngModel]="produit.quantite" (ngModelChange)="produit.quantite = $event;">
</td>
<td>
<input type="text" size="10" pInputText [name]="'prixUnitaire_' + produit.codeProduit" [readonly]="action=='show'" pKeyFilter="num" [ngModel]="produit.prixUnitaire"(ngModelChange)="produit.prixUnitaire = $event;">
</td>
</tr>
Please check Forked stackblitz with updated code.
As an aside, I recommend you change your implementation to use Angular Reactive Forms instead of ngModel;

Current input value does not get passed to event handler in AngularJS

<tr ng-repeat="item in groups">
<td hidden><input type="hidden" value="{{item.id_group}}" /></td>
<td><input type="text" value="{{item.description}}" class="form-control" /></td>
<td>
Edit |
Delete
</td>
</tr>
So this code was supposed to show values in a table and when the user changes anything in the description and click on Edit, it should POST the new value to the server. Instead it's posting the old value, I need some help please to identify why this is happening.
Try using Ng-model
<tr ng-repeat="item in groups track by $index">
<td hidden><input type="hidden" ng-model="groups[$index].id_group" /></td>
<td><input type="text" ng-model="groups[$index].description" class="form-control" /></td>
<td>
Edit |
Delete
</td>
</tr>

HTML / FLASK - Dynamic Table with Checkboxes per row

With Flask / HTML, I am dynamically populating a table of directory listings where I would like the user to have the option to select single or multiple directories via a checkbox, however when I check the box on any table row besides the first, only the first row's checkbox is being selected. I have ensured that the value of the checkboxes are independent, however I would like to have each row's checkbox to be unique to one another.
HTML:
<div id="select-form">
<form action="" method="post">
<h1>{{ directory.user_entered_path }}</h1>
<table cellspacing="0" class="table">
<tbody>
<tr>
<td class="head">Filename</td>
<td class="head">Type</td>
<td class="head">Size</td>
<td class="head">Select</td>
</tr>
{% for file in dir_list %}
<tr>
<td name="name"> {{ file.file_name }}</td>
<td> {{ file.file_type }} </td>
<td> {{ file.file_size }}</td>
<td><input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="{{file}}">
<label class="form-check-label" for="inlineCheckbox1"> </label></td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
</div>
I tried the following:
To the end of your html, within the <form></form> I added a submit button for convenience, I don't know of another way to create a post request.
<form action="" method="post">
<h1>{{ directory.user_entered_path }}</h1>
<table cellspacing="0" class="table">
<tbody>
<tr>
<td class="head">Filename</td>
<td class="head">Type</td>
<td class="head">Size</td>
<td class="head">Select</td>
</tr>
{% for file in dir_list %}
<tr>
<td name="name"> {{ file.file_name }}</td>
<td> {{ file.file_type }} </td>
<td> {{ file.file_size }}</td>
<td><input class="form-check-input" type="checkbox" name="check" id="inlineCheckbox1" value="{{file}}">
<label class="form-check-label" for="inlineCheckbox1"> </label></td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- added this button -->
<button type="submit" name="submit-button" value="Submit">submit</button>
</form>
Then I added this route to a flask app.py
from flask import request, render_template
#app.route('/stack-dynamic-checkboxes', methods=["POST", "GET"])
def dynamic_checkboxes():
if request.method == 'POST':
if request.form['submit-button'] == "Submit":
for checkbox in request.form.getlist('check'):
print(checkbox)
def afile(x):
return {'file_name':f'file {x}',
'file_type':f'type {x}',
'file_size':f'size {x}'}
dir_list = [afile(x) for x in range(10)]
directory = {'user_entered_path':'a path'}
return render_template( 'testing/stack-dynamic-checkboxes.html',
directory=directory,
dir_list=dir_list )
When I run the app and navigate to the page with your html, select some checkboxes and press submit, I get information about the files printed to my console. They are all dictionaries in this format
{'file_name': 'file 0', 'file_type': 'type 0', 'file_size': 'size 0'}
I hope this was wat you were looking for.
I've been searching for a way to do this for a while. I'm glad you posted this question because I didn't understand the way I had to set up the HTML part correctly, so, thank you!
In the future, It would be nice to have a little bit more context, what your code looks like perhaps, as I'm uncertain whether this is what you were looking for

"Cannot read property 'parentNode' of undefined"- Angular, HTML, Typescript

I'm getting an error which reads:
"Cannot read property 'parentNode' of undefined". I am using Angular. I have Typescript and HTML files. The code is below.
Typescript:
public deleteRow(btn) {
console.log("parentNode:" + btn.parentNode);
var row = btn.parentNode.parentNode;
row.parentNode.removeChild(row);
}
HTML:
<tr bg-color="#2b5dd1" *ngFor="let row of rows; let even = even; let odd = odd" [ngClass]="{ odd: odd, even: even}" class = "even">
<td><input type="text" [(contenteditableModel)]="text1" tabindex="1"></td>
<td><input type="text" [(contenteditableModel)]="text2" tabindex="2"></td>
<td><input type="text" [(contenteditableModel)]="text2" tabindex="3"></td>
<td class="actions">
<input type="button" value="Delete" (click)="deleteRow(this)">
</td>
</tr>
I am not sure what's going wrong, it should work perfectly.
I'm working on putting together a Stackblitz to demonstrate how it works.
Any comments or suggestions would be appreciated.
Thank you.
the keyword this doesn't work like that in Angular templates, you generally won't be accessing the DOM directly, as Angular handles that for you, the idea is you update the model and angular takes care of the view. Try it like this instead:
<tr bg-color="#2b5dd1" *ngFor="let row of rows; let even = even; let odd = odd; let index = index" [ngClass]="{ odd: odd, even: even}" class = "even">
<td><input type="text" [(contenteditableModel)]="text1" tabindex="1"></td>
<td><input type="text" [(contenteditableModel)]="text2" tabindex="2"></td>
<td><input type="text" [(contenteditableModel)]="text2" tabindex="3"></td>
<td class="actions">
<input type="button" value="Delete" (click)="deleteRow(index)">
</td>
</tr>
public deleteRow(index) {
this.rows.splice(index,1);
}
working plunk: https://plnkr.co/edit/jAHT4CXQcpRgIOxw4eR6?p=preview

Angular 4.x: How to bind table checkbox with button in Angular 4.x?

I am new in Angular 4.x. I have a html table. Every row has a checkbox and a checkbox. I want to bind checkbox with button, so that when the checkbox is checked, the button is enabled, and when the checkbox in unchecked, the button is disabled:
here is a sample of code, but it is not working :
<tbody>
<tr *ngFor="let item of mf.data; let i = index;">
<td><input type="checkbox" value="" [checked]="item.checked"></td>
<td>{{i}}</td>
<td>{{item.name}}</td>
<td>{{item.email}}</td>
<td>{{item.age}}</td>
<td>{{item.city | uppercase}}</td>
<td><button type="button" class="btn btn-success" [disabled]="item.checked">start</button></td>
</tr>
</tbody>
Can you help me to make this work please ?
use [(ngModel)]. Because check will not enable the two-way binding. It just handles One-way changing
<td><input type="checkbox" value="" [(ngModel)]="item.checked"></td>
make the button disable not equal to item check, like this [disabled]="!item.checked"
<td><button type="button" class="btn btn-success" [disabled]="!item.checked">start</button></td>
Currently your checkbox only binds one way. To apply changes by clicking it, add the following to your input tag:
(change)="item.checked = !item.checked"
You don't need checked directive. Just binding the model is enough.
<tbody>
<tr *ngFor="let item of mf.data; let i = index;">
<td><input type="checkbox" [(ngModel)]="item.checked"></td>
<td>{{i}}</td>
<td>{{item.name}}</td>
<td>{{item.email}}</td>
<td>{{item.age}}</td>
<td>{{item.city | uppercase}}</td>
<td><button type="button" class="btn btn-success" [disabled]="!item.checked">start</button></td>
<pre>{{item.checked}}</pre>
</tr>
</tbody>
<tbody>
<tr *ngFor="let item of mf.data; let i = index;">
<td><input type="checkbox" value="" [checked]="item.checked"></td>
<td>{{i}}</td>
<td>{{item.name}}</td>
<td>{{item.email}}</td>
<td>{{item.age}}</td>
<td>{{item.city | uppercase}}</td>
<td><button type="button" class="btn btn-success" [disabled]="item.checked">start</button></td>
</tr>
</tbody>
Use this:
<td>
<div class="togglebutton">
<label>
<input type="checkbox" [checked]="record.status" (change)="changeStatus(record.id,$event)">
<span class="toggle"></span>
</label>
</div>
</td>