datatable.net in Angular not recognize the tr inside the table - javascript

this is my problem, sometimes the component render the table like this.
(No problems):
(Problem):
In the 2 photo you can see the empty row generated by datatables, it means the datatable not recognize the rows and this implies the datatable options like search or pageLength dont work. What i should do?
This is my table component:
Template:
<div class="table-responsive">
<table datatable [dtOptions]="dtOptions" class="table table-hover" [ngClass]="extraClass" width="100%">
<thead>
<tr>
<th *ngFor="let column of columns">{{ column }}</th>
</tr>
</thead>
<tfoot *ngIf="footer">
<tr>
<th *ngFor="let column of columns">{{ column }}</th>
</tr>
</tfoot>
<tbody>
<ng-content></ng-content>
</tbody>
</table>
</div>
Component:
import { Component, Input, OnChanges, OnInit } from '#angular/core';
import { datatableLanguage } from "../../data/index";
#Component({
selector: 'app-table',
templateUrl: './table.component.html'
})
export class TableComponent implements OnInit, OnChanges {
#Input()
public columns: Array<string>;
#Input()
public extraClass: string;
#Input()
public footer: boolean;
public dtOptions: DataTables.Settings;
constructor() {
this.columns = new Array<string>(0);
this.extraClass = '';
this.footer = true;
this.dtOptions = {};
}
ngOnInit() {
this.checkRequiredFields();
this.dtOptions = {
"language": datatableLanguage,
"responsive": true
}
}
ngOnChanges() {
this.checkRequiredFields();
}
checkRequiredFields(): void {
if(this.columns.length <= 0)
throw new Error("Attribute 'columns' is required.");
}
}
And if you need it, the father component:
Table template part:
<app-table id="ingredientsTable" [columns]="['Nombre', 'Precio/Unidad', 'Cantidad', 'Acciones']" [footer]="ingredients.length >= 10">
<tr [class.table-danger]="ingredient.amount <= 0" *ngFor="let ingredient of ingredients">
<td class="align-middle">{{ ingredient.name }}</td>
<td class="align-middle text-center">{{ ingredient.priceByUnit | number }}</td>
<td class="align-middle text-center">{{ ingredient.amount | number }}</td>
<td>
<div class="text-center">
<div class="btn-group">
<button class="btn btn-info" (click)="changeModal(ingredient)" data-toggle="modal" data-target="#modalIngredients">
<i class="far fa-edit"></i>
</button>
<button class="btn btn-danger" (click)="deleteIngredient(ingredient)">
<i class="far fa-trash-alt"></i>
</button>
</div>
</div>
</td>
</tr>
</app-table>

Related

Add <a>-tag behavior to <tr>-tag (Angular)

does someone know how to make a html -row with a routerlink clickable, with the option to open it in the same tab OR a new tab (ctrl + click). The problem that I encountered is, that you can't wrap the 'tr'-tag in a 'a'-tag. Thanks for any suggestions.
<tbody *ngFor="let item of defaultInvoicesList?._embedded.items">
<tr [routerLink]="this.getDetailsPath(item.legacyInvoiceId)" role="link">
<td>{{item.locationName}}</td>
<td>{{item.customerName}}</td>
<td><a [routerLink]="[getOrderDetailsUri(item.orderNumber)]">{{item.orderNumber}}</a></td>
<td>{{item.invoiceNumber}}</td>
<td>{{item.invoicePeriodStart | date: 'dd.MM.yyyy' }} - {{item.invoicePeriodEnd | date: 'dd.MM.yyyy' }}</td>
<td>{{item.createdByLastName}}, {{item.createdByFirstName}}</td>
</tr>
</tbody>
You can do something like this, although when you ctrl click, it both navigates and opens in new tab, but you can eliminate that with a few tweaks!
ts
import {
Component,
Input,
ChangeDetectionStrategy,
ViewEncapsulation,
Output,
EventEmitter,
} from '#angular/core';
import { Router } from '#angular/router';
import { Config } from './config';
import { DataTable } from './data';
import { PageRequest } from './pageRequest';
#Component({
selector: 'my-table',
templateUrl: 'table.component.html',
styleUrls: ['table.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
})
export class MyTableComponent {
constructor(private router: Router) {}
#Input()
public config: Config;
#Input()
public data: DataTable<any>;
public size = 5;
public pageNumber = 0;
#Output()
public newPage: EventEmitter<PageRequest> = new EventEmitter<PageRequest>();
#Output()
public selection: EventEmitter<number> = new EventEmitter<number>();
public changePage(pageNum: number) {
const num =
pageNum < 0
? 0
: pageNum >= this.data.lastPage
? this.data.lastPage - 1
: pageNum;
this.pageNumber = num;
this.newPage.emit({
page: num,
size: Number(this.size),
});
}
public onSelect(index: number) {
this.selection.emit(index + this.pageNumber * this.size);
}
emulateHref(link, event) {
event.preventDefault();
console.log(event);
this.router.navigate([link]).then((result) => {
if (event.ctrlKey) {
window.open(window.location.href, '_blank');
}
});
}
}
html
<table class="my-table">
<thead class="my-table headers">
<tr>
<th *ngFor="let column of config">{{ column.header }}</th>
</tr>
</thead>
<tbody class="my-table body">
<tr
my-active
*ngFor="let row of data.data; index as rowIndex"
(click)="emulateHref('details/' + rowIndex, $event)"
>
<td
*ngFor="let column of config; index as i"
[ngClass]="{ last: i === config.length - 1 }"
>
{{ row[column.value] }}
</td>
</tr>
</tbody>
</table>
<div class="pag-space">
<button type="button" class="pag-button" (click)="changePage(0)"><<</button>
<button
type="button"
class="pag-button"
(click)="changePage(this.pageNumber - 1)"
>
<
</button>
<select
class="size-page"
[(ngModel)]="size"
(change)="changePage(this.pageNumber)"
>
<option selected value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
</select>
<button
type="button"
class="pag-button"
(click)="changePage(this.pageNumber + 1)"
>
>
</button>
<button
type="button"
class="pag-button"
(click)="changePage(this.data.lastPage)"
>
>>
</button>
</div>
forked stackblitz
<tbody *ngFor="let item of defaultInvoicesList?._embedded.items">
<a href="">
<tr [routerLink]="this.getDetailsPath(item.legacyInvoiceId)" role="link">
<td>{{item.locationName}}</td>
<td>{{item.customerName}}</td>
<td><a [routerLink]="[getOrderDetailsUri(item.orderNumber)]">{{item.orderNumber}}</a></td>
<td>{{item.invoiceNumber}}</td>
<td>{{item.invoicePeriodStart | date: 'dd.MM.yyyy' }} - {{item.invoicePeriodEnd | date: 'dd.MM.yyyy' }}
</td>
<td>{{item.createdByLastName}}, {{item.createdByFirstName}}</td>
</tr>
</a>
</tbody>
With the help of #naren-murali answer, I was able to find a solution. Just add a click-event to the 'tr'-element. That what it contains:
Ts:
emulateHref(link, event) {
event.preventDefault();
if (event.ctrlKey) {
window.open(link, '_blank');
} else {
window.open(link, "_self")
}
}
HTML:
<tbody *ngFor="let item of defaultInvoicesList?._embedded.items">
<tr (click)="this.emulateHref(this.getDetailsPath(item.legacyInvoiceId), $event)">
<td>{{item.locationName}}</td>
<td>{{item.customerName}}</td>
<td><a [routerLink]="[getOrderDetailsUri(item.orderNumber)]">{{item.orderNumber}}</a></td>
<td>{{item.invoiceNumber}}</td>
<td>{{item.invoicePeriodStart | date: 'dd.MM.yyyy' }} - {{item.invoicePeriodEnd | date: 'dd.MM.yyyy' }}</td>
<td>{{item.createdByLastName}}, {{item.createdByFirstName}}</td>
</tr>
</tbody>

Validation of HTML table cell and changing background color using Javascript

This is HTML table and I want to validate it in such a way that if user clears entry, the background color of particular cell should be turned red. Code for model should be in JavaScript or Typescript. Please don't provide jQuery solutions
app.component.html
<table class="material-table">
<thead>
<tr>
<th></th>
<!-- <th *ngFor="let schema of tableSchema">
{{ schema.field }}
</th> -->
</tr>
</thead>
<tr *ngFor="let rowData of tableData">
<td value="Delete" (click)="deleteRow(rowData)">X</td>
<td
*ngFor="let schema of tableSchema"
[class.red-text]="!rowData[schema.field].valid"
>
<span
#el
contenteditable
(blur)="rowData[schema.field].value = el.innerText"
>
{{ rowData[schema.field].value }}
</span>
</td>
</tr>
</table>
You can use Attribute directives:
JS
import { Directive, ElementRef, HostListener, KeyValueDiffers } from '#angular/core';
#Directive({
selector: '[requiredHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef) { }
color = "red";
#HostListener('input') onChange() {
this.highlight();
}
private highlight() {
const color = this.el.nativeElement.innerHTML ? null: this.color;
this.el.nativeElement.style.backgroundColor = color;
}
}
HTML Template:
<td *ngFor="let schema of tableSchema">
<span #el contenteditable requiredHighlight (blur)="rowData[schema.field].value = el.innerText" >
{{ rowData[schema.field].value }}
</span>
</td>
Use NgClass.
<td *ngFor="let schema of tableSchema" [ngClass]="{'red-text':!rowData[schema.field].valid}">
<span #el contenteditable (blur)="rowData[schema.field].value = el.innerText">
{{ rowData[schema.field].value }}
</span>
</td>

Angular-6 dynamic add and remove column not render proper data

In my project I have dynamic row add and remove column demo link here
The drop-down of key contains database and desktop. Based on the drop-down of key the value drop-down will be changed.
My issue: When I click 1st row it seems good. But when I move on to 2nd row the data append not properly
Eg:
In 1st row I select Database,value should append ['mysql', 'oracle', 'mongo']
In 2nd row I select desktop, value should append ['dell', 'lenovo', 'hp']
app.component.html
<div class="container" style="margin-top: 5%">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Action</th>
<th>key</th>
<th>value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let dynamic of dynamicArray; let i = index;">
<td (click)="deleteRow(i)">
<i class="fa fa-trash fa-2x"></i>
</td>
<td>
<select [(ngModel)]="dynamicArray[i].title1" class="form-control" #sel (change)="changed(sel.value)">
<option [value]='1'>Database</option>
<option [value]='2'>Desktop</option>
</select>
</td>
<td>
<select [(ngModel)]="dynamicArray[i].title2" class="form-control">
<option *ngFor="let data of dropdownData;">{{data}}</option>
</select>
</td>
</tr>
<tr>
<td (click)="addRow(0)">
<i class="fa fa-plus fa-2x"></i>
</td>
</tr>
</tbody>
</table>
</div>
app.component.ts
import { Component, VERSION, OnInit } from "#angular/core";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
dynamicArray: Array<any> = [];
newDynamic: any = {};
dbValue= ['mysql', 'oracle', 'mongo'];
desktopValue = ['dell', 'lenovo', 'hp'];
dropdownData:any = [];
ngOnInit(): void {
this.newDynamic = {title1: "", title2: ""};
this.dynamicArray.push(this.newDynamic);
}
addRow(index) {
this.newDynamic = {title1: "", title2: ""};
this.dynamicArray.push(this.newDynamic);
console.log(this.dynamicArray);
return true;
}
deleteRow(index) {
if(this.dynamicArray.length ==1) {
return false;
} else {
this.dynamicArray.splice(index, 1);
return true;
}
}
changed(value) {
if(value == 1){
this.dropdownData = this.dbValue;
}
if(value == 2){
this.dropdownData = this.desktopValue;
}
}
}
Please help me on this issue. Thanks in advance.
You need to add dropdownData to dynamicArray every time when you are adding a new row. Try this
<div class="container" style="margin-top: 5%">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Action</th>
<th>key</th>
<th>value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let dynamic of dynamicArray; let i = index;">
<td (click)="deleteRow(i)">
<i class="fa fa-trash fa-2x"></i>
</td>
<td>
<select [(ngModel)]="dynamicArray[i].title1" class="form-control" #sel (change)="changed(sel.value, i)">
<option [value]='1'>Database</option>
<option [value]='2'>Desktop</option>
</select>
</td>
<td>
<select [(ngModel)]="dynamicArray[i].title2" class="form-control">
<option *ngFor="let data of dynamicArray[i].dropdownData;">{{data}}</option>
</select>
</td>
</tr>
<tr>
<td (click)="addRow(0)">
<i class="fa fa-plus fa-2x"></i>
</td>
</tr>
</tbody>
</table>
</div>
app.component.ts
import { Component, VERSION, OnInit } from "#angular/core";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
dynamicArray: Array<any> = [];
newDynamic: any = {};
dbValue = ["mysql", "oracle", "mongo"];
desktopValue = ["dell", "lenovo", "hp"];
ngOnInit(): void {
this.newDynamic = { title1: "", title2: "", dropdownData: [] };
this.dynamicArray.push(this.newDynamic);
}
addRow(index) {
this.newDynamic = { title1: "", title2: "", dropdownData: [] };
this.dynamicArray.push(this.newDynamic);
console.log(this.dynamicArray);
return true;
}
deleteRow(index) {
if (this.dynamicArray.length == 1) {
return false;
} else {
this.dynamicArray.splice(index, 1);
return true;
}
}
changed(value, index) {
let dropdownData;
if (value == 1) {
this.dynamicArray[index].dropdownData = this.dbValue;
}
if (value == 2) {
this.dynamicArray[index].dropdownData = this.desktopValue;
}
}
}
Stackblitz link : https://stackblitz.com/edit/angular-ivy-psdnpa?file=src/app/app.component.ts

Angular 4: Ng2SearchPipeModule using this module for the search. Not working properly on the Data in Numeric

import { Injectable } from '#angular/core';
import { IFavContactSchema } from './favSchema';
#Injectable({
providedIn: 'root'
})
export class FavContactServiceService {
allContactDetails:IFavContactSchema[] = [
{
first_name:"neha",middle_name:"singh",last_name:"sengar",email:"neha.singh931126#gmail.com",mobile_number:9898989898,phone_number:8989898989,notes:"Add to my faver",calling_rate:"frequent"
},
{
first_name:"sonal",last_name:"trivedi",email:"sonal.trivedi#gmail.com",mobile_number:9092312345,phone_number:8989898989,notes:"Add to my onme",calling_rate:"frequent"
},
{
first_name:"oshin",last_name:"sharma",email:"oshin.sharma#gmail.com",mobile_number:9522335434,phone_number:8989898989,notes:"Add to my tow",calling_rate:"frequent"
},
{
first_name:"karasadn",last_name:"sdasd",email:"karan.veer#gmail.com",mobile_number:8839367967,phone_number:8989898989,notes:"Add to my three",calling_rate:"non_frequent"
},
{
first_name:"kunil",last_name:"sharma",email:"kanul.sharma#gmail.com",mobile_number:9097854322,phone_number:8989898989,notes:"Add to my four",calling_rate:"frequent"
},
{
first_name:"kane",last_name:"jain",email:"ranie.jain#gmail.com",mobile_number:8989673422,phone_number:8989898989,notes:"Add to my five",calling_rate:"frequent"
},
{
first_name:"sane",last_name:"sharma",email:"punit.deer#gmail.com",mobile_number:9000000000,phone_number:8989898989,notes:"Add to my six",calling_rate:"non_frequent"
},
];
constructor() { }
addContacts(details:IFavContactSchema){
this.allContactDetails.push(details);
return "Data Added Successfully";
}
getAllContacts(){
return this.allContactDetails;
}
deleteContact(i){
this.allContactDetails.splice(i, 1);
}
getContact(i){
return this.allContactDetails[i];
}
updateContact(i,updatedContact){
this.allContactDetails[i] = updatedContact;
}
}
TS
import { Component, OnInit } from '#angular/core';
import { IFavContactSchema } from '../favSchema';
import { FavContactServiceService } from '../fav-contact-service.service';
#Component({
selector: 'app-favourites-list',
templateUrl: './favourites-list.component.html',
styleUrls: ['./favourites-list.component.css']
})
export class FavouritesListComponent implements OnInit {
key: string = 'first_name'; //set default
reverse: boolean = false;
p: number = 1;
favContactLists:IFavContactSchema[];
constructor(private favConService:FavContactServiceService) { }
ngOnInit() {
this.favContactLists = this.favConService.getAllContacts();
}
deleteContact(i:Number){
this.favConService.deleteContact(i);
}
sort(key){
this.key = key;
this.reverse = !this.reverse;
}
}
HTML
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div class="container">
<h2>Fav Contacts</h2>
<nav class="navbar">
<input class="form-control" type="text" name="search" [(ngModel)]="filter">
</nav>
<table class="table">
<thead>
<tr>
<th>#</th>
<th (click)="sort('first_name')">Name
<span class="glyphicon sort-icon" *ngIf="key =='name'" [ngClass]="{'glyphicon-chevron-up':reverse,'glyphicon-chevron-down':!reverse}"></span>
</th>
<th (click)="sort('email')">Email</th>
<th (click)="sort('calling_rate')">Calling Rate</th>
<th (click)="sort('mobile_number')">Mobile Number</th>
<th>Actions</th>
</tr>
</thead>
<tbody *ngIf="favContactLists?.length > 0; else no_record">
<tr *ngFor="let contact of favContactLists| filter:filter | orderBy: key : reverse| paginate: { itemsPerPage: 5, currentPage: p };let i=index">
<td>{{ i+1 }}</td>
<td>{{ contact.first_name + " " }}{{contact.middle_name ? contact.middle_name : ""}}{{ " " + contact.last_name }}</td>
<td>{{ contact.email }}</td>
<td *ngIf="contact.calling_rate == 'frequent'; else non_frequent" >{{ "Frequent" }}</td>
<ng-template #non_frequent><td>{{ "Non Frequent" }}</td></ng-template>
<td >{{ contact.mobile_number }}</td>
<td><a [routerLink]="['/edit', i+1]">
<span class="glyphicon glyphicon-pencil"></span>
</a>
<a (click) = "deleteContact(i)">
<span class="glyphicon glyphicon-trash"></span>
</a>
</td>
</tr>
</tbody>
<ng-template #no_record>
<tbody>
<td colspan="5" class="active cen" align="center">No Record Found</td>
</tbody>
</ng-template>
<pagination-controls (pageChange)="p = $event"></pagination-controls>
</table>
</div>
</body>
</html>
I am new to Angular facing a small issue.
Using the Ng2SearchPipeModule for the search It is working fine for the Data in string but not with the data in Number. I am attaching the Screenshot below...
For some search scenario working fine but for some not.
Please Help.
There are two images one with the normal search and one in which all the records are there even if it doesnot match the filtering criteria

how to create dynamic row in a table javascript angular 2

I am creating a table based on dropdown selection. I am able to display the data for a single selection. I want to create a function for "new button" which will add a row and selected value will be display in new generated row. how can I achieve this using javascript or angular 2.
P.S.I am just a beginner. thanks in advance.
Screenshot
import { NgModule } from '#angular/core';
import { Component, OnInit } from '#angular/core';
import {SelectItem} from 'primeng/primeng';
import { FormsModule } from '#angular/forms';
import {ButtonModule} from 'primeng/primeng';
import {DataTableModule,SharedModule} from 'primeng/primeng';
#Component({
selector: 'app-test',
templateUrl: 'app/test/test.component.html',
styleUrls: ['app/test/test.component.css']
})
export class TestComponent implements OnInit {
makes: SelectItem[];
selectedMake: string;
motors: SelectItem[];
selectedMotorType: string;
poles: SelectItem[];
selectedPole: string;
}
constructor() {
this.makes = [];
this.makes.push({label:'Select makes', value:null});
this.makes.push({label:'Siemens', value:{id:1, name: 'Siemens', code: 'Siemens'}});
this.makes.push({label:'ABS', value:{id:2, name: 'ABS', code: 'ABS'}});
this.motors = [];
this.motors.push({label:'Select Motor Type', value:null});
this.motors.push({label:'IE1', value:{id:11, name: 'IE1', code: 'IE1'}});
this.motors.push({label:'IE2', value:{id:12, name: 'IE2', code: 'IE2'}});
this.motors.push({label:'IE3', value:{id:13, name: 'IE3', code: 'IE3'}});
this.poles = [];
this.poles.push({label:'Select Pole Type', value:null});
this.poles.push({label:'2 Pole', value:{id:21, name: '2Pole', code: '2Pole'}});
this.poles.push({label:'4 Pole', value:{id:22, name: '4Pole', code: '4Pole'}});
this.poles.push({label:'6 Pole', value:{id:23, name: '6Pole', code: '6Pole'}});
}
//code for button click new row generate
rows = [{name: ''}];
name = "new";
addRow() {
this.rows.push({name: this.name});
}
//=================
private textValue = "initial value";
private log: string ='result';
private kw: string = 'kw';
private frame: number = 0;
DisplayResult(){
if(this.selectedMake.name=='ABS' && this.selectedMotorType.name=='IE1' ){
alert(this.selectedMake.name);
this.log = 'IABVC5Z' '\n'
this.kw = 'new' '\n'
}}
<div class="container row">
<div class="col-sm-6">
<p class="col-sm-3" >Makes :</p>
<p-dropdown class="col-sm-4" [options]="makes" [(ngModel)]="selectedMake" [style]="{'width':'200px'}" ></p-dropdown>
</div>
</div>
<br>
<div class="container row">
<div class="col-sm-6">
<p class="col-sm-3" >Motor Type :</p>
<p-dropdown class="col-sm-4" [options]="motors" [(ngModel)]="selectedMotorType" [style]="{'width':'200px'}" ></p-dropdown>
</div>
</div>
<br>
<div class="container row">
<div class="col-sm-6">
<p class="col-sm-3" >Pole Type :</p>
<p-dropdown class="col-sm-4" [options]="poles" [(ngModel)]="selectedPole" [style]="{'width':'200px'}" ></p-dropdown>
</div>
</div>
<div class="col-sm-4">
<button class="" pButton type="button" class="ui-button-danger" (click)="addRow()" label = " Add New Motor"></button>
<button class="" pButton type="button" (click)="DisplayResult()" label="Display Result"></button>
</div>
<table id="t01">
<tr>
<th>S.No.</th>
<th>Qty</th>
<th>Type Refrence</th>
<th>KW Rating</th>
<th>Frame Size</th>
<th>Voltage</th>
<th>Frequency</th>
<th>Features</th>
</tr>
<tr *ngFor=" let row of rows">
<td>1</td>
<td><input type="qty" name="qty"></td>
<td>{{log}}</td>
<td>{{kw}}</td>
<td>{{frame}}</td>
<td>415 v</td>
<td>50 Hz</td>
<td></td>
</tr>
</table>
All you need to do is write a function/method inside the component and then call that function/method in the click event if you select the add button
#Component({...})
export class TestComponent {
addRow() {
this.rows.push({
make : this.make,
model: this.model,
pole: this.pole
});
}
The addRow fires when the button is clicked
<button class="" pButton type="button" class="ui-button-danger" (click)="addRow()" label = " Add New Motor">Add New Motor</button>
I also added text between the button tags for display. You must update your table to select the appropriate values to display
<table id="t01">
<tr>
<th>S.No.</th>
<th>Qty</th>
<th>Type Refrence</th>
<th>KW Rating</th>
<th>Frame Size</th>
<th>Voltage</th>
<th>Frequency</th>
<th>Features</th>
</tr>
<tr *ngFor=" let row of rows">
<td>{{ row.make.name }}</td>
<td><input type="qty" name="qty" [row.model]></td>
<td>{{ row.model.log }}</td>
<td>{{ row.model.kw}}</td>
<td>{{ row.model.frame }}</td>
<td>{{ row.model.somethingElse }}</td>
<td>{{ row.pole.simething }}</td>
<td>{{ row.pole.etc }}</td>
</tr>
</table>
I didn't know your data, so just us m selected values from random fields, but that is how you would typically do that

Categories