Does anyone know how to add a row to PrimeNg DataTable - html

I'm trying to add a new row to the current table so that I can have a row under the list of data that can have a save button and an insert to be done e.g. save phone number. I have added html comments of where the new row will go but not sure how to do it in PrimeNg.
See the code below:
<div class="m_datatable m-datatable m-datatable--default m-datatable--loaded">
<p-dataTable [value]="personPhone.phones"
emptyMessage="{{l('NoData')}}"
paginator="false"
rows="5"
tableStyleClass="m-datatable__table">
<p-column header="{{l('Actions')}}" [style]="{'width':'130px','text-align':'center'}">
<ng-template let-record="rowData" pTemplate="body">
<button (click)="deletePhone(phone, personPhone)" class="btn btn-outline-danger m-btn m-btn--icon m-btn--icon-only m-btn--pill">
<i class="fa fa-times"></i>
</button>
</ng-template>
</p-column>
<p-column header="{{l('PhoneType')}}">
<ng-template let-record="rowData" pTemplate="body">
{{getPhoneTypeAsString(record.type)}}
</ng-template>
</p-column>
<p-column header="{{l('PhoneNumber')}}">
<ng-template let-record="rowData" pTemplate="body">
{{record.number}}
</ng-template>
</p-column>
<!--New row to go here-->
</p-dataTable>
</div>
I Just want a row like this:
<tr>
<td>
<button (click)="savePhone()" class="btn btn-sm btn-success">
<i class="fa fa-floppy-o"></i>
</button>
</td>
<td>
<select name="Type" [(ngModel)]="newPhone.type" class="form-control">
<option value="0">{{l("Mobile")}}</option>
<option value="1">{{l("Home")}}</option>
<option value="2">{{l("Business")}}</option>
</select>
</td>
<td><input type="text" name="number" [(ngModel)]="newPhone.number" class="form-control" /></td>
</tr>

First find the length of the data what you are getting like below?
public dataLength:number;
this.myService.getAllResult('query)
.subscribe((response: any[]) => {
this.data = response
this.dataLength = this.data.length;
}
Now in p-template body take another row and use *ngIf and check the dataLength is greater than or equal to current Index:
<ng-template pTemplate="body" let-i="rowIndex" let-data>
<tr>
<td>{{i + 1}}</td>
<td>{{data.name}}</td>
<td>{{data.email}}</td>
</tr>
<tr *ngIf="i >= (dataLength -1)">Print your data</tr>
</ng-template>
I think there should be something like $last and $first index in primeNg as we have in angular for *ngFor.
If we find the last index in Prime Ng. Then no need to take the another dataLength. But Above solution should work for you.

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;

Editable field saved to database

I've got this editable field. I need it to save the new data and store it in the database.
HTML:
<ng-container *ngIf="groupedVolumes">
<ng-container *ngFor="let model of groupKeys() | slice:-3" >
<tr>
<th class="model">{{ carValues(model)[0].model }}</th>
<ng-container *ngFor="let value of carValues(model)">
<td contenteditable='true' class="data">
{{ value.scheduledVolume }}
</td>
</ng-container>
</tr>
</ng-container>
</ng-container>
The HTML data shows the editable field.
This is the button to save with:
<div class="row">
<div class="col-auto">
<button
type="submit"
class="btn btn-success mx-1"
onclick="saveData()">Save
</button>
</div>
</div>
This is not a good approach.
Use input (probably type="text") for input using the angular form api, then you can store the new values in database on completion.

angular ng-option add icon

I am trying to write a dropdown list for selecting country, is possible to add flag of country next to the country name??
<div class="chosen-input-group col-sm-10 ">
<select id="country_type" chosen data-placeholder="-- 國家 --" disable-search="false"
ng-options="country_.country_id as country_.name for country_ in vm.country_data"
ng-model="vm.item.country_id">
<option value=""> -- 國家 --</option>
</select>
</div>
You could use ng-repeat on the option tag and then style the option with the image as you want it
<select >
<option ng-repeat="country_ in vm.country_data"
value="country_.country_id"
style="background-image:url({{country_.name}}.png);">
{{ country_.name }}
</option>
</select>
It is not possible using a native select with options.
Have a look to https://github.com/angular-ui/ui-select
Soruce : Angular select with images
I added the icon directly to the ng-template tag, and it works:
<ng-select [clearable]="false" [searchable]="false" [items]="items" bindLabel="libelle" [(ngModel)]="selectedItem">
<ng-template ng-label-tmp let-item="item">
<i class="fa fa-eye"></i>
<b> {{item.libelle}}</b>
</ng-template>
<ng-template ng-option-tmp let-item="item" let-index="index">
<i class="fa fa-eye"></i>
<b> {{item.libelle}}</b>
</ng-template>
</ng-select>

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>

v-repeat in table rows

I have table of emails with <TR>'s being repeated with v-repeat followed with a single <TR> for displaying an empty form for adding a new email.
Problem is that the <TR> with empty form always appears as the FIRST row BEFORE the list of existing email <TR>s.
Is there a way to force the <TR> with the empty email form to render AFTER the list of email <TR>'s?
<section v-show="emails" v-cloak>
<table id="email-list">
<tbody>
<tr
v-repeat="email: emails"
class="email"
v-class="
editing : this == editedEmail
"
>
<td>
<input
class = "edit"
type = "text"
v-model = "email.address | addressValidator"
v-on = "
click : editAddress(this, $index),
blur : doneEdit(this, $index),
keyup : doneEdit(this, $index) | key 'enter',
keyup : cancelEdit(this, $index) | key 'esc'
"
>
</td>
<td>
<a
class="btn btn-xs btn-danger"
style="cursor:pointer;"
v-on="click: removeEmail(this, $index)"
>
<i class="fa fa-trash"></i>
</a>
</td>
</tr>
</tbody>
<tfoot>
<tr
class="email"
v-class="
editing : this == editedEmail
"
>
<form
id="add-new-form"
v-on="submit:addNew"
>
<input
id="0"
autofocus
autocomplete="off"
placeholder="New Email Address"
v-model="newEmail.address | addressValidator"
>
<button
type="submit"
v-show="newEmail.address && validation.address"
class="btn btn-xs btn-success"
style="cursor:pointer;"
>
<i class="fa fa-plus"></i>
</button>
</form>
</tr>
</tfoot>
</table>
</section>
A form can’t be a direct child of a table row. Put it outside of the table as it is not part of the datas.
#Samuel De Backer pointed out the problem in his comment to my question.