Cosmic Plantation Matrix Classification Or Arrangement

I am currently utilizing angular 9 along with Nebular v6.1.0 in my project. One issue I have encountered is related to filtering and sorting data displayed using the nebular TreeGridComponent. When dealing with basic data types such as strings or numbers, filtering and sorting work seamlessly for every property of the object. However, complications arise when the object contains complex data types like another object. It appears that filtering based on the properties of this nested object is not straightforward, even though displaying them is not a problem. To elaborate further, consider the following example:

import { Component } from '@angular/core';
import { NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder } from '@nebular/theme';

interface FSEntry {
  name: string;
  myObject: MyObject;
}

interface MyObject {
    myObjectName: string;
}

@Component({
  template: `
    <nb-card>
      <nb-card-body>

        <table [nbTreeGrid]="source" nbSort (sort)="changeSort($event)">
          <tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="allColumns"></tr>
          <tr nbTreeGridRow *nbTreeGridRowDef="let row; columns: allColumns"></tr>

          <!-- this row is sortable -->
          <ng-container nbTreeGridColumnDef="name">
                <th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef [nbSortHeader]="getDirection('name')">Name</th>
                <td nbTreeGridCell *nbTreeGridCellDef="let row">
                    row.data.name
                </td>
          </ng-container>

          <!-- this row is NOT sortable -->
          <ng-container nbTreeGridColumnDef="myObjectName">
                <th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef [nbSortHeader]="getDirection('myObjectName')">MyObjectName</th>
                <td nbTreeGridCell *nbTreeGridCellDef="let row">
                    row.data.myObject.myObjectName
                </td>
          </ng-container> 
        </table>

      </nb-card-body>
    </nb-card>
  `,
  styleUrls: ['./tree-grid-shared.scss'],
})
export class TreeGridComponent {
  defaultColumns = [ 'name', 'myObjectName' ];
  allColumns = [ ...this.defaultColumns ];
  source: NbTreeGridDataSource<FSEntry>;

  constructor(dataSourceBuilder: NbTreeGridDataSourceBuilder<FSEntry>) {
    const getters: NbGetters<FSEntry, FSEntry> = {
      dataGetter: (node: FSEntry) => node,
      childrenGetter: (node: FSEntry) => node.childEntries || undefined,
      expandedGetter: (node: FSEntry) => !!node.expanded,
    };
    this.source = dataSourceBuilder.create(this.data, getters);
  }

  getDirection(column: string): NbSortDirection {
    if (column === this.sortColumn) {
      return this.sortDirection;
    }
    return NbSortDirection.NONE;
  }

  changeSort(sortRequest: NbSortRequest): void {
    this.dataSource.sort(sortRequest);
    this.sortColumn = sortRequest.column;
    this.sortDirection = sortRequest.direction;
  }

  private data: FSEntry[] = [
    {
        name: 'name 1', 
        myObject: {
            myObjectName: 'myObjectName 1'
        }
    },
    {
        name: 'name 2', 
        myObject: {
            myObjectName: 'myObjectName 2'
        }
    }
  ];
}

This code allows sorting the name row, but not the myObjectName row. Are there any solutions to enable sorting without having to move properties from MyObject to FSEntry?

Answer №1

If you're struggling, here's a suggestion: Develop a unique class that extends NbTreeGridFilterService

import { NbTreeGridFilterService } from '@nebular/theme';

export class CustomTreeGridFilterService<T> extends NbTreeGridFilterService<T> {

    protected filterPredicate(data: T, searchQuery: string): boolean {

        const preparedQuery = searchQuery.trim().toLocaleLowerCase();
        for (const val of Object.values(data)) {

            const prepVal = this.prepValue(val);

            const preparedVal = `${prepVal}`.trim().toLocaleLowerCase();
            if (preparedVal.includes(preparedQuery)) {
                return true;
            }
        }

        return false;
    }

    prepValue(value): string[] {
        const x = [];
        const isObject = typeof value === 'object' && value !== null;
        if (!isObject) {
            x.push(value);
        } else {
            for (const val of Object.values(value)) {
                x.push(this.prepValue(val));
            }
        }

        return x;

    }
}

After that, in your component, use it as shown below

constructor() {
const filterService = new CustomTreeGridFilterService<Client>();
const sortService = new NbTreeGridSortService<Client>();
const treeGridService = new NbTreeGridService<Client>();
const treeGridDataService = new NbTreeGridDataService<Client>();
const dataSourceBuilder = new NbTreeGridDataSourceBuilder<Client>(filterService, sortService, treeGridService, treeGridDataService);}

For sorting, a similar approach can be taken.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

In Deno, it is possible to confirm that a variable is an instance of a String

I'm having trouble asserting instances of string in Deno: import { assertInstanceOf } from "https://deno.land/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2642405050405e445e59445e">[email protected]</a& ...

Error in Angular 8: Property 'name' is undefined and cannot be read

Delving into the world of Angular, I encountered an interesting error: ERROR TypeError: Cannot read property 'name' of undefined. Here's the snippet of code: recipe-list.component.ts import { Component, OnInit } from '@angular/core&ap ...

My tests are unable to execute on the test database due to the lack of a defined service

I am currently trying to execute my test file in NestJS. My goal is to connect to a test database and run my service with it. However, I am facing an issue where my service is undefined and the method service.findById is also undefined. How can I obtain an ...

The issue with transferring state does not seem to be resolved in Angular 17, causing problems with APIs being accessed

During my project, I successfully implemented SSR and the transfer state feature on Angular 15 version. The APIs were called from the server side without any issues. However, when I migrated to Angular 17, I encountered a problem where the transfer state n ...

The loading template remains visible despite the Eventsource being closed when using the Async Pipe

How can I resolve the issue I'm facing with the Angular async pipe and event source while using Spring boot WebFlux? I need to display a "loading data" message until the API call is complete. Once the API fetches data, I want to show the retrieved dat ...

Unable to access or modify NGXS state within an Angular 8 NativeScript application

After gaining experience with Angular, I decided to experiment with the NGXS data store while following a NativeScript tutorial. Despite trying several NGXS tutorials, I couldn't get the state to update without any errors from Android Studio or NS. N ...

Creating modern web applications using Angular and .Net Core with the power of Bootstrap 4

Has anyone experimented with developing an application using the following commands? dotnet new --install Microsoft.AspNetCore.SpaTemplates::* dotnet new angular You can find an example of this at this link. By default, the command creates an Angular + ...

Using Angular 6 shortcodes in HTML

Is there a way to save an element in HTML as an alias for repeated use in Angular 6 without using *ngIf directive? For instance, consider the following code snippet: <dumb-comp [name]="(someObservable | async).name" [role]="(someObservable | a ...

Creating TypeScript Unions dependent on a nested object's property

I want to create a Union Type that is dependent on a nested property within my object. Take a look at the example provided below: type Foo = { abilities: { canManage: boolean } } type Bar = { abilities: { canManage: boolean ...

Dynamic autocomplete in Oclif utilizing an HTTP request

Is it feasible for Oclif to support the functionality of making API calls to retrieve values for autocomplete? Consider this scenario: A database stores multiple users information Upon typing show users <Tab> <Tab>, the CLI triggers an API ca ...

When selecting an ion-tab-button in Ionic 4, the color does not change as expected

One of my challenges involves implementing an ion-tab that allows different ways of redirection: either through Routes specified in the tabs.module.ts file or by using [routerLink] directly in the HTML. The issue I am facing is that when the ion-tab-butto ...

Transforming a JSON file that has been previously converted to an Observable into a TypeScript map within an Angular application

There is a json data file named dummy, with the following structure: [ {"key":"KEY1", "value":["alpha","beta","gamma"]}, {"key":"KEY2", "value":["A","B","C"]}, {"key":"KEY3", "value":["One","Foo","Bar"]} ] The goal is to convert this json f ...

React Routing: Unleashing the Power of Multi-Level Routing

In my quest to create a route with multiple levels (<Route path="/hello/world" element={<a>hello world</a>} />), I encountered a few issues. Here are the versions I am using: react: 18.1 react-router-dom: 6.3.0 Success with O ...

Tips on updating icons automatically

Incorporating Ionic Angular, Font Awesome, and Stripe into my app, I encounter a challenge. I aim to dynamically change the icon on the HTML page based on data received from the server in the .ts page. This is the current setup: <ion-item *ngFor="let ...

Which approach is more effective: utilizing a single event binding with several functions or multiple event bindings with just one function?

Which format is better: <a (click)="f1(); f2()"> or <a (click)="f1()" (click)="f2()">? The order does not matter to me, and I prefer not to create an additional function to call both. ...

Creating dynamic HTML with Angular 2 using property binding

After retrieving an HTML string from the database, I came across html='<span>{{name}}</span>' where 'name' is a component property. I am looking to display this string in HTML while maintaining the name binding. I have expl ...

Creating a Fixed HeaderToolbar in FullCalendar React

I am currently working on customizing the FullCalendar React component and I am looking to incorporate a sticky headerToolbar. My main objective is to have the header along with its toolbar remain fixed at the top of the calendar, even when users scroll th ...

Navigating on button click in Angular 5

Is there a way to navigate to a home component when the user clicks a button without using routerLink? I know how to do it with <a href=””>, but not with routerLink. Can this be achieved by utilizing a button click event? <a class="nav-item n ...

The ngx-datatable is designed to bind only to the final comparator

When utilizing templates with ngx-datatable-column and binding comparator functions, only the final bound comparator is applied to all sortable columns. For instance: <div class="m-333"> <button mat-raised-button color="primary" (click)="openP ...

How can you create a unique record by appending a number in Javascript?

Currently, when a file already exists, I add a timestamp prefix to the filename to ensure it is unique. However, instead of using timestamps, I would like to use an ordinal suffix or simply append a number to the filename. I am considering adding an incr ...