Skip to content

Commit

Permalink
Merge branch 'master' into minor
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Jun 23, 2021
2 parents f9f2323 + d76c306 commit ad73fce
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 7 deletions.
8 changes: 8 additions & 0 deletions docs/content/developer-guide/customizing-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,12 @@ mutation {
}
}
```
#### UI for relation type

The Admin UI app has built-in selection components for "relation" custom fields which reference certain common entity types, such as Asset, Product, ProductVariant and Customer. If you are relating to an entity not covered by the built-in selection components, you will instead see the message:

```text
No input component configured for "<entity>" type
```

In this case, you will need to create a UI extension which defines a custom field control for that custom field. You can read more about this in the [CustomField Controls guide]({{< relref "custom-field-controls" >}})
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,69 @@ To recap the steps involved:
2. Add this component to your shared extension module's `declarations` array.
3. Use `registerCustomFieldComponent()` to register your component for the given entity & custom field name.

## Custom Field Controls for Relations

If you have a custom field of the `relation` type (which allows you to relate entities with one another), you can also define custom field controls for them. The basic mechanism is exactly the same as with primitive custom field types (i.e. `string`, `int` etc.), but there are a couple of important points to know:

1. The value of the `formControl` will be the _related entity object_ rather than an id. The Admin UI will internally take care of converting the entity object into an ID when performing the create/update mutation.
2. Your control will most likely need to fetch data in order to display a list of selections for the user.

Here is a simple example taken from the [real-world-vendure](https://github.com/vendure-ecommerce/real-world-vendure/blob/master/src/plugins/reviews/ui/components/featured-review-selector/featured-review-selector.component.ts) repo:

```TypeScript
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { CustomFieldControl, DataService } from '@vendure/admin-ui/core';
import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';

import { GET_REVIEWS_FOR_PRODUCT } from '../product-reviews-list/product-reviews-list.graphql';
import { GetReviewForProduct, ProductReviewFragment } from '../../generated-types';

@Component({
selector: 'relation-review-input',
template: `
<div *ngIf="formControl.value as review">
<vdr-chip>{{ review.rating }} / 5</vdr-chip>
{{ review.summary }}
<a [routerLink]="['/extensions', 'product-reviews', review.id]">
<clr-icon shape="link"></clr-icon>
</a>
</div>
<select appendTo="body" [formControl]="formControl">
<option [ngValue]="null">Select a review...</option>
<option *ngFor="let item of reviews$ | async" [ngValue]="item">
<b>{{ item.summary }}</b>
{{ item.rating }} / 5
</option>
</select>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RelationReviewInputComponent implements OnInit, CustomFieldControl {
@Input() readonly: boolean;
@Input() formControl: FormControl;
@Input() config: any;

reviews$: Observable<ProductReviewFragment[]>;

constructor(private dataService: DataService, private route: ActivatedRoute) {}

ngOnInit() {
this.reviews$ = this.route.data.pipe(
switchMap(data => data.entity),
switchMap((product: any) => {
return this.dataService
.query<GetReviewForProduct.Query, GetReviewForProduct.Variables>(
GET_REVIEWS_FOR_PRODUCT,
{
productId: product.id,
},
)
.mapSingle(({ product }) => product?.reviews.items ?? []);
}),
);
}
}
```
11 changes: 4 additions & 7 deletions packages/admin-ui/src/lib/core/src/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ const DECLARATIONS = [
LocaleDatePipe,
LocaleCurrencyPipe,
TagSelectorComponent,
ManageTagsDialogComponent,
RelationSelectorDialogComponent,
RelationCardComponent,
];

const DYNAMIC_FORM_INPUTS = [
Expand All @@ -240,13 +243,7 @@ const DYNAMIC_FORM_INPUTS = [
@NgModule({
imports: [IMPORTS],
exports: [...IMPORTS, ...DECLARATIONS, ...DYNAMIC_FORM_INPUTS],
declarations: [
...DECLARATIONS,
...DYNAMIC_FORM_INPUTS,
ManageTagsDialogComponent,
RelationSelectorDialogComponent,
RelationCardComponent,
],
declarations: [...DECLARATIONS, ...DYNAMIC_FORM_INPUTS],
providers: [
// This needs to be shared, since lazy-loaded
// modules have their own entryComponents which
Expand Down

0 comments on commit ad73fce

Please sign in to comment.