Cannot create property 'selected' on string, using ngModel with Angular - html

so I'm trying to use [(ngModel)] like this:
<div class="items">
<tbody>
<tr *ngFor="let account of this.accounts">
<td>
<input type="checkbox" [(ngModel)]="this.account.name.selected" name="account">
{{account.name}}
</td>
</tr>
</tbody>
</div>
My accounts is created and filled in the component: accounts: Account[] = [];
My Account object:
export class Account {
name: string;
surname: string;
}
I'm getting ERROR TypeError: Cannot create property 'selected' on string 'John'
I saw this thread: Cannot create property 'selected' on string 'Information Technology' angularjs But didn't quite understand how to apply mentioned fix to my case, maybe because I'm using Angular and not AngularJS. Would be glad if anyone could help a bit understanding the problem here?

It looks like you need to have selected property in your array. So to avoid polluting Account class, you can use map method:
let withSelectedProperty = this.accounts.map(s=> ({...s, selected: false}));
And HTML:
<tr *ngFor="let account of withSelectedProperty">
<td>
<input type="checkbox" [(ngModel)]="account.selected" name="account">
{{account.name}}
</td>
</tr>
UPDATE:
You can use method filter to get all selected values:
let onlySelected = this.withSelectedProperty.filter(f => f.selected);

Related

How to bind data with ngFor in angular

I am new to angular. Just learning it.
I want to bind data with ngFor. but its not showing any data. Kindly help me to solve this
html file :
<tbody class="text-center">
<tr *ngFor="let agent of agentlist ;let i = index">
<td>{{i + 1 + paginationObject?.page * paginationObject?.itemPerPage}}</td>-->
<td>{{agent?.id?agent?.id:''}}</td>
</tr>
</tbody>
error : <!--bindings={ "ng-reflect-ng-for-of": null }-->
Try removing the --> at the end of the first table cell and correct the binding on the second one.
<tbody class="text-center">
<tr *ngFor="let agent of agentlist ;let i = index">
<td>{{i + 1 + paginationObject?.page * paginationObject?.itemPerPage}}</td>-->
<td>{{agent?.id}}</td>
</tr>
</tbody>
Also, you need to make sure that agentlist has something to iterate. maybe putting a console.log(agentlist) and see what it has inside of it in the ts class. If angelist is only declared but never defined you will get that error. Initialize angelist as an empty array to make sure that have an iterable before defining with the final data.

HTML 5 Angular 10: Display array attribute values using EXL

I'm trying to display user info using HTML and Angular 10, here my User Object:
export interface User {
email: string;
password: string;
userName: string;
roles: Role[];
}
export interface Role {
name: string;
}
Here's my html code
<tbody>
<tr *ngFor="let user of users" >
<td>{{user.name}}</td>
<td>{{user.username}}</td>
<td>{{user.email}}</td>
<td>{{user.password}}</td>
<td>{{user.roles}}</td>
</tr>
</tbody>
How can i get Role.names for every User separated by ",".
like:
name username email password role
user adminName admin#mail.com admin123 ADMIN, MODERATOR, USER
Create separate function where you can get generated value for displaying
function getUserRoles(roles) {
return roles.map((role) => role.name).join(‘ ,’)
}
<td>{{getUserRoles(user.roles)}}</td>
EDITED:
My way of doing this is another *ngFor at the end of the table, something like this:
<tbody>
<tr *ngFor="let user of users" >
<td>{{user.name}}</td>
<td>{{user.username}}</td>
<td>{{user.email}}</td>
<td>{{user.password}}</td>
<td *ngFor="let role of user.roles">
{{role.name}}
</td>
</tr>
</tbody>
You have to use some CSS to properly display the last row and add a comma as well.

Angular write data lines dynamically to a table

In my project I getting the data from JSONPlaceholder - Users
I'm new in Angular, so if you find something stupid in the way I get the data please warn me.
dataFromServer;
constructor(private http: HttpClient){
this.dummyPromise.then(
response => {
console.log("response from dummy promise:", response);
this.dataFromServer = response;
},
error => {
console.log("Error happened with dummy promise:", error)
}
)
}
dummyPromise = new Promise((resolve, reject) => {
this.http.get('https://jsonplaceholder.typicode.com/users').subscribe(data => {
console.log(data);
this.dataFromServer = data;
});
//resolve(returnData);
});
Problem is, in my HTML file, I write the data into a table like this:
<tr *ngIf="dataFromServer">
<td>{{dataFromServer[0].id}}</td>
<td>{{dataFromServer[0].name}}</td>
<td>{{dataFromServer[0].username}}</td>
<td>{{dataFromServer[0].email}}</td>
</tr>
<tr *ngIf="dataFromServer">
<td>{{dataFromServer[1].id}}</td>
<td>{{dataFromServer[1].name}}</td>
<td>{{dataFromServer[1].username}}</td>
<td>{{dataFromServer[1].email}}</td>
</tr>
... for all the 10 people. I want to do it dynamically, as many lines as many people's data I get.
I think that you should try to use *ngFor instead of *ngIf. I will give you an example.
<tr *ngFor="let data of dataFromServer">
<td>{{data.id}}</td>
<td>{{data.name}}</td>
<td>{{data.username}}</td>
<td>{{data.email}}</td>
</tr>
So, it will repeat for every object in your dataFromServer
use ngFor to iterate on an array of data:
<table *ngIf="dataFromServer">
<tr *ngFor="let item of dataFromServer">
<td>{{item.id}}</td>
...
</tr>
</table>
the ngIf condition on the table will prevent console errors/rendering issues if dataFromServer is null/undefined before receiving from your API
You can replace your html code as bellow
<tr *ngFor="let row of dataFromServer">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.username}}</td>
<td>{{row.email}}</td>
</tr>
You can use *ngFor to do it. It's pratically a for in the html. As an example we assume that we have a component like this :
private users: User[] = [];
ngOnInit(){
this.service.getUser()
.subscribe(userList => {
this.users = userList;
});
}
The User class :
export class User {
public id: number;
public name: string;
}
You can use the *ngFor in your html like this way :
<span *ngFor="let user of users">
UserID: {{user.id}} - User Name: {{user.name}}
</span>
So basically, related to your code, just put in an object of User the json data you get from the http call, then modify the html like this way :
<tr *ngFor="let user of users">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
.....
</tr>

Dynamically add property to object in angularjs ng-repeat

I have a list of object and iterating that list using ng-repeat to generate table row. each td contains source name and checkbox. I want to bind the checkbox with a property which is not available into list. how that is possible? The list is like that:-
scope.reasons = [
{sourceName:'Lack of rainfall'},
{ sourceName: 'Change in land use' },
{sourceName:'Change in Land Cover'}
];
and the HTML code is like that:-
<table>
<tr ng-repeat="source in reasons">
<td>{{source.sourceName}}</td>
<td><input type="checkbox" ng-checked="source.postAdequate"></td>
</tr>
</table>
You can do this using the ng-model attribute, ng-change is just for the checking purposes that is change detection.
<table>
<tr ng-repeat="source in reasons">
<td>{{source.sourceName}}</td>
<td>
<input type="checkbox" ng-model="source.postAdequate" ng-change="changeDet()">
</td>
</tr>
</table>
Demo Fiddle
Hope this helps
Try this:
<input type="checkbox" ng-model="source.postAdequate">
See here jsfiddle link:
https://jsfiddle.net/avnesh2/5cpm48tc/2/
But it will add source.postAdequate: true/false only if you click, remains objects will remains same.
So if you want to add source.postAdequate: true/false in all add in $scope.reasons before only.
Hope this will help you.
Using ng-model instead of ng-checked will add property internally when checkbox is changed
<input type="checkbox" ng-model="source.postAdequate"></td>
If you must have that property on all objects iterate the array and add it
scope.reasons.forEach(function(item){
item.postAdequate = false
})
Can you loop the scope object once to initially set postAdequate:false for all items. Then bind that object in checkbox ng-model.
angular.forEach($scope.reasons, function(e,i){
e.postAdequate = false;
});
html code
<table>
<tr ng-repeat="source in reasons">
<td>{{source.sourceName}}</td>
<td>
<input type="checkbox" ng-model="source.postAdequate" ng-click="clickfunction(source.postAdequate)">
</td></tr>
</table>

Angular 2 DataBinding displaying a list in same <td></td>

I am new to Angular2 so any help is much appreciated.
I am getting data in the form of a list<user>. Each user has a list of roles. So in typescript I created this user type:
export class User {
id: string;
firstName: string;
middleName: string;
lastName: string;
email: string;
roles: Role[];
}
I am parsing the data in above type form. 'users' is an array users: Array<User>; in that component.
Displaying the data I want to list out Role[] into comma separated values in like <td>admin, customer, writer</td>,
but what I am getting instead is:
<td>admin</td>
<td>customer</td>
<td>writer</td>
Here is the code I am trying:
<tr *ngFor="let user of users">
<td>{{user.id}}</td>
<td>{{user.firstName +' '+ user.middleName+' '+user.lastName}}</td>
<td>{{user.email}}</td>
<td *ngFor="let role of Role">{{role.name}}</td>
<td><button type="button" class="btn btn-primary " (click)="roleOnClick(user)"></button></td>
</tr>
How can I achieve something like <td> admin, customer, writer</td>?
<td *ngFor="let role of roles">{{role.name}}</td>
That line above says to repeat the <td> tag for each element of the Role array, which is why you're getting the behaviour that you're seeing.
If you just want to get a comma separated list of roles, you may just want to use a simple function call on the role array, for eg:
<td> {{ roles.join(', ') }} </td>
join is a function on the standard JavaScript Array class that allows you to combine the elements of the array simply. The parameter to the function is the text you want to place between each member of the array.