Angular4 - execute function if NOT all checkboxes are selected - html

I have a main checkbox which has ngModel value as [(ngModel)]="formModel.acknowledged1 and on component it is set to false like
formModel = {
acknowledged1 :false
}
And I have a table with n number of rows, each row having checkboxes with ngModel as [(ngModel)]="formModel.acknowledged so when i click on main checkbox, all checkboxes on tables get selected and then my function deleterow gets executed, but i want
If I select only singly checkbox from table rows, then some other function should get executed. see below to make my question clear.
html -
<p>
<checkbox [(ngModel)]="formModel.acknowledged1" id="box1" name="acknowledgement1"></checkbox></p>
<tbody infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="300"
(scrolled)="onScroll()"
[scrollWindow]="false">
<ng-container *ngFor="let data of allData>
<tr class= "row-break">
<checkbox [(ngModel)]="formModel.acknowledged1" id="box2" name="acknowledgement2">
</checkbox>
<td>
<a>{{data.Code}}</a>
</td>
<td>
{{data.Description}}
</td>
</tr>
</ng-container>
</tbody>
Component.ts -
export class CodesComponent implements OnInit{
formModel = {
acknowledged1 :false
}
ngOnInit (){
deleteallrow(){
if(this.formModel.acknowledged1==true){
this.reasonCodesActions.deleterow();
}
deletesinglerow(){ }
}

You need to create an array with single booleans for every checkbox.
component.html
...
<ng-container *ngFor="let data of allData; let i = index;">
<tr class="row-break">
<checkbox
(change)="changeBox(i)"
[checked]="checkboxes[i]"
id="box2"
name="acknowledgement2"
></checkbox>
...
</tr>
</ng-container>
component.ts
...
checkboxes = [];
changeBox(index) {
if (this.checkboxes[index]) {
return this.checkboxes[index] = !this.checkboxes[index];
}
return this.checkboxes[index] = true;
}
...
Something in the code could be wrong, I don't use Angular for a while, but that is the logic that I've used in the last time that I've made it!

Related

angular fake API using jasonplaceholder, getting details after clicking button

I am working on a dummy API with jsonplaceholder, I am getting all posts after clicking button, but i wanna get userid and title on load,and after clicking title need to get that particular body of that id How can i achieve this.
in jasonplaceholder there are 100 posts with id,title,body. on clicking getdata i need only id and title after when I click on title I need to get body as either in paragraph or popup or something.
html
<button (click)="get()">Get Data</button>
<div class="col-md mt-4 mb-4">
<table class="table table-bordered">
<thead>
<tr>
<th>id</th>
<th>title</th>
<th>body</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let d of data">
<td><span>{{d.id}}</span></td>
<td><span>{{d.title}}</span></td>
<td><span>{{d.body}}</span></td>
</tr>
</tbody>
</table>
</div>
ts
get(){
this.userservice.getData().subscribe((data) =>{
console.log(data)
this.data = data
})
}
service
getData():Observable<any>{
const url = "https://jsonplaceholder.typicode.com/posts";
return this.http.get(url)
}
A simple solution would be to use *ngIf and a variable, eg. selectedId
<td (click)="showBody(d.id)"><span>{{d.title}}</span></td>
<td *ngIf="selectedId === d.id"><span>{{d.body}}</span></td>
Then in your component, initiate it:
selectedId: any = null;
and
showBody(id: number){
this.selectedId ? this.selectedId = null : this.selectedId = id;
}
so that it would hide the body if you click on the title again.
As I understand, you need to get the id of the element you clicked on it to show the element's body.
so to achive this, you can write something like this:
component.html
<tr *ngFor="let d of data" (click)="setBody(d)">
<td><span>{{d.id}}</span></td>
<td><span>{{d.title}}</span></td>
</tr>
<!-- Show selected item body here -->
<h1>Selected item body</h1>
<p>{{selectedItemBody}}</p>
component.ts file
[Optional]: you can define the POST interface top of your ts file to have more clean code:
interface POST {
id: number;
title: string;
body: string;
}
setBody(post: POST) {
this.selectedItemBody = post.body;
alert(this.selectedItemBody); // you can remove this alert
}
I provided you this sample working code here in stackblits

Why are the form inputs in my html table unclickable?

I am trying to render a table in html that is the representation of a reactive form array.
I loop over the complex object (FormGroup > FormArray > FormGroup > FormArray) With the final array being the data that we want to represent to the UI in its transformed format. (Happens in the function groupFormGroup())
Everything works fine, the data is correctly transformed and displayed.
However, now I am trying to add inputs (NOT formControlName inputs) to the table and when they load, they load without me being able to click into, or change their value. They are not disabled, just unclickable. No errors come up in the console.
What I have tried:
Modifying the class names so it is no longer class='form-control'
Increasing the z-index of inputs to be on the forefront
Making the inputs position relative
Here is the code:
<div class="row" [formGroup]="address">
<div class="col-12">
<table class="w-100">
<thead>
<th></th>
<th>Order ID</th>
<th>GP Code</th>
<th>Product</th>
<th>Quantity</th>
<th>Preset Suite Number</th>
<th></th>
</thead>
<tbody>
<ng-template formArrayName="addressOrders" ngFor let-addressOrder [ngForOf]="address.get('addressOrders').controls" let-ao="index">
<ng-container [formGroup]="addressOrder">
<ng-template ngFor let-fulfillment [ngForOf]="groupFormGroup(addressOrder.get('fulfillments').getRawValue(),'orderDetailId')" let-f="index">
<tr>
<td class='table-input'>
<input type="checkbox"
(change)="updateFulfillmentFormControl(fulfillment,addressOrder,'selected',$event)"/>
</td>
<td>{{addressOrder.get('orderId').value}}</td>
<td>{{fulfillment['gpItemNumber']}}</td>
<td>{{fulfillment['name']}}</td>
<td>{{fulfillment['quantity']}}</td>
<td>
<ng-container *ngIf="fulfillment['isSuite']">
<!-- <input class="form-control" (keydown)="updateFulfillmentFormControl(fulfillment,addressOrder,'suiteNumber',$event)" /> -->
<input type="text" class="form-control" />
</ng-container>
</td>
<td>Edit Detail</td>
</tr>
</ng-template>
</ng-container>
</ng-template>
</tbody>
</table>
</div>
</div>
And the code generating the Form Group:
draw() {
this.formGroup = this.initFormGroup(this.ordersToDisplay)
}
initFormGroup(ordersToDisplay: Array<BulkFulfillCustomer>):FormGroup {
var queueList = this.queues.map(q => q['queue_id']);
return this.fb.group({
customers: this.fb.array(
ordersToDisplay.map(otd => {
return this.fb.group({
gpCustomerNumber:[otd.gpCustomerNumber],
customerName:[otd.customerName],
customerAddresses: this.initAddressForm(otd.addressOrders, queueList)
})
})
)
})
}
initAddressForm(addressOrders: Array<BulkFulfillAddress>, queues:Array<string>):FormArray {
return this.fb.array(
addressOrders.map(ao => {
return this.fb.group({
addressLine:[ao.addressLine],
bundleShipment:[true],
addressOrders: this.initAddressOrdersForm(ao.orders,queues)
})
})
)
}
initAddressOrdersForm(orders: Array<BulkFulfillOrder>, queues:Array<string>):FormArray {
return this.fb.array(
orders.map(o => {
return this.fb.group({
orderId: [o.order.id],
fulfillments: this.initFulfillmentsForm(o.orderDetailFulfillments,queues)
})
})
)
}
initFulfillmentsForm(fulfillments: Array<FulfillmentLine>, queues:Array<string>) {
return this.fb.array(
fulfillments.map(f => {
return this.fb.group({
selected:[true],
expandDetail:[false],
isSuite:[f.inventory.isSuite],
suitePrefix:[f.inventory.suitePrefix],
gpItemNumber:[f.inventory.gpItemNumber],
name:[f.inventory.name],
queueId:[{value:f.inventory.pulseQueueId,disabled:(!this.isPulseFulfill && f.inventory.fulfillmentMethod != INVENTORY_FULFILLMENT_PULSE)}, Validators.compose([Validators.required, ContainsListValidator(queues,'Queue ID')])],
orderDetailId:[f.orderDetailFulfillment.orderDetailId],
pulseOrderId:[f.orderDetailFulfillment.pulseOrderId],
suiteNumber:[{value:f.orderDetailFulfillment.suiteNumber,disabled:!this.isPulseFulfill || !f.inventory.isSuite}, Validators.required],
quantity:[{value:f.orderDetailFulfillment.quantity,disabled:f.orderDetailFulfillment.fulfillmentMethod != 1},Validators.compose([Validators.required, Validators.min(1),Validators.max(f.orderDetailFulfillment.quantity)])]
})
})
)
}

When a button is clicked I want to access the data of the rows which were checked by the user.I don't know how to loop through my mat-table rows

I want to loop through this column of my mat-table to find which rows are checked and then push that row data into an array.
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()" (change)="pushRowToArray($event, row)" (change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)">
</mat-checkbox>
</td>
I would make the checkbox call a function and add it to an array in there.
Like this:
<input type="checkbox" id="matCheckBox" (change)="yourfunc($event)"/>
and make the func like
yourfunc(e) {
if(e.target.checked){
this.array.push(e.target);
}else{
this.array = this.array.filter(obj => obj !== e.target);
}
}

Need to get specific html element row index from *ngFor to activate boolean function

I'm trying to build a dynamic table in Angular with add, edit, delete functionality. Both my edit/delete buttons exist as their own column on every single one of the table rows. The edit button (onclick) is designed to make each of the 3 text data fields (in the same row as the edit button itself) turn into input fields whose user-entered text can then be saved.
<table id="thetable" align="center">
<tr>
<th>Application ID</th>
<th>Description</th>
<th>API Key</th>
<th>EDIT/DELETE</th>
</tr>
<tr id="newtablerow" ng-app="tblRowApp" *ngFor="let prov of providers; let i = index">
<td id="tablevalues" *ngFor="let col of columns">
<span id="columnText" ng-init="getRowIndex(i)" *ngIf="!editing">{{prov[col]}}</span>
<span class="editfield" *ngIf="editing">
<input id="changeText" ng-init="getChangeTextCol(col)" type="text" style="margin-right: 10px" placeholder="{{prov[col]}}">
<button ngOnload="getChangeTextCol(col)" (click)="save(changeText.value); !editing">Save</button>
</span>
</td>
<td id="editdelete">
<button class="edit" name="editButton" (click)="editToggle(i)">/</button>
<button class="delete" (click)="deleteRow(i)">x</button>
</td>
</tr>
public editing: boolean = false;
editToggle(event) {
var table = (<HTMLTableElement>document.getElementById("thetable"));
var getTextFields = table.getElementsByClassName("columnText");
for (var i = 0; i < getTextFields.length; i++) {
if (getTextFields[i].getRowIndex(event) == event) {
getTextFields[i].editing = !getTextFields[i].editing;
}
}
}
getRowIndex(event) {
console.log("row index = " + event);
return event;
}
getChangeTextCol(event) {
return event;
}
deleteRow(event) {
this.providers.splice(event, 1);
}
editToggle() is activated on edit button click and finds the current row index of itself by variable i specified by *ngFor. However, I also need to tell angular the row index of the span element containing the html input field to be shown, but I get an error saying property 'getRowIndex' does not exist on type 'Element'. This works for other functions in HTML elements like deleteRow(i), for instance.

Angular Datatables - Select only filtered rows

I am rendering my DataTable the angular way, I added a checkbox per row and a select all checkbox at the top. The problem is that for example, I filter the rows using the search box if I check the select all it checks all the rows. What do I do so that when the select all checkbox is clicked, it only checks the visible rows after the filtering.
Html
<table id="tblAvailable" datatable="ng" dt-options="mainCtrl.dtOptions" dt-instance="mainCtrl.dtInstance" dt-column-defs="mainCtrl.dtColumnDefs" class="table table-responsive table-hover">
<thead>
<tr>
<th>Ref. #</th>
<th>Type</th>
<th>Category</th>
<th>Applied Amount</th>
<th>New Amount</th>
<th><input type="checkbox" ng-model="mainCtrl.selectAll" ng-click="mainCtrl.toggleAll(mainCtrl.selectAll)" ng-change="mainCtrl.update()"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="Item in mainCtrl.newLineDetails" ng-if="Item.Amount > 0">
<td>{{Item.Id}}</td>
<td>{{Item.Type.Name}}</td>
<td>{{Item.Category.Name}}</td>
<td>{{Item.Amount | number:2}}</td>
<td><input type="number" ng-disabled="Item.isSelected == false" id="Amount" name="Amount" class="form-control ng-pristine ng-untouched ng-valid ng-not-empty" ng-model="Item.Amount" ng-min="1" ng-max="Item.Amount" ng-required="Item.isSelected == true" ng-change="mainCtrl.updateForFreeUps()"/></td>
<td><input type="checkbox" ng-model="Item.isSelected" ng-change="mainCtrl.toggleOne(Item.Id)"></td>
</tr>
</tbody>
</table>
Ctrl
self.toggleAll = function(selectAll) {
angular.forEach(self.newLineDetails, function (value, index) {
self.newLineDetails[index]["isSelected"] = selectAll;
if (selectAll == false) {
self.newLineDetails[index]["Amount"] = null;
}
})
}
self.toggleOne = function (Id) {
for (var i = 0, len = self.newLineDetails.length; i < len; i++) {
if (self.newLineDetails[i]["Id"] == Id) {
self.newLineDetails[i]["Amount"] = null;
self.selectAll = false;
self.update();
return;
}
}
self.selectAll = true;
}
You must go through the DataTables API. DT remove and inject DOM nodes from a "shadow table" so just manipulating DOM will only have apparently (not real) effect until next redraw. Fortunately you have already implemented a dtInstance.
From 1.10.6 the most convenient way to iterate through rows, columns or cells is the every method. See this plunkr -> http://plnkr.co/edit/NOP5u4PUcwVOBFUtBkBi?p=preview
$scope.$watch('settings.selectAll', function(newVal, oldVal) {
if (newVal == oldVal) return
var api = $scope.dtInstance.DataTable;
api.rows({ search:'applied' }).every(function() {
api.cell({ row:this.index(), column:0 })
.nodes()
.to$()
.find('input')
.prop('checked', $scope.settings.selectAll);
})
$scope.dtInstance.DataTable.draw()
})
Here the checkbox is in column 0; the code can be translated into
cycle through all rows
get the first column
convert to jQuery instance
find the <input>
update the checked status
Some notes about your selectAll checkbox :
best to use an object as ng-model, in the example I have used a settings.selectAll literal
ng-click does not work effectively with checkboxes, if you really want to use a directive, use ng-change only
since you are using a ng-model, you can just $watch that value, calling mainCtrl.toggleAll(mainCtrl.selectAll) is "obscure"
There are many ways for solving this problem:
1) You can write change function for select all checkbox. In that function first you should filter all of your data after that check them.
2) You can copy your main data to another variable (we call it x for now). after that show x in table (not your main resource). when you want to filter the rows using the search box filter main data and past it into the x variable when you want to use it for check or add etc use x variable