How to use ngClass with table in Angular - css

I have a table, where I want to declare ngClass (first row)
<table [ngClass]="{'before_forth': pageNumber < 4, 'forth': pageNumber = 4}">
<tr id="words" *ngFor="let item of itemsSource3; let i = index;">
<td *ngFor="let item2 of helper[i]; let j = index;">
<input class="resizedTextbox" name="{{i}}{{j}}"
[(ngModel)]="helper[i][j].value" (ngModelChange)="onValueChange(f,i)"/>
</td>
{{item}}
</tr>
</table>
And my CSS is
table.forth.td:nth-child(2){background-color: green}
table.forth.td:nth-child(5){background-color: green}
table.before_forth.td:nth-child(2){background-color: red}
table.before_forth.td:nth-child(5){background-color: red}
So, what I would like to do is to set the colour, which depends on the number of page (in my component I use this method
this.pageNumber = this.activatedRoute.snapshot.queryParams['page'];
and it worked fine in other cases ( I use it oft)
I guess the problem is in css, in this piece of code table.forth.td:nth-child, could you please tell me what would be the right way to access class within the table?

You should use pageNumber === 4 and not pageNumber = 4, because then you are just assigning the variable:
<table [ngClass]="{'before_forth': pageNumber < 4, 'forth': pageNumber === 4}">
The second problem is the css rule, you are using a .td class in there, even though it's nowhere used in the html. My guess is that you want to target the <td> element inside the table:
table.forth td:nth-child(2){background-color: green}
table.forth td:nth-child(5){background-color: green}
table.before_forth td:nth-child(2){background-color: red}
table.before_forth td:nth-child(5){background-color: red}
The third problem is the usage of {{item}} outside the <td> tag. This is invalid html and will result in unwanted behaviour, you should move this inside the td
Also, don't use id inside in combination with *ngFor. An element with an id is supposed to be unique throughout the entire page. Actually, it's better not to use id at all if you have no special use for it:
<table [class.before_forth]="pageNumber < 4" [class.forth]="pageNumber === 4">
<tr *ngFor="let item of itemsSource3; let i = index;">
<td *ngFor="let item2 of helper[i]; let j = index;">
<input class="resizedTextbox" name="{{i}}{{j}}" [(ngModel)]="helper[i}[j].value" (ngModelChange)="onValueChange(f,i)">
{{item}}
</td>
</tr>
</table>
The last point is, the proper spelling of 4th is fourth and not forth, but that's just an fyi ;)

Related

Weird behavior of css class in td with rowspan (Angular)

I'm using a custom css class called 'td-group' to customize td with a rowspan, to be more specific [attr.rowspan] since i'm using angular. In short words, the css style doesn't always get applied correctly, i've looked everywhere and tried everything and still didn't figure it out
The bug only occurs on chrome and never in edge
Here the image of the bug
<tr *ngFor="let r of list; let i = index">
<ng-container *ngIf="group && r.representative.show">
<td class="td-group" [attr.rowspan]="r.representative.height">
{{r.representative.name}}
</td>
</ng-container>
<td *ngFor="let c of cols">
{{r[c.name]}}
</td>
</tr>
Stackblitz https://stackblitz.com/edit/angular-yr3pxq?file=src/app/app.component.html

How to effectively use foreach in laravel-livewire in a table when the data dynamically changes?

I've been struggling with the foreach blade directive when combined with Laravel-Livewire and dynamically changing data rendered in an html table.
Specific scenario:
A table is presented to the user
Each row of the table includes a clickable icon that toggles a variable associated with that row
Toggling this icon visibly removes the row from the table
It sounds simple enough but I cannot get it to work correctly.
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class UnreconciledServices extends Component
{
public $services;
public function render()
{
return view('livewire.unreconciled-services');
}
//
// receives an invoice number and changes the "reconciled" value for the $aaaServices record to true
//
public function test($a)
{
}
}
This is pretty simple - there is a function called "test" that accepts a variable (the function does nothing at all) and there is a collection of records called $services that has been passed in from the parent.
The blade file is as follows:
<div>
<table style="width:100%">
<thead>
<tr>
<th width="5%">
</th>
<th>
Service Date
</th>
<th>
Call #
</th>
<th>
Payment
</th>
</tr>
</thead>
<tbody>
#foreach ($services as $service)
{{-- <span wire:key="{{$service->invoice_number}}"> --}}
{{-- #if ($service->reconciled == false) --}}
<tr id="{{$service->invoice_number}}" class="text-center" style="{{ $service->reconciled == 1 ? 'display:none' : 'show'}}">
<td>
{{-- <input class="m-2" type="checkbox"> --}}
{{-- <span class="m-2"><i class="far fa-trash-alt text-red-500"></i></span> --}}
<span wire:key="{{$service->invoice_number}}" wire:click="test('{{$service->invoice_number}}')" class="m-2 cursor-pointer"><i class="lm-2 rm-2 fas fa-plus text-green-500"></i></span>
</td>
<td>
{{$service->invoice_date}}
</td>
<td>
{{$service->call_number}}
</td>
<td>
{{$service->service_price}}
</td>
</tr>
{{-- #endif --}}
{{-- </span> --}}
#endforeach
</tbody>
</table>
</div>
This is a simple table with 4 columns. The 1st is a clickable icon, the other 3 are data. Rows should only be visible if the "reconciled" boolean is 0.
When initially rendered, the appropriate records are displayed (there are 2 that qualify and 177 that do not). However, as soon as I click the icon - even when the function it links to has zero actual content - all records are suddenly visible except for the one that I've just hidden.
Looking at the html change when I click the icon, the tag changes from
<tr id="21031251674" class="text-center" style="display:none">
to
<tr id="21031253205" class="text-center" style="show">.
I have tried using livewire keys, though I'm not sure how this would affect the functionality since I'm not rendering components, but rather data driven html.
Surely someone else has encountered this and overcome. Please point me in the right direction.
Sorry for the delay. This whole thread should be deleted as bone-headed. But it was written in earnest...
When all was said and done, I was unclear on the differences b/w an html / ajax - based approach such as livewire and something more javascript-based such as Vue. I was expecting functionality that didn't exist in the framework as I was attempting to use it.
To solve the problem, I moved towards individual row items being components in and of themselves, using emit to communicate between components and adjust the backend data source.
Once I embraced the html / ajax approach and stopped trying to force / expect javascript functionality & dom manipulation then all was well. Just a mindset difference from what I am familiar with, and it took me some time to turn the corner.

How to highlight a selected row in *ngFor?

I couldn't find something that will help me to solve this issue in Angular2. I'd like to set a css class when I select a row. (without using jQuery)
<table class="table table-bordered table-condensed table-hover">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Website</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of companies" (click)="selectedCompany(item, $event)">
<td>{{item.name}}</td>
<td>{{item.email}}</td>
<td>{{item.website}}</td>
</tr>
</tbody>
</table>
I'm using Angular2 final release
There are plenty of solutions to do this, one of them is you can store the current company when clicked.
In the *ngFor you check if the current item is the currentCompany and you add the class highlighted or whatever class you wish if its the same company.
export class TableComponent {
public currentCompany;
public selectCompany(event: any, item: any) {
this.currentCompany = item.name;
}
}
And then on your template:
<tr *ngFor="let item of companies" (click)="selectCompany($event, item)"
[class.highlighted]="item.name === currentCompany">
--
Another solution if you wish to have multiple highlighted companies you can add a property highlighted to your item. Then on selectCompany() you just set the property to true. On your check you do [class.highlighted]="item.highlighted".
I know this was answered a while ago, but to expand on the accepted answer, you could also use [ngClass]="{'class_name': item.id === currentCompany }". The table hover may need to be removed as it may hide the background color change
<tr *ngFor="let item of companies" (click)="selectCompany($event, item)" [ngClass]="{'class_name': item.id === currentCompany }" >
Then css
.class_name{ background-color: yellow; }

How do I change ng-class on window resize?

I have functionality where when I shrink the screen below a certain size and click on a table row it reveals other items in that table row. (white screen on left).
Then when I expand the window I want all table rows to return to normal, but I have a bug where if it's open already it won't close.
I tried setting the $scope.showIt variable to true/false, but it only seems to have an effect if it's the opposite of the initial $scope.showIt value. How do I change all the ng-classes in every td when the screen is a certain size?
This is my html:
<tr class="table-body "ng-repeat="service in services | orderBy:myOrderBy | filter:search">
<td align="center" valign="middle" ng-click="showIt = dropDetails(showIt)" ng-class="{'name-show':showIt, 'name-show-disabled':!showIt}">{{ service.name }}</td>
<td ng-class="{'show':showIt, 'show-disabled':!showIt}">{{ service.description }}</td>
<td ng-class="{'show':showIt, 'show-disabled':!showIt}">{{ service.prices }}</td>
</tr>
And in my controller:
$scope.dropDetails = function(showIt){ //This function works well.
console.log(window)
console.log(window.innerWidth)
if(window.innerWidth < 760){
return !showIt;
}else{
return showIt;
}
}
var w = angular.element($window);
var resizeId=0;
$scope.showIt = true;
w.bind('resize ', function (a) {
clearTimeout(resizeId);
resizeId = setTimeout(function(){
if(w[0].innerWidth < 760){
}else{
$scope.showIt = true; //Does nothing.
$scope.$apply();
}
}, 500);
})
Do use Dot Rule while defining ng-model in Angular view. So that will help you to follow prototypal inheritance while refering to there property.
The reason here is, you have used ng-repeat(which does create prototypically inherited child scope while rendering template each time on view). Here the same thing you need to do. Define model like $scope.model and inside that define showIt property. Rather you should put that showIt on each of you element of services, by which you handle each event individually.
Markup
<tr class="table-body" ng-repeat="service in services | orderBy:myOrderBy | filter:search">
<td align="center" valign="middle"
ng-click="service.showIt= dropDetails(service.showIt)"
ng-class="{'name-show':service.showIt, 'name-show-disabled':!service.showIt}">
{{ service.name }}
</td>
<td ng-class="{'show':service.showIt, 'show-disabled':!service.showIt}">
{{ service.description }}
</td>
<td ng-class="{'show':service.showIt, 'show-disabled':!service.showIt}">
{{ service.prices }}
</td>
</tr>
Now question remains how to hide all the services, so that would be very easy. Loop through each services collection element & make showIt variable as false.
angular.forEach($scope.services, function(service){
service.showIt = false;
})
Also you are using custom event on DOM, I'd suggest you to put this code in directive. So that can get reusable too.

Display selected checkbox values in div with jQuery

I have a series of checkboxes and I would like to append the text value to a div every time and item gets selected, but I'd also like to remove the item from the div's text when an item is deselected.
I'm guessing the best way would be with some sort of an array? Can I get some guidance on this one?
edit: I should have mentioned this is for an ASP.NET checkboxlist (my bad), so my output looks something like this:
<div id="ctl00_ContentPlaceHolder1_divServices" style="width:450px; height:250px; overflow-y:scroll;">
<table id="ctl00_ContentPlaceHolder1_chklstServices" border="0">
<tr>
<td><input id="ctl00_ContentPlaceHolder1_chklstServices_0" type="checkbox" name="ctl00$ContentPlaceHolder1$chklstServices$0" onclick="ToggleBGColour(this);" /><label for="ctl00_ContentPlaceHolder1_chklstServices_0">Adhesives & Sealants</label></td>
</tr><tr>
<td><input id="ctl00_ContentPlaceHolder1_chklstServices_1" type="checkbox" name="ctl00$ContentPlaceHolder1$chklstServices$1" onclick="ToggleBGColour(this);" /><label for="ctl00_ContentPlaceHolder1_chklstServices_1">Air Ambulance</label></td>
</tr><tr>
<td><input id="ctl00_ContentPlaceHolder1_chklstServices_2" type="checkbox" name="ctl00$ContentPlaceHolder1$chklstServices$2" onclick="ToggleBGColour(this);" /><label for="ctl00_ContentPlaceHolder1_chklstServices_2">Air Charter</label></td>
</tr>
</table>
</div>
<div id="selectedServices"></div>
I am actually trying to accomplish two things:
1) colorize (or remove color) of the cell background color when the checkbox is toggled (done this bit)
2) Append or remove the text of selected items when the checkboxes are checked/unchecked
My javascript/jquery code:
function ToggleBGColour(item) {
var td = $(item).parent();
if (td.is('.rowSelected'))
td.removeClass("rowSelected");
else
td.addClass("rowSelected");
}
You can use .map() and Array.join(), like this:
$(":checkbox").change(function() {
var arr = $(":checkbox:checked").map(function() {
return $(this).next().text(); //get the <label>'s text
}).get();
$("#myDiv").text(arr.join(','));
});
Whenever a checkbox changes, it'll loop through all checked checkboxes, create an array of their values, then put that as a comma delimited string into the <div>.
This is an example of course, just change the selectors to narrow down to the checkboxes you care about. You can give it a try here.

Resources