Table row on click function is not working in Angular7 - html

I am trying to call a function whenever i click a row in an HTML table but it is not working and it is not giving any errors.
I've tried several things, and online code shows that the way i try it, it should be working.
My code is as following:
Html:
<h2>Userstories</h2>
<button (click)="onNewStory()">New Story</button>
<table>
<tr *ngFor="let story of userstories" ng-click="onUpdate(story)" [class.selected]="story === selectedStory">
<td>{{story.id}}</td>
<td>{{story.name}}</td>
<td><button ng-click="onUpdate(story)">Click me!</button></td>
</tr>
</table>
<app-userstory-detail [story]="selectedStory"></app-userstory-detail>
And my .ts looks like this:
selectedStory: UserStory;
onNewStory() {
var newStory = {id:this.userstories[this.userstories.length-1].id+1, name:"", description:"Deze is nieuw", status:"open", owner:USERS[1]};
this.userstories.push(newStory);
this.selectedStory = newStory;
}
onUpdate(userstory: UserStory): void {
this.selectedStory = userstory;
console.log(this.selectedStory);
}
Currently my console is not printing the log, when i try to call the onUpdate method. The expected result is to see some output in the logs, but i have no clue why it is not firing the onUpdate method.

In angular 7 you can use (click) which is similar to ng-click of Angular JS.
Try:
<h2>Userstories</h2>
<button (click)="onNewStory()">New Story</button>
<table>
<tr *ngFor="let story of userstories" (click)="onUpdate(story)" [class.selected]="story === selectedStory">
<td>{{story.id}}</td>
<td>{{story.name}}</td>
<td><button (click)="onUpdate(story)">Click me!</button></td>
</tr>
</table>
<app-userstory-detail [story]="selectedStory"></app-userstory-detail>
StackBlitz Demo

ng-click is actually for AngularJS (1.x)
You want to use (click) which is for Angular.
DOCUMENTATION: https://angular.io/guide/ajs-quick-reference#ng-click

The event is fired twice. In <tr> and in <button>.
Try this:
<h2>Userstories</h2>
<button (click)="onNewStory()">New Story</button>
<table>
<tr *ngFor="let story of userstories" [class.selected]="story === selectedStory">
<td>{{story.id}}</td>
<td>{{story.name}}</td>
<td><button (click)="onUpdate(story)">Click me!</button></td>
</tr>
</table>
<app-userstory-detail [story]="selectedStory"></app-userstory-detail>

Related

Angular checkbox gets updated even though ngModel doesn't

I'm working on a shift arrangement app. In it I'm trying to create two tables that show which possible shifts each user has selected.
Both tables display the same data, but arrange it differently. Each table cell has a number of check-boxes that display the possible shifts for each person (in table 1) or the possible people for a shift (in table 2). A checkbox from table 1 that displays shift A option for person X will have the same data-bind as its equivalent checkbox in table 2, which displays person X option for shift A.
The purpose of this is to update the equivalent data in both tables simultaneously when the user couples a person with a shift. The problem: when a checkbox in table 1 is checked/unchecked, all of the check-boxes in table 2 gets checked/unchecked, as shown below:
Here is my template:
<div class="table-container" dir="ltr">
<h3>People</h3>
<table>
<thead>
<th>Name</th>
<th>Options</th>
</thead>
<tbody>
<tr *ngFor="let user of userPreferences">
<td>{{user.name}}</td>
<td>
<div *ngFor="let selection of userYesses[user.name]">
<mat-checkbox class="option-checkbox" dir="ltr" [(ngModel)]="selection.isSelected" name="usc">{{selection.option}}</mat-checkbox>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="table-container" dir="ltr">
<h3>Shifts</h3>
<table>
<thead>
<th>Time</th>
<th>Options</th>
</thead>
<tbody>
<tr *ngFor="let shift of totalShifts">
<td dir="ltr">{{shift.time}}</td>
<td>
<div *ngFor="let selection of shiftYesses[shift.time]">
<mat-checkbox class="option-checkbox" [(ngModel)]="selection.isSelected" name="syc">{{selection.name}}</mat-checkbox>
</div>
</td>
</tr>
</tbody>
</table>
</div>
And here is relevant component code:
this.userPreferences.forEach(u => {
this.userYesses[u.name] = [];
u.preferences.shifts.forEach(week => {
week.forEach(day => {
if (!day.shifts) return;
day.shifts.forEach(shift => {
if (!this.shiftYesses[`${day.date} ${shift.time}`]) this.shiftYesses[`${day.date} ${shift.time}`] = [];
if (shift.isSelected) {
let selection = new Selection(`${day.date} ${shift.time}`, u.name);
this.userYesses[u.name].push(selection);
this.shiftYesses[`${day.date} ${shift.time}`].push(selection);
}
});
});
});
});
The code seems alright to me, am I missing anything? Maybe it's a bug in Angular?
Thanks in advance!
In case anyone else experiences this issue -
After a few days of struggling with this, I stumbled upon this issue from Angular's git - https://github.com/angular/angular/issues/9230
I've read the following in kara's answer:
In the case that you don't want to register a form control, you currently have a few options:
1 - Use ngModel outside the context of a form tag. This will never throw.
<input [(ngModel)]="person.food">
After reading this, I switched the <form> tag into a <div> and everything works as expected now.

show a string from backend-server as icon

I get a response from backend server for my angular 2/4 application. The response includes an attribute "connectionStatus", which indicates the status of a database-connection with "UP" or "DOWN". I show the retrieved status and other informations in my view with the following code:
<tbody>
<tr *ngFor='let database of environment.databases'>
<td>{{database.connectionName}}</td>
<td>{{database.dbSourceType}}</td>
<td>{{database.username}}</td>
<td>{{database.password}}</td>
<td>{{database.connectionUrl}}</td>
<td>{{database.creationDate}}</td>
<td>{{database.connectionStatus}}</td>
<td>
<button (click)='onEditDatabase(environment,database)'class="btn btn-primary btn-sm oi oi-cog"></button>
<button (click)='onDeleteDatabase(database)'class="btn btn-danger btn-sm oi oi-trash"></button>
</td>
</tr>
</tbody>
Instead of showing the status as "UP" or "DOWN", i want to use openiconics. If the state is "UP", then use the check-icon, if its down, the flash-icon. How can i realize that? i appreciate all help.
Make use of ngClass
<td [ngClass]="(database.connectionStatus ==='UP')?'upclass':'downclass'"></td>
in the css define the class and icons
.upclass{check-icon}
.downclass{flash-icon}
You can use *ngIf or [hidden] to display one of the status as per your condition.
<td *ngIf="database.connectionStatus">your icon UP html tag here</td>
<td *ngIf="!database.connectionStatus">your icon DOWN html tag here</td>

Angular 2: how to hide a field in table and show when mouse hover?

I have this simple Angular2/html table:
<tr *ngFor="let item of mf.data; let i = index;">
<td><input type="checkbox" value="" [(ngModel)]="item.checked" ></td>
<td>{{i}}</td>
<td>{{item.name}}</td>
<td>{{item.password}}</td>
<td>{{item.number}}</td>
<td>Infos</td>
<td><button type="button" class="btn btn-success" [disabled]="!item.checked">start</button></td>
</tr>
I would like to hide field password with ***** or ....., but display clear text when mouse hovers in and hide when mouse hovers out. Basically, I is sensitive data and I don't want some one to be able to take a photo when I open my app. How can I do this ?
Use the mouseover and mouseout events and bind a display variable to them.
E.g.:
<td (mouseover)="displayPassword = true" (mouseout)="displayPassword = false">{{displayPassword? item.password : '****'}}</td>
maybe something like this could do the trick :
// not working <td title="{{item.password}}">{{item.password.split('').forEach(p => '*')}}</td>
<td title="{{item.password}}">******</td>
I have finally found something that work find. Fill free to improve this solution.
Basically I added an index to every of my rows.
<td align="center" (mouseover)="displayPassword(item.index)" (mouseout)="hiddePassword(item.index)">{{item.showpassword? item.password:'00000000000000000000000000000000000'}}</td>
In my app.component.ts, I added this two functions:
displayPassword(index){
console.log(index)
this.data[index].showpassword = true;
}
hiddePassword(index){
this.data[index].showpassword = false;
}
now it is working as expected ...

Angular 2 save all changes from grid

I need to save all changes from editable fields in table.
<tbody>
<tr *ngFor="let a of arr; let i = index">
<td contenteditable>{{a.text}}</td>
<td contenteditable type="number" pattern="[0-9]">{{a.number}}</td>
</tr>
</tbody>
<button class="btn btn-success" (click) = "saveAllChanges()">Save all </button>
--
saveAllChanges(){
for(let a of this.arr){
this.myservice.updateRepeat(r)
}
}
Objects in array arent saved after edit on grid so it doesnt work.
Any idea how can i save all changes?

Angular Ng-If Ng-Style not changing the table font colour

I have the following code which is an ionic list which populates the data retrieved. Im trying to colour code it into different colours based on the Status reponse.
<ion-list>
<ion-item ng-repeat="test in tests" class ="item-text-wrap" style="height:40%">
<a href="#/tab/test/test-detail/{{test.ID}}">
<div style="width:80%; float:left;">
<table>
<span ng-if="test.Status == 'Cleared'" ng-style="color:green">
<tr>
<td> <strong>Remark: </strong></td>
<td style="padding:3px">{{test.Remark}}</td>
</tr>
<tr>
<td><strong>Status:</strong></td>
<td style="padding:3px">{{test.Status}}</td>
</tr>
</span>
</table>
</div>
</ion-item>
</ion-list>
But the colour of the table data still does not change. What could be the problem? Am i using the ng-if and ng-style wrongly? Thanks!
Update 1: Using the insights provided by #SSH, i updated my controller with the following codes:
Html:
<ion-list>
<ion-item ng-repeat="test in tests" class ="item-text-wrap" style="height:40%">
<a href="#/tab/test/test-detail/{{test.ID}}">
<div style="width:80%; float:left;">
<table>
<span ng-style="calculateStyle()">
<tr>
<td> <strong>Remark: </strong></td>
<td style="padding:3px">{{test.Remark}}</td>
</tr>
<tr>
<td><strong>Status:</strong></td>
<td style="padding:3px">{{test.Status}}</td>
</tr>
</span>
</table>
</div>
</ion-item>
</ion-list>
Controller:
$scope.calculateStyle = function() {
var style={}
console.log('test3: '+$scope.tests.Status);
console.log('test6: '+$scope.Status);
if ($scope.Status == 'Cleared') {
style.color='green';
console.log('Viola');
}
else{
console.log('GG');
}
return style;
}
})
But the result returned in the controllers are still null/undefined. test3 and test6 returned me 'undefined' while the If statement returned me 'GG'. What could be the problem? Thanks!
Update 2: Using SSH answers, i modified to the following:
Html:
<span ng-style="calculateStyle(test)">
Controller:
$scope.calculateStyle = function(test) {
var style={}
if (test.Status == 'Cleared') style.color='green';
return style;
}
But the test variable at the controller is still undefined. Using $scope.test doesn't work too. What could be the problem?
Yes you do use it wrongly. You need to pass an object consisting of style names and conditions:
<span ng-style="{color:(test.Status == 'Cleared')?'green'}">
or better use a function in your controller to calculate and return style object, to keep your template clean:
<span ng-style="calculateStyle(test)">
and then in your controller definition
$scope.calculateStyle = function(test) {
var style={}
if (test.Status == 'Cleared') style.color='green';
return style;
}