Skip to content

Commit

Permalink
Feature: Collections as array; traBy function for ngFor; (#100)
Browse files Browse the repository at this point in the history
Version 1.1.0 🎆 

* Feature: collections has `data` member now. `data` is an array, and the requested information is kept in order.  Closes #84. Closes #54.
* Feature: trackBy added on collection. Optimize use of ngFor.
* Deprecated: callback functions deprecated on get(), all(), detele() and save().

And...

* Demo: demo-collection-info component added. Show info about received collection.
* tslint: array<> to [] on types
* version 1.1.0 bump
* Readme updated: sort and trackby added
  • Loading branch information
pablorsk authored Aug 12, 2018
1 parent ec2b371 commit 9da3d85
Show file tree
Hide file tree
Showing 35 changed files with 222 additions and 238 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,24 @@ export class AuthorsComponent {
#### View for this controller

```html
<p *ngFor="let author of authors.$toArray">
<p *ngFor="let author of authors.data; trackBy: authors.trackBy">
id: {{ author.id }} <br />
name: {{ author.attributes.name }} <br />
birth date: {{ author.attributes.date_of_birth | date }}
</p>
```

#### More options? Collection filtering
#### Collection sort

Ex: `name` is a authors attribute, and makes a query like `/authors?sort=name,job_title`

```javascript
let authors$ = authorsService.all({
sort: ['name', 'job_title']
});
```

#### Collection filtering

Filter resources with `attribute: value` values. Filters are used as 'exact match' (only resources with attribute value same as value are returned). `value` can also be an array, then only objects with same `attribute` value as one of `values` array elements are returned.

Expand Down
23 changes: 7 additions & 16 deletions demo/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AppComponent } from './app.component';
import { AuthorsService } from './authors/authors.service';
import { BooksService } from './books/books.service';
import { PhotosService } from './photos/photos.service';
import { SharedModule } from './shared/shared.module';

const appRoutes: Routes = [
{
Expand All @@ -27,27 +28,17 @@ const appRoutes: Routes = [
];

@NgModule({
providers: [
AuthorsService,
BooksService,
PhotosService
],
providers: [AuthorsService, BooksService, PhotosService],
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot(
appRoutes,
{ useHash: true }
),
SharedModule,
RouterModule.forRoot(appRoutes, { useHash: true }),
NgxJsonapiModule.forRoot({
url: environment.jsonapi_url
})
],
declarations: [
AppComponent
],
bootstrap: [
AppComponent
]
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
export class AppModule {}
13 changes: 4 additions & 9 deletions demo/app/authors/authors.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@ import { CommonModule } from '@angular/common';
import { AuthorComponent } from './components/author.component';
import { AuthorsComponent } from './components/authors.component';
import { AuthorsRoutingModule } from './authors-routing.module';
import { SharedModule } from '../shared/shared.module';

@NgModule({
imports: [
CommonModule,
AuthorsRoutingModule
],
declarations: [
AuthorComponent,
AuthorsComponent
]
imports: [CommonModule, SharedModule, AuthorsRoutingModule],
declarations: [AuthorComponent, AuthorsComponent]
})
export class AuthorsModule { }
export class AuthorsModule {}
34 changes: 17 additions & 17 deletions demo/app/authors/authors.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,6 @@ import { Injectable } from '@angular/core';
import { Autoregister, Service, ISchema, Resource, ICollection } from 'ngx-jsonapi';
import { Book } from '../books/books.service';

@Injectable()
@Autoregister()
export class AuthorsService extends Service<Author> {
// public resource = Author;
public type = 'authors';
public schema: ISchema = {
relationships: {
books: {
hasMany: true
},
photos: {
hasMany: true
}
}
};
}

export class Author extends Resource {
public attributes = {
name: 'default name',
Expand All @@ -40,3 +23,20 @@ export class Author extends Resource {
return <ICollection>this.relationships.photos.data;
}
}

@Injectable()
@Autoregister()
export class AuthorsService extends Service<Author> {
public resource = Author;
public type = 'authors';
public schema: ISchema = {
relationships: {
books: {
hasMany: true
},
photos: {
hasMany: true
}
}
};
}
38 changes: 17 additions & 21 deletions demo/app/authors/components/author.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,22 @@ import { Observable } from 'rxjs/Observable';
})
export class AuthorComponent {
public author: Author;
public relatedbooks: Array<Resource>;
public relatedbooks: Resource[];

public constructor(
protected authorsService: AuthorsService,
protected photosService: PhotosService,
private route: ActivatedRoute
) {
route.params.subscribe(({ id }) => {
authorsService.get(
id,
{ include: ['books', 'photos'] }
)
.subscribe(
author => {
this.author = author;
console.info('success author controller', author);
},
error => console.error('Could not load author.', error)
);
});
public constructor(protected authorsService: AuthorsService, protected photosService: PhotosService, private route: ActivatedRoute) {
route.params
.finally(() => {
console.log('xxxx finally');
})
.subscribe(({ id }) => {
authorsService.get(id, { include: ['books', 'photos'] }).subscribe(
author => {
this.author = author;
console.info('success author controller', author);
},
error => console.error('Could not load author.', error)
);
});
}

/*
Expand All @@ -42,7 +38,7 @@ export class AuthorComponent {
let author = this.authorsService.new();
author.attributes.name = prompt('New author name:', 'John Doe');
if (!author.attributes.name) {
return ;
return;
}
author.attributes.date_of_birth = '2030-12-10';
console.log('author data for save', author.toObject());
Expand All @@ -69,7 +65,7 @@ export class AuthorComponent {
);
}

public getPhotos(author: Resource): Array<Resource> {
public getPhotos(author: Resource): Resource[] {
return (<ICollection>author.relationships.photos.data).$toArray;
}

Expand Down
4 changes: 2 additions & 2 deletions demo/app/authors/components/authors.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<h3>Authors</h3>
<p><code>$length={{ authors.$length }}. $is_loading={{ authors.$is_loading }}. $source={{ authors.$source }}.</code></p>
<demo-collection-info [collection]="authors"></demo-collection-info>
<table class="table table-striped">
<thead>
<tr>
Expand All @@ -9,7 +9,7 @@ <h3>Authors</h3>
<th>Date of dead</th>
</tr>
</thead>
<tr *ngFor="let author of authors.$toArray">
<tr *ngFor="let author of authors.data; trackBy: authors.trackBy">
<td>{{ author.id }}</td>
<td>
<a [routerLink]="['/authors', author.id]">{{ author.attributes.name }}</a>
Expand Down
44 changes: 21 additions & 23 deletions demo/app/authors/components/authors.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Service, ICollection } from 'ngx-jsonapi';

import { forEach } from '../../../foreach';
import { Component } from '@angular/core';
import { ICollection } from 'ngx-jsonapi';
import 'rxjs/add/operator/finally';
import { AuthorsService } from './../authors.service';

@Component({
Expand All @@ -11,24 +10,23 @@ import { AuthorsService } from './../authors.service';
export class AuthorsComponent {
public authors: ICollection;

public constructor(
private authorsService: AuthorsService
) {
authorsService.all(
// { include: ['books', 'photos'] }
// {
// localfilter: {
// name: 'y', // authors with a `y` character on name
// date_of_birth: /^2016\-.*/ // we can use regular expresions too :)
// }
// }
)
.subscribe(
authors => {
this.authors = authors;
console.info('success authors controller', authors);
},
error => console.error('Could not load authors.')
);
public constructor(private authorsService: AuthorsService) {
authorsService
.all({
// include: ['books', 'photos'],
// localfilter: {
// name: 'y', // authors with a `y` character on name
// date_of_birth: /^2016\-.*/ // we can use regular expresions too :)
// },
sort: ['name'],
ttl: 3600
})
.subscribe(
authors => {
this.authors = authors;
console.info('success authors controller', authors);
},
error => console.error('Could not load authors.')
);
}
}
13 changes: 4 additions & 9 deletions demo/app/books/books.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@ import { CommonModule } from '@angular/common';
import { BookComponent } from './components/book.component';
import { BooksComponent } from './components/books.component';
import { BooksRoutingModule } from './books-routing.module';
import { SharedModule } from '../shared/shared.module';

@NgModule({
imports: [
CommonModule,
BooksRoutingModule
],
declarations: [
BookComponent,
BooksComponent
]
imports: [CommonModule, SharedModule, BooksRoutingModule],
declarations: [BookComponent, BooksComponent]
})
export class BooksModule { }
export class BooksModule {}
11 changes: 2 additions & 9 deletions demo/app/books/components/books.component.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
<h3>Books</h3>
<br/>
<!-- <label>
Search books with:
<input
ng-model="filter_text"
ng-change="getAll({ title: filter_text});"
ng-model-options="{ debounce: 200 }"
></input>
</label> -->
<demo-collection-info [collection]="books"></demo-collection-info>
<table class="table table-striped">
<thead>
<tr>
Expand All @@ -18,6 +10,7 @@ <h3>Books</h3>
<th>Photos</th>
</tr>
</thead>
<!-- Use authors example. @deprected since version 2.0.0 -->
<tr *ngFor="let book of books.$toArray">
<td>{{ book.id }}</td>
<td>
Expand Down
1 change: 1 addition & 0 deletions demo/app/shared/collection-info.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p><code>$length={{ collection.$length }}. $is_loading={{ collection.$is_loading }}. $source={{ collection.$source }}.</code></p>
9 changes: 9 additions & 0 deletions demo/app/shared/collection-info.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Component, Input } from '@angular/core';
import { ICollection } from 'ngx-jsonapi';
@Component({
selector: 'demo-collection-info',
templateUrl: './collection-info.component.html'
})
export class CollectionInfoComponent {
@Input() public collection: ICollection;
}
9 changes: 9 additions & 0 deletions demo/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CollectionInfoComponent } from './collection-info.component';
@NgModule({
imports: [CommonModule],
exports: [CollectionInfoComponent],
declarations: [CollectionInfoComponent]
})
export class SharedModule {}
2 changes: 1 addition & 1 deletion src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export class Core {
}

// just an helper
public duplicateResource<R extends Resource>(resource: R, ...relations_alias_to_duplicate_too: Array<string>): R {
public duplicateResource<R extends Resource>(resource: R, ...relations_alias_to_duplicate_too: string[]): R {
let newresource = <R>this.getResourceService(resource.type).new();
newresource.attributes = { ...newresource.attributes, ...resource.attributes };

Expand Down
8 changes: 5 additions & 3 deletions src/interfaces/collection.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Resource } from '../resource';
import { IPage } from './page';
import { IDataResource } from './data-resource';
import { IDocumentData } from './document';

export interface ICollection<R extends Resource = Resource> extends Array<Resource> {
export interface ICollection<R extends Resource = Resource> extends IDocumentData {
$length: number;
$toArray: Array<R>;
$toArray: R[];
$is_loading: boolean;
$source: 'new' | 'memory' | 'store' | 'server';
$cache_last_update: number;
data: Array<IDataResource>; // this need disapear is for datacollection
page: IPage;
data: R[];
trackBy: Function;
}
6 changes: 3 additions & 3 deletions src/interfaces/data-collection.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { IDataResource } from './data-resource';
import { IDocument } from '../interfaces/document';
import { IDocument, IDocumentData } from '../interfaces/document';
import { IPage } from './page';

export interface IDataCollection extends IDocument {
data: Array<IDataResource>;
export interface IDataCollection extends IDocumentData {
data: IDataResource[];
page?: IPage;
_lastupdate_time?: number; // used when come from Store
}
4 changes: 2 additions & 2 deletions src/interfaces/data-object.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IDocument } from './document';
import { IDocument, IDocumentData } from './document';
import { IDataResource } from './data-resource';

export interface IDataObject extends IDocument {
export interface IDataObject extends IDocumentData {
data: IDataResource;
}
Loading

0 comments on commit 9da3d85

Please sign in to comment.