Applying an ngClass on only 1 element of a table in angular - html

In my table, I'm attempting to add a read more button to each row that has a paragraph. The button is displayed for each row, and when I click one, it operates concurrently for each row.
Here is my code:
<table class="table">
<thead>
<tr>
<th scope="col">Text</th>
<th scope="col">Date</th>
<th scope="col">Comments</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of posts[0].posts">
<div [ngClass]="{'limitTextHeight': isReadMore}">
<td>{{p.post_text}}</td>
</div>
<button type="button" (click)="showText()" style="margin-top:15px">
{{ isReadMore ? 'Read More': 'Read Less' }}
</button>
<td>{{p.post_date}}</td>
<td>{{p.post_comments.length}} comment</td>
</tr>
</tbody>
</table>
and my showText() function:
showText() {
this.isReadMore = !this.isReadMore
}

This is happening because you're using single boolean variable i.e, isReadMore for all the looped tr tag.
What you can do is posts[0].posts map this posts with one more key that can be anything for example isReadMore in your case, then you will get unique instance to handle for each para, like this.
{{ p?.isReadMore ? 'Read More': 'Read Less' }}.
Hope you understood what I'm trying to say.

You are using a common variable for all the rows. That's why when you click one they all change. You should use local ones, one for each row like so:
<table class="table">
<thead>
<tr>
<th scope="col">Text</th>
<th scope="col">Date</th>
<th scope="col">Comments</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of posts[0].posts">
<div [ngClass]="{'limitTextHeight': isReadMore}">
<td>{{p.post_text}}</td>
</div>
<button type="button" (click)="showText(p)" style="margin-top:15px">
{{ p.isReadMore ? 'Read More': 'Read Less' }}
</button>
<td>{{p.post_date}}</td>
<td>{{p.post_comments.length}} comment</td>
</tr>
</tbody>
</table>
and the showText() function:
showText(post) {
post.isReadMore = !post.isReadMore
}
You could also add an *ngIf to check if there is text long enough before showing the button:
<button type="button" *ngIf="p.post_text?.length > 20" (click)="showText(p)" style="margin-top:15px">
{{ p.isReadMore ? 'Read More': 'Read Less' }}
</button>

Related

ERROR Error: dataKey must be defined to use row expansion

I'm trying to figure out how to use Row Expansion in PrimeEng. I was just following the guide in their documentation and it shows that I should define my datakey. I already defined it below if I'm not mistaken. I'm new to this, please don't judge.
<p-table [value]="users" [paginator]="true" [rows]="10" [showCurrentPageReport]="true"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries"
[rowsPerPageOptions]="[10, 25, 50]">
<ng-template pTemplate="header">
<tr>
<th style="width:2rem">blank</th>
<th style="width:1rem">ID</th>
<th style="width:8rem">Name</th>
<th style="width:8rem">Username</th>
<th style="width:8rem">Email</th>
<th style="width:8rem">Street</th>
<th style="width:8rem">Suite</th>
<th style="width:8rem">City</th>
<th style="width:8rem">Zip code</th>
<th style="width:8rem">LAT</th>
<th style="width:8rem">LNG</th>
<th style="width:8rem">Phone</th>
<th style="width:8rem">Website</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-user let-expanded="expanded">
<tr>
<td>
<!-- <button type="button" pButton pRipple (click)="viewPostUser(user.id)" class="p-button-text p-button-rounded p-button-plain" ></button> -->
<button type="button" pButton pRipple [pRowToggler]="posts" (click)="viewPostUser(user.id)" class="p-button-text p-button-rounded p-button-plain" [icon]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></button>
</td>
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.username}}</td>
<td>{{user.email}}</td>
<td>{{user.address.street}}</td>
<td>{{user.address.suite}}</td>
<td>{{user.address.city}}</td>
<td>{{user.address.zipcode}}</td>
<td>{{user.address.geo.lat}}</td>
<td>{{user.address.geo.lng}}</td>
<td>{{user.phone}}</td>
<td>{{user.website}}</td>
</tr>
</ng-template>
Here is my row expansion ng-template.
<ng-template pTemplate="rowexpansion" let-posts>
<tr>
<td colspan="7">
<div class="p-p-3">
<p-table [value]="posts.userId" [dataKey]="posts.userId">
<ng-template pTemplate="header">
<tr>
<th style="width:4rem">userID</th>
<th style="width:4rem">ID</th>
<th style="width:4rem">Title</th>
<th style="width:4rem">Body</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-posts>
<tr>
<td>{{posts.userId}}</td>
<td>{{posts.id}}</td>
<td>{{posts.title}}</td>
<td>{{posts.body}}</td>
<td><p-button type="button" icon="pi pi-search"></p-button></td>
</tr>
</ng-template>
</p-table>
</div>
</td>
</tr>
</ng-template>
I've tried searching the error that I have, but it points me to updating the version.
I think here is where you get it wrong:
[value]="posts.userId" [dataKey]="posts.userId"
[value] is the collection that you want to iterate through, which should be posts in this case
[dataKey] is the property of one item in that collection which you could just define by name: userId
So the final code is:
[value]="posts" [dataKey]="userId"
First, to fix the error you're seeing, add the attribute dataKey="id" to the p-table element.
Next, using let-posts is probably not what you wanted. You didn't write how your data structure is constructed but I'll assume each user has a property called posts. You need to change your template like this:
<ng-template pTemplate="rowexpansion" let-user>
<tr>
<td colspan="7">
<div class="p-p-3">
<p-table [value]="user.posts" dataKey="id">
<ng-template pTemplate="header">
<tr>
<th style="width:4rem">userID</th>
<th style="width:4rem">ID</th>
<th style="width:4rem">Title</th>
<th style="width:4rem">Body</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-post>
<tr>
<td>{{post.userId}}</td>
<td>{{post.id}}</td>
<td>{{post.title}}</td>
<td>{{post.body}}</td>
<td><p-button type="button" icon="pi pi-search"></p-button></td>
</tr>
</ng-template>
</p-table>
</div>
</td>
</tr>
</ng-template>
Explanation:
Use let-user in the rowexpansion template. Now the user variable will contain the user data for the current expandable row.
In the inner p-table, provide the [value] input with the data for the sub table, i.e., the posts for the current user.
In the inner p-table, provide the dataKey input with the name of the field which is the unique key of the table. This might be even not necessary in your case.
In the inner p-table, in the body template, use let-post instead of let-posts since each iteration, i.e., each row of the inner table showing posts for the user, will store the current row, which is a single post.
In each <td> element in the inner table's body template, use post.<field-name>. post will contain the data for the current row so all you need to do is access the field you need inside the object.
You can add dataKey in first line, like this
<p-table [value]="users" dataKey="name">
Maybe it will solve your problem.

How to align text input elements within the boundaries of a table?

Working with some Jinja code in my Flask app, I have a
<table class="table table-hover">
<thead>
<th scope="col" class="text-primary">Name</th>
<th scope="col" class="text-primary">Description</th>
</thead>
<tbody class="text-secondary">
{% for item in char.inventory %}
<tr id="{{item.itemid}}_row">
<div>
<td id="{{item.itemid}}_name">{{item.name}}</td>
</div>
<div>
<td id="{{item.itemid}}_description">{{item.description}}</td>
</div>
<td class="text-right"><button id="{{item.itemid}}" class="btn btn-outline-info" onclick="itemeditor(this)">edit</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
A loop that generates a table that's formatted with some bootstrap. The button when clicked on, leads to some JQuery code that transforms the item and description table entries into text inputs, containing the values of the table entries.
function itemeditor(elem) {
self = $(elem);
itemid = self.attr("id");
itemnamenode = $("#" + itemid + "_name")
itemdescriptionnode = $("#" + itemid + "_description")
itemnamefield = $('<input type="text" style="display : inline;" size="50" class="form-control" />')
itemnamefield.val(itemnamenode.text())
itemdescfield = $(('<input type="text" style="display : inline;" size="50" class="form-control" />'))
itemdescfield.val(itemdescriptionnode.text())
itemnamenode.replaceWith(itemnamefield)
itemdescriptionnode.replaceWith(itemdescfield)
}
The issue is that when the JQuery updates the table entries with their text inputs, the text inputs default to talking up the full width of the table and going under each other rather than spawning next to each other, in the original location of the table entries.
Before the button gets clicked
After the button is clicked
How can I set up the Bootstrap/ CSS such that the text inputs line up with the table?
Thank you very much for all and any help
Your table is not correct.
You can't put div as a closest child of tr.
Let try with this
<tbody class="text-secondary">
{% for item in char.inventory %}
<tr id="{{item.itemid}}_row">
<td>
<div id="{{item.itemid}}_name">{{item.name}}</div>
</td>
<td>
<div id="{{item.itemid}}_description">{{item.description}}</div>
</td>
<td class="text-right"><button id="{{item.itemid}}" class="btn btn-outline-info"
onclick="itemeditor(this)">edit</button>
</td>
</tr>
{% endfor %}
</tbody>
I'm thinking another way.
You don't need to replace the element.
Try to use input only, disabled as default, and only enable it when in editing mode, and also rememeber to style disabled input as a text.

ckeckbox does not appear in my table cell

I try to create a table that containt checkbox using laravel blade .
But checkbox does not appear in the table.
this is my code:
#section('content')
<div class="container">
<table class="table table-striped">
<thead>
<tr>
<th>Survey</th>
<th>Date</th>
<th>Published</th>
<th>Creator</th>
<th>seen</th>
</tr>
</thead>
<tbody>
#foreach($surveys as $survey)
<tr {!! !$survey->seen && session('statut') == 'admin'? 'class="warning"' : '' !!}>
<td>{{$survey->title}}</td>
<td>{{$survey->created_at->todatestring()}}</td>
<td>{!! Form::checkbox('active', $survey->id, $survey->active) !!}</td>
#foreach($users as $user)
#if($user->id == $survey->user_id)
<td>
{{$user->name}}
</td>
#endif
#endforeach
<td>{!! Form::checkbox('seen', $survey->id, $survey->seen) !!}</td>
<td><button type="button" class="btn btn-info">Detail</button></td>
</tr>
#endforeach
</tbody>
</table>
</div>
#endsection
help me please!thank you in advance
Please use in this way.
{{ Form::checkbox('agree', 'yes') }}
Refer to this URL
I've tried your code and the checkbox works fine without problem as long as you already done all of this things correctly.
Install & setup Laravel Collective (https://laravelcollective.com/docs/master/html)
$surveys already sent from your controller with its data
$survey->seen contains boolean value (true/false)

AngularDart ng-repeat in tables?

I'm trying to iterate over lists with sublists, and printing them as <tr> without much success.
This code illustrates what i want to accomplish:
<table>
<tr>
<th>1</th>
<th>2</th>
<th>3</th>
</tr>
<span ng-repeat='x in [["a1","a2"],["b1","b2"],["c1","c2"]]'>
<tr>{{x.length}}<tr>
<span ng-repeat='y in x'>
<tr>{{y}}<tr>
</span>
</span>
</table>
I would expect this to show:
<table>
<tr>3</tr>
<tr>a1</tr>
<tr>a2</tr>
<tr>b1</tr>
// and so on..
</table>
what should i do to make this work? I want to be able to repeat without the need to put in spans..
Only table tags (td, th, tr, tbody...) inside of <table> tag are shown, you should add ng-repeat to <tr>
If you use angular1.2 or higher you can use ng-repeat-start and ng-repeat-end tags:
html:
<table ng-controller="apiCtrl">
<tr ng-repeat-start="item in foo" ng-init="first=item[0]">
<td>first: {{ first }}</td>
</tr>
<tr ng-repeat-end ng-init="last = item[1]">
<td>last: {{ last }}</td>
</tr>
</table>
js:
function apiCtrl($scope) {
$scope.foo = [
['one', 'uno'],
['two', 'dos'],
['three', 'tres']
];
}
Here is JSfiddle
Here is fiddle with nested lists
This question is really old and AngularDart has changed a lot in the meantime. We can use the <ng-container> tag to apply all kinds of directives to a group of tags which are to be repeated or put under an *ngIf and so forth. The <ng-container> tag will not appear in the DOM output, but its contents will be there and affected by the specified directive.
<table>
<ng-container *ngFor="let row of matrix">
<tr>
<ng-container *ngFor="let value of row">
<td>{{value}}</td>
</ng-container>
<tr>
</ng-container>
</table>
When your component.dart has:
List<List<int>> get matrix => [[1, 2, 3], [4, 5, 6]];

Using multiple ngrepeat in one html element / or workaround?

I want to make a table like below:
<table>
<thead>
<tr>
<th rowspan="2" ng-repeat="item in someitems">{{ item.title }}</th>
<th colspan="{{ group.items.length }}" ng-repeat="group in some_item_groups">{{ group.title }}</th>
</tr>
<tr>
<th ng-repeat="item in (group in some_item_groups).items">{{ item.title }}</th>
</tr>
</thead>
<tbody>
...
</tbody>
</table>
(I tried to add table pic here but don't have enough reputation points.)
Is there any way to draw this type of table with angular ng-repeat?