Я пытаюсь заставить сортировку таблицы работать для /users
, которая определена в UserListComponent
. Функциональность сортировки была нарушена из-за введения NavbarComponent
.
Я устал по возможности переключаться на автономные компоненты, как предложено в этом ответе. Я новичок в Angular, и, насколько я понимаю, @NgModule
в DemoMaterialModule
(main.ts) весьма полезен, поскольку мне не нужно импортировать каждый модуль материала в каждом компоненте.
Angular 18 продвигает автономный подход, поэтому, возможно, стоит пойти по этому пути.
Является ли это лучшим вариантом для моего варианта использования? Не лучше ли полностью перейти от моего гибридного подхода (автономный + модульный) к автономному?
Как заставить это работать?
ОБНОВЛЯТЬ:
Сортировка не работает. Обновлен код . Добавлены демонстрационные данные для легкого воспроизведения проблемы сортировки.
ОБНОВЛЕНИЕ 2:
Наконец-то всё заработало: Коммит GitHub
Спасибо за помощь! Код компилируется. Ошибка исчезла. Проблема в том, что сортировка не работает...
Ваши ответы были весьма полезны. Большое спасибо! Я принял ответы. Дело в том, что когда я пытаюсь починить одну деталь, другая ломается. (Может быть немного не по теме: external-preview.redd.it/…)
Я могу только указать решение, а не предоставить код без ошибок, это зависит от вас!
Во время преобразования автономного стиля в модульный мы используем в маршрутизации компоненты, которые не импортируются в AppModule, что чаще всего и вызывает проблему.
Я преобразовал все приложение в автономное, как было указано в предыдущем вопросе.
import {CdkTableModule} from '@angular/cdk/table';
import {NgModule} from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {bootstrapApplication, BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {MatAutocompleteModule} from "@angular/material/autocomplete";
import {MatButtonModule} from "@angular/material/button";
import {MatButtonToggleModule} from "@angular/material/button-toggle";
import {MatCardModule} from "@angular/material/card";
import {MatCheckboxModule} from "@angular/material/checkbox";
import {MatChipsModule} from "@angular/material/chips";
import {MatStepperModule} from "@angular/material/stepper";
import {MatDatepickerModule} from "@angular/material/datepicker";
import {MatDialogModule} from "@angular/material/dialog";
import {MatDividerModule} from "@angular/material/divider";
import {MatExpansionModule} from "@angular/material/expansion";
import {MatGridListModule} from "@angular/material/grid-list";
import {MatIconModule} from "@angular/material/icon";
import {MatInputModule} from "@angular/material/input";
import {MatListModule} from "@angular/material/list";
import {MatMenuModule} from "@angular/material/menu";
import {MatNativeDateModule, MatRippleModule} from "@angular/material/core";
import {MatPaginatorModule} from "@angular/material/paginator";
import {MatProgressBarModule} from "@angular/material/progress-bar";
import {MatProgressSpinnerModule} from "@angular/material/progress-spinner";
import {MatRadioModule} from "@angular/material/radio";
import {MatSelectModule} from "@angular/material/select";
import {MatSidenavModule} from "@angular/material/sidenav";
import {MatSliderModule} from "@angular/material/slider";
import {MatSlideToggleModule} from "@angular/material/slide-toggle";
import {MatSnackBarModule} from "@angular/material/snack-bar";
import {MatTabsModule} from "@angular/material/tabs";
import {MatToolbarModule} from "@angular/material/toolbar";
import {MatTooltipModule} from "@angular/material/tooltip";
import {MatTableModule} from '@angular/material/table';
import {provideHttpClient} from "@angular/common/http";
import {provideRouter, RouterModule} from '@angular/router';
import {AppComponent} from "./app/app.component";
import {CarListComponent} from "./app/cars-list/car-list.component";
import {CarComponent} from "./app/car/car.component";
import { routes } from './app/app.routes';
import {MatSortModule} from "@angular/material/sort";
import {UserCarsComponent} from "./app/user-cars/user-cars.component";
import {UserComponent} from "./app/user/user.component";
import {CommonModule} from "@angular/common";
import {MatFormFieldModule} from "@angular/material/form-field";
import { NavbarComponent } from './app/navbar/navbar.component';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { UserListComponent } from './app/user-list/user-list.component';
@NgModule({
exports: [
CdkTableModule,
MatAutocompleteModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatCheckboxModule,
MatChipsModule,
MatStepperModule,
MatDatepickerModule,
MatDialogModule,
MatDividerModule,
MatExpansionModule,
MatGridListModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatNativeDateModule,
MatPaginatorModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatRadioModule,
MatRippleModule,
MatSelectModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatSnackBarModule,
MatTableModule,
MatTabsModule,
MatToolbarModule,
MatTooltipModule,
MatDialogModule,
MatGridListModule,
MatSortModule,
MatFormFieldModule
]
})
export class DemoMaterialModule {}
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
DemoMaterialModule,
MatNativeDateModule,
ReactiveFormsModule,
RouterModule.forRoot(routes),
RouterModule,
CommonModule
],
declarations: [
AppComponent,
NavbarComponent,
UserListComponent,
UserComponent,
CarListComponent,
CarComponent,
UserCarsComponent,
],
bootstrap: [AppComponent],
exports: [
],
providers: [provideHttpClient()]
})
export class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule, {
ngZoneEventCoalescing: true
})
.catch(err => console.error(err));
Ниже приведены изменения кода для исправления сортировки. Если у вас возникнут сомнения, дайте мне знать.
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { MatSort, Sort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Car } from "../models/car.model";
import { ActivatedRoute, Router } from '@angular/router';
import { CarService } from '../services/car.service';
import { FormControl } from "@angular/forms";
import { debounceTime, takeUntil } from "rxjs/operators";
import { Subject } from 'rxjs';
function compare(a: number | string, b: number | string, isAsc: boolean) {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}
@Component({
selector: 'app-cars',
templateUrl: './car-list.component.html',
styleUrls: ['./car-list.component.css']
})
export class CarListComponent implements OnInit, AfterViewInit {
displayedColumns: string[] = ['id', 'make', 'model', 'numberplate'];
dataSource: MatTableDataSource<Car>;
cars: Car[] = [];
filterControl: FormControl = new FormControl('');
private ngUnsubscribe = new Subject<void>();
@ViewChild(MatSort) sort!: MatSort;
constructor(private carService: CarService,
private route: ActivatedRoute,
private router: Router) {
this.dataSource = new MatTableDataSource<Car>();
}
ngOnInit() {
this.initializeTable();
}
ngAfterViewInit() {
this.route.queryParams.pipe(takeUntil(this.ngUnsubscribe)).subscribe(params => {
const { find } = params;
this.filterControl.setValue(find || '');
this.applyFilter(find || '');
});
}
initializeTable() {
// Fetch cars from service
// this.carService.getCars().subscribe((data: Car[]) => {
// this.cars = data;
// this.dataSource.data = this.cars;
// });
// fake API call
this.cars = [
{
id: 1,
make: 'car1',
model: 'asdf1',
numberplate: '12344',
},
{
id: 2,
make: 'car2',
model: 'asdf2',
numberplate: 'h4r5ty',
},
{
id: 1,
make: 'car33',
model: 'asdf33',
numberplate: 'zxcvfbdf',
},
{
id: 1,
make: 'car45',
model: 'asdf45',
numberplate: 'asdfae',
}
];
this.dataSource.data = this.cars;
// Set filter predicate
this.dataSource.filterPredicate = (data, filter: string): boolean => {
return data.make.toLowerCase().includes(filter) || data.model.toLowerCase().includes(filter) || data.numberplate.toLowerCase().includes(filter);
};
// Subscribe to changes in the filter control with debounce
this.filterControl.valueChanges.pipe(
debounceTime(300),
takeUntil(this.ngUnsubscribe)
).subscribe(value => {
this.applyFilter(value);
});
}
applyFilter(filterValue: string) {
filterValue = filterValue.trim().toLowerCase();
this.dataSource.filter = filterValue;
// Update the URL with the new filter value or remove the parameter if the filter is empty
this.router.navigate([], {
relativeTo: this.route,
queryParams: filterValue ? { find: filterValue } : {},
queryParamsHandling: filterValue ? 'merge' : ''
});
}
applySort(sortState: Sort) {
const data = this.cars.slice();
if (!sortState.active || sortState.direction === '') {
this.dataSource.data = data;
return;
}
this.dataSource.data = data.sort((a, b) => {
const isAsc = sortState.direction === 'asc';
switch (sortState.active) {
case 'id':
return compare(a.id, b.id, isAsc);
case 'make':
return compare(a.make, b.make, isAsc);
case 'model':
return compare(a.model, b.model, isAsc);
case 'numberplate':
return compare(a.numberplate, b.numberplate, isAsc);
default:
return 0;
}
});
const sortField = sortState.active;
const sortDirection = sortState.direction as 'asc' | 'desc';
// Update the URL with the new sort value
this.router.navigate([], {
relativeTo: this.route,
queryParams: { sort: `${sortField}:${sortDirection}` },
queryParamsHandling: 'merge'
});
}
navigateToCarDetail(car: Car): void {
this.router.navigate(['/cars', car.id]);
}
}
@J.Olufsen обновил мой ответ!
Сортировка работает. Большое спасибо!
У вас такие же ошибки в консоли браузера? ОШИБКА TypeError: this.sort не определен.
@J.Olufsen закомментируйте эту строку, она не нужна
надеюсь это поможет!