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,92 +1,153 @@
{ {
"extends": "tslint:recommended", "extends": "tslint:recommended",
"rules": { "rulesDirectory": [
"array-type": false, "codelyzer"
"arrow-parens": false, ],
"deprecation": { "rules": {
"severity": "warning" "align": {
}, "options": [
"component-class-suffix": true, "parameters",
"contextual-lifecycle": true, "statements"
"directive-class-suffix": true, ]
"directive-selector": [ },
true, "array-type": false,
"attribute", "arrow-return-shorthand": true,
"app", "curly": true,
"camelCase" "deprecation": {
], "severity": "warning"
"component-selector": [ },
true, "eofline": true,
"element", "import-blacklist": [
"app", true,
"kebab-case" "rxjs/Rx"
], ],
"import-blacklist": [ "import-spacing": true,
true, "indent": {
"rxjs/Rx" "options": [
], "tabs"
"interface-name": false, ]
"max-classes-per-file": false, },
"max-line-length": [ "max-classes-per-file": false,
true, "max-line-length": [
140 true,
], 120
"member-access": false, ],
"member-ordering": [ "member-ordering": [
true, true,
{ {
"order": [ "order": [
"static-field", "static-field",
"instance-field", "instance-field",
"static-method", "static-method",
"instance-method" "instance-method"
] ]
} }
], ],
"no-consecutive-blank-lines": false, "no-console": [
"no-console": [ true,
true, "debug",
"debug", "info",
"info", "time",
"time", "timeEnd",
"timeEnd", "trace"
"trace" ],
], "no-empty": false,
"no-empty": false, "no-inferrable-types": [
"no-inferrable-types": [ true,
true, "ignore-params"
"ignore-params" ],
], "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-var-requires": false,
"no-use-before-declare": true, "object-literal-key-quotes": [
"no-var-requires": false, true,
"object-literal-key-quotes": [ "as-needed"
true, ],
"as-needed" "quotemark": [
], true,
"object-literal-sort-keys": false, "double"
"ordered-imports": false, ],
"quotemark": [ "semicolon": {
true, "options": [
"single" "always"
], ]
"trailing-comma": false, },
"no-conflicting-lifecycle": true, "space-before-function-paren": {
"no-host-metadata-property": true, "options": {
"no-input-rename": true, "anonymous": "never",
"no-inputs-metadata-property": true, "asyncArrow": "always",
"no-output-native": true, "constructor": "never",
"no-output-on-prefix": true, "method": "never",
"no-output-rename": true, "named": "never"
"no-outputs-metadata-property": true, }
"template-banana-in-box": true, },
"template-no-negated-async": true, "typedef": [
"use-lifecycle-interface": true, true,
"use-pipe-transform-interface": true "call-signature"
}, ],
"rulesDirectory": [ "typedef-whitespace": {
"codelyzer" "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-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
]
}
} }