Adding a chip per genre (only loading genres once)

This commit is contained in:
Zoe Roux 2020-09-14 23:34:47 +02:00
parent 8d5ee797ec
commit e4621bbdea
5 changed files with 202 additions and 94 deletions

View File

@ -40,6 +40,7 @@ import {MatAutocompleteModule} from "@angular/material/autocomplete";
import {MatExpansionModule} from "@angular/material/expansion"; import {MatExpansionModule} from "@angular/material/expansion";
import {InfiniteScrollModule} from "ngx-infinite-scroll"; import {InfiniteScrollModule} from "ngx-infinite-scroll";
import {ShowGridComponent} from "./components/show-grid/show-grid.component"; import {ShowGridComponent} from "./components/show-grid/show-grid.component";
import {MatBadgeModule} from "@angular/material/badge";
@NgModule({ @NgModule({
@ -87,7 +88,8 @@ import {ShowGridComponent} from "./components/show-grid/show-grid.component";
MatChipsModule, MatChipsModule,
MatAutocompleteModule, MatAutocompleteModule,
MatExpansionModule, MatExpansionModule,
InfiniteScrollModule InfiniteScrollModule,
MatBadgeModule
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })

View File

@ -1,6 +1,9 @@
<div class="container-fluid justify-content-center" *ngIf="this.sortEnabled"> <div class="container-fluid justify-content-center" *ngIf="this.sortEnabled">
<button mat-icon-button matTooltipPosition="below" matTooltip="Filter"> <button mat-icon-button matTooltipPosition="below" matTooltip="Filter" [matMenuTriggerFor]="filterMenu">
<mat-icon>filter_list</mat-icon> <mat-icon [matBadge]="this.filters.length.toString()" [matBadgeHidden]="this.filters.length == 0"
matBadgeColor="warn" matBadgeSize="small">
filter_list
</mat-icon>
</button> </button>
<button mat-button matTooltipPosition="below" matTooltip="Sort" [matMenuTriggerFor]="sortMenu"> <button mat-button matTooltipPosition="below" matTooltip="Sort" [matMenuTriggerFor]="sortMenu">
<mat-icon>sort</mat-icon> Sort by {{this.sortType}} <mat-icon>sort</mat-icon> Sort by {{this.sortType}}
@ -9,6 +12,12 @@
</button> </button>
</div> </div>
<mat-menu #filterMenu="matMenu">
<mat-chip-list>
<mat-chip *ngFor="let genre of this.genres">{{genre.name}}</mat-chip>
</mat-chip-list>
</mat-menu>
<mat-menu #sortMenu="matMenu"> <mat-menu #sortMenu="matMenu">
<div *ngFor="let type of this.sortKeys"> <div *ngFor="let type of this.sortKeys">
<button *ngIf="type != this.sortType; else elseBlock;" mat-menu-item (click)="sort(type, true)"> <button *ngIf="type != this.sortType; else elseBlock;" mat-menu-item (click)="sort(type, true)">

View File

@ -1,12 +1,14 @@
import {Component, Input} from '@angular/core'; import {Component, Input} from '@angular/core';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute} from '@angular/router';
import {DomSanitizer} from '@angular/platform-browser'; import {DomSanitizer} from '@angular/platform-browser';
import { Genre } from "../../../models/resources/genre";
import {LibraryItem} from "../../../models/resources/library-item"; import {LibraryItem} from "../../../models/resources/library-item";
import {Page} from "../../../models/page"; import {Page} from "../../../models/page";
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {Show, ShowRole} from "../../../models/resources/show"; import {Show, ShowRole} from "../../../models/resources/show";
import {Collection} from "../../../models/resources/collection"; import {Collection} from "../../../models/resources/collection";
import {ItemsUtils} from "../../misc/items-utils"; import {ItemsUtils} from "../../misc/items-utils";
import { PreLoaderService } from "../../services/pre-loader.service";
@Component({ @Component({
selector: 'app-items-grid', selector: 'app-items-grid',
@ -20,15 +22,22 @@ export class ItemsGridComponent
sortType: string = "title"; sortType: string = "title";
sortKeys: string[] = ["title", "start year", "end year"] sortKeys: string[] = ["title", "start year", "end year"]
sortUp: boolean = true; sortUp: boolean = true;
filters: string[] = [];
genres: Genre[];
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
private loader: PreLoaderService,
public client: HttpClient) public client: HttpClient)
{ {
this.route.data.subscribe((data) => this.route.data.subscribe((data) =>
{ {
this.page = data.items; this.page = data.items;
}); });
this.loader.load<Genre>("/api/genres?limit=0").subscribe(data =>
{
this.genres = data;
});
} }
getThumb(slug: string) getThumb(slug: string)

View File

@ -0,0 +1,27 @@
import { HttpClient } from "@angular/common/http";
import { Injectable } from '@angular/core';
import { Page } from "../../models/page";
import { Observable, of } from "rxjs"
import { map } from "rxjs/operators"
@Injectable({
providedIn: 'root'
})
export class PreLoaderService
{
private cache: [string, any[]][] = [];
constructor(private http: HttpClient) { }
load<T>(route: string): Observable<T[]>
{
let loaded = this.cache.find(x => x[0] == route);
if (loaded != null)
return of(loaded[1]);
return this.http.get<Page<T>>(route).pipe(map(newData =>
{
this.cache.push([route, newData.items]);
return newData.items;
}));
}
}

View File

@ -1,37 +1,37 @@
{ {
"extends": "tslint:recommended", "extends": "tslint:recommended",
"rulesDirectory": [
"codelyzer"
],
"rules": { "rules": {
"align": {
"options": [
"parameters",
"statements"
]
},
"array-type": false, "array-type": false,
"arrow-parens": false, "arrow-return-shorthand": true,
"curly": true,
"deprecation": { "deprecation": {
"severity": "warning" "severity": "warning"
}, },
"component-class-suffix": true, "eofline": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"import-blacklist": [ "import-blacklist": [
true, true,
"rxjs/Rx" "rxjs/Rx"
], ],
"interface-name": false, "import-spacing": true,
"indent": {
"options": [
"tabs"
]
},
"max-classes-per-file": false, "max-classes-per-file": false,
"max-line-length": [ "max-line-length": [
true, true,
140 120
], ],
"member-access": false,
"member-ordering": [ "member-ordering": [
true, true,
{ {
@ -43,7 +43,6 @@
] ]
} }
], ],
"no-consecutive-blank-lines": false,
"no-console": [ "no-console": [
true, true,
"debug", "debug",
@ -60,19 +59,72 @@
"no-non-null-assertion": true, "no-non-null-assertion": true,
"no-redundant-jsdoc": true, "no-redundant-jsdoc": true,
"no-switch-case-fall-through": true, "no-switch-case-fall-through": true,
"no-use-before-declare": true,
"no-var-requires": false, "no-var-requires": false,
"object-literal-key-quotes": [ "object-literal-key-quotes": [
true, true,
"as-needed" "as-needed"
], ],
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [ "quotemark": [
true, true,
"single" "double"
], ],
"trailing-comma": false, "semicolon": {
"options": [
"always"
]
},
"space-before-function-paren": {
"options": {
"anonymous": "never",
"asyncArrow": "always",
"constructor": "never",
"method": "never",
"named": "never"
}
},
"typedef": [
true,
"call-signature"
],
"typedef-whitespace": {
"options": [
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
},
{
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
}
]
},
"variable-name": {
"options": [
"ban-keywords",
"check-format",
"allow-pascal-case"
]
},
"whitespace": {
"options": [
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type",
"check-typecast",
"check-module"
]
},
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"no-conflicting-lifecycle": true, "no-conflicting-lifecycle": true,
"no-host-metadata-property": true, "no-host-metadata-property": true,
"no-input-rename": true, "no-input-rename": true,
@ -84,9 +136,18 @@
"template-banana-in-box": true, "template-banana-in-box": true,
"template-no-negated-async": true, "template-no-negated-async": true,
"use-lifecycle-interface": true, "use-lifecycle-interface": true,
"use-pipe-transform-interface": true "use-pipe-transform-interface": true,
}, "directive-selector": [
"rulesDirectory": [ true,
"codelyzer" "attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
] ]
} }
}