Browse Source

Move extensible form to personal settings component

pull/13700/head
Mahmut Gundogdu 4 years ago
parent
commit
4a421e0da7
  1. 8
      npm/ng-packs/packages/account/src/lib/account.module.ts
  2. 5
      npm/ng-packs/packages/account/src/lib/components/extensible-personal-settings/extensible-personal-settings.component.html
  3. 0
      npm/ng-packs/packages/account/src/lib/components/extensible-personal-settings/extensible-personal-settings.component.scss
  4. 24
      npm/ng-packs/packages/account/src/lib/components/extensible-personal-settings/extensible-personal-settings.component.spec.ts
  5. 42
      npm/ng-packs/packages/account/src/lib/components/extensible-personal-settings/extensible-personal-settings.component.ts
  6. 33
      npm/ng-packs/packages/account/src/lib/components/personal-settings/half-row/half-row.component.ts
  7. 30
      npm/ng-packs/packages/account/src/lib/components/personal-settings/name-surname/name-surname.component.ts
  8. 50
      npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.html
  9. 47
      npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts
  10. 40
      npm/ng-packs/packages/account/src/lib/defaults/default-personal-settings-form-props.ts
  11. 241
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.html
  12. 17
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts

8
npm/ng-packs/packages/account/src/lib/account.module.ts

@ -15,11 +15,11 @@ import { accountConfigOptionsFactory } from './utils/factory-utils';
import { AuthenticationFlowGuard } from './guards/authentication-flow.guard';
import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component';
import { ResetPasswordComponent } from './components/reset-password/reset-password.component';
import { ExtensiblePersonalSettingsComponent } from './components/extensible-personal-settings/extensible-personal-settings.component';
import { UiExtensionsModule } from '@abp/ng.theme.shared/extensions';
import { ACCOUNT_EDIT_FORM_PROP_CONTRIBUTORS } from './tokens/extensions.token';
import { AccountExtensionsGuard } from './guards/extensions.guard';
import { HelloComponent } from './components/hello/hello.component';
import { HalfRowComponent } from './components/personal-settings/half-row/half-row.component';
import { NameSurnameComponent } from './components/personal-settings/name-surname/name-surname.component';
const declarations = [
LoginComponent,
@ -29,10 +29,12 @@ const declarations = [
PersonalSettingsComponent,
ForgotPasswordComponent,
ResetPasswordComponent,
HalfRowComponent,
NameSurnameComponent
];
@NgModule({
declarations: [...declarations, ExtensiblePersonalSettingsComponent, HelloComponent],
declarations: [...declarations],
imports: [
CoreModule,
AccountRoutingModule,

5
npm/ng-packs/packages/account/src/lib/components/extensible-personal-settings/extensible-personal-settings.component.html

@ -1,5 +0,0 @@
<p>extensible-personal-settings works!</p>
<form [formGroup]="form" (ngSubmit)="save()" validateOnSubmit>
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form>
</form>

0
npm/ng-packs/packages/account/src/lib/components/extensible-personal-settings/extensible-personal-settings.component.scss

24
npm/ng-packs/packages/account/src/lib/components/extensible-personal-settings/extensible-personal-settings.component.spec.ts

@ -1,24 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ExtensiblePersonalSettingsComponent } from './extensible-personal-settings.component';
describe('ExtensiblePersonalSettingsComponent', () => {
let component: ExtensiblePersonalSettingsComponent;
let fixture: ComponentFixture<ExtensiblePersonalSettingsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ExtensiblePersonalSettingsComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ExtensiblePersonalSettingsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

42
npm/ng-packs/packages/account/src/lib/components/extensible-personal-settings/extensible-personal-settings.component.ts

@ -1,42 +0,0 @@
import {Component, Injector, OnInit} from '@angular/core';
import {EXTENSIONS_IDENTIFIER, FormPropData, generateFormFromProps} from "@abp/ng.theme.shared/extensions";
import { eAccountComponents } from '../../enums/components';
import {FormBuilder, FormGroup} from "@angular/forms";
import {ProfileService} from "@abp/ng.account.core/proxy";
@Component({
selector: 'abp-extensible-personal-settings',
templateUrl: './extensible-personal-settings.component.html',
styleUrls: ['./extensible-personal-settings.component.scss'],
providers:[
{
provide: EXTENSIONS_IDENTIFIER,
useValue: eAccountComponents.PersonalSettings,
},
]
})
export class ExtensiblePersonalSettingsComponent implements OnInit {
selected = {a: 1};// hacky for triggering 'edit' mode of extensible-form
form: FormGroup;
constructor(
private profileService: ProfileService,
protected fb: FormBuilder,
protected injector: Injector,
) {}
buildForm() {
const data = new FormPropData(this.injector, this.selected);
this.form = generateFormFromProps(data);
}
ngOnInit(): void {
this.buildForm()
}
save() {
}
}

33
npm/ng-packs/packages/account/src/lib/components/personal-settings/half-row/half-row.component.ts

@ -0,0 +1,33 @@
import {Component, Inject} from '@angular/core';
import {FORM_PROP_DATA_STREAM, FormProp} from "@abp/ng.theme.shared/extensions";
import {ControlContainer, FormGroup, FormGroupDirective} from "@angular/forms";
@Component({
selector: 'abp-half-row',
template: `
<div class="col col-md-6">
<div class="mb-3 form-group" >
<label for="surname" class="form-label">{{
displayName | abpLocalization
}}
{{name}}
</label>
<input type="text" [attr.id]="id" class="form-control" [attr.name]="name" [formControlName]="name"/>
</div>
</div>`,
styles: [],
viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }]
})
export class HalfRowComponent {
public displayName: string;
public name: string;
public id: string;
public formGroup: FormGroup
constructor(@Inject(FORM_PROP_DATA_STREAM) private propData: FormProp) {
this.displayName = propData.displayName
this.name = propData.name
this.id = propData.id
}
}

30
npm/ng-packs/packages/account/src/lib/components/personal-settings/name-surname/name-surname.component.ts

@ -0,0 +1,30 @@
import { Component } from '@angular/core';
import {ControlContainer, FormGroupDirective} from "@angular/forms";
@Component({
selector: 'abp-name-surname',
template: `<div class="row">
<div class="col col-md-6">
<div class="mb-3 form-group">
<label for="name" class="form-label">{{
'AbpIdentity::DisplayName:Name' | abpLocalization
}}</label
><input type="text" id="name" class="form-control" formControlName="name" />
</div>
</div>
<div class="col col-md-6">
<div class="mb-3 form-group">
<label for="surname" class="form-label">{{
'AbpIdentity::DisplayName:Surname' | abpLocalization
}}</label
><input type="text" id="surname" class="form-control" formControlName="surname" />
</div>
</div>
</div>`,
styles: [],
viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }]
})
export class NameSurnameComponent {
constructor() {}
}

50
npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.html

@ -1,49 +1,7 @@
<form validateOnSubmit *ngIf="form" [formGroup]="form" (ngSubmit)="submit()">
<div class="mb-3 form-group">
<label for="username" class="form-label">{{
'AbpIdentity::DisplayName:UserName' | abpLocalization
}}</label
><span> * </span
><input
type="text"
id="username"
class="form-control"
formControlName="userName"
autofocus
(keydown.space)="$event.preventDefault()"
/>
</div>
<div class="row">
<div class="col col-md-6">
<div class="mb-3 form-group">
<label for="name" class="form-label">{{
'AbpIdentity::DisplayName:Name' | abpLocalization
}}</label
><input type="text" id="name" class="form-control" formControlName="name" />
</div>
</div>
<div class="col col-md-6">
<div class="mb-3 form-group">
<label for="surname" class="form-label">{{
'AbpIdentity::DisplayName:Surname' | abpLocalization
}}</label
><input type="text" id="surname" class="form-control" formControlName="surname" />
</div>
</div>
</div>
<div class="mb-3 form-group">
<label for="email-address" class="form-label">{{
'AbpIdentity::DisplayName:Email' | abpLocalization
}}</label
><span> * </span
><input type="text" id="email-address" class="form-control" formControlName="email" />
</div>
<div class="mb-3 form-group">
<label for="phone-number" class="form-label">{{
'AbpIdentity::DisplayName:PhoneNumber' | abpLocalization
}}</label
><input type="text" id="phone-number" class="form-control" formControlName="phoneNumber" />
</div>
<h1>Thor</h1>
<form [formGroup]="form" *ngIf="form" (ngSubmit)="submit()" validateOnSubmit>
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form>
<abp-button
buttonType="submit"
iconClass="fa fa-check"

47
npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts

@ -1,17 +1,24 @@
import { ProfileService } from '@abp/ng.account.core/proxy';
import { ToasterService } from '@abp/ng.theme.shared';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { finalize } from 'rxjs/operators';
import { Account } from '../../models/account';
import { ManageProfileStateService } from '../../services/manage-profile.state.service';
import {ProfileDto, ProfileService} from '@abp/ng.account.core/proxy';
import {ToasterService} from '@abp/ng.theme.shared';
import {Component, Injector, OnInit, ViewEncapsulation} from '@angular/core';
import {FormBuilder, FormGroup} from '@angular/forms';
import {finalize} from 'rxjs/operators';
import {Account} from '../../models/account';
import {ManageProfileStateService} from '../../services/manage-profile.state.service';
import {EXTENSIONS_IDENTIFIER, FormPropData, generateFormFromProps} from "@abp/ng.theme.shared/extensions";
import {eAccountComponents} from "../../enums";
const { maxLength, required, email } = Validators;
@Component({
selector: 'abp-personal-settings-form',
templateUrl: './personal-settings.component.html',
exportAs: 'abpPersonalSettingsForm',
providers:[
{
provide: EXTENSIONS_IDENTIFIER,
useValue: eAccountComponents.PersonalSettings,
},
]
})
export class PersonalSettingsComponent
implements
@ -19,6 +26,8 @@ export class PersonalSettingsComponent
Account.PersonalSettingsComponentInputs,
Account.PersonalSettingsComponentOutputs
{
selected:ProfileDto
form: FormGroup;
inProgress: boolean;
@ -28,21 +37,21 @@ export class PersonalSettingsComponent
private toasterService: ToasterService,
private profileService: ProfileService,
private manageProfileState: ManageProfileStateService,
protected injector: Injector,
) {}
ngOnInit() {
this.buildForm();
}
buildForm() {
const profile = this.manageProfileState.getProfile();
this.form = this.fb.group({
userName: [profile.userName, [required, maxLength(256)]],
email: [profile.email, [required, email, maxLength(256)]],
name: [profile.name || '', [maxLength(64)]],
surname: [profile.surname || '', [maxLength(64)]],
phoneNumber: [profile.phoneNumber || '', [maxLength(16)]],
});
this.selected = this.manageProfileState.getProfile();
if(!this.selected){
return
}
const data = new FormPropData(this.injector, this.selected);
this.form = generateFormFromProps(data);
}
ngOnInit(): void {
this.buildForm()
}
submit() {

40
npm/ng-packs/packages/account/src/lib/defaults/default-personal-settings-form-props.ts

@ -1,15 +1,45 @@
import {ePropType, FormProp} from "@abp/ng.theme.shared/extensions";
import {UpdateProfileDto} from "@abp/ng.account.core/proxy";
import {Validators} from "@angular/forms";
import {HelloComponent} from "../components/hello/hello.component";
import {NameSurnameComponent} from "../components/personal-settings/name-surname/name-surname.component";
const { maxLength, required, email } = Validators;
export const DEFAULT_PERSONAL_SETTINGS_UPDATE_FORM_PROPS = FormProp.createMany<UpdateProfileDto>([
{
type: ePropType.String,
name: 'userName',
displayName: 'Account::UserName',
id: 'user-name',
validators: () => [Validators.required, Validators.maxLength(256)],
template: HelloComponent
displayName: 'AbpIdentity::DisplayName:UserName',
id: 'username',
validators: () => [required,maxLength(256)],
},
{
type: ePropType.String,
name: 'name',
displayName: 'AbpIdentity::DisplayName:Name',
id: 'name',
validators: () => [maxLength(64),required],
template:NameSurnameComponent
},
{
type: ePropType.String,
name: 'surname',
displayName: 'AbpIdentity::DisplayName:Surname',
id: 'surname',
validators: () => [maxLength(64),required],
visible:() => false
},
{
type: ePropType.String,
name: 'email',
displayName: 'AbpIdentity::DisplayName:Email',
id: 'email-address',
validators: () => [required, email, maxLength(256)],
},
{
type: ePropType.String,
name: 'phoneNumber',
displayName: 'AbpIdentity::DisplayName:PhoneNumber',
id: 'phone-number',
validators: () => [maxLength(16)],
},
])

241
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.html

@ -1,148 +1,153 @@
<div
class="mb-3 form-group"
*abpPermission="prop.permission; runChangeDetection: false"
[ngSwitch]="getComponent(prop)"
>
<ng-container [ngSwitch]="getComponent(prop)"
*abpPermission="prop.permission; runChangeDetection: false">
<ng-template ngSwitchCase="template">
<ng-container *ngComponentOutlet="prop.template;injector:injectorForCustomComponent" >
<ng-container
[formControlName]="prop.name"
*ngComponentOutlet="prop.template;injector:injectorForCustomComponent">
</ng-container>
</ng-template>
<ng-template ngSwitchCase="input">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<input
#field
[id]="prop.id"
[formControlName]="prop.name"
[autocomplete]="prop.autocomplete"
[type]="getType(prop)"
[abpDisabled]="disabled"
[readonly]="readonly"
class="form-control"
/>
</ng-template>
<ng-template ngSwitchCase="hidden">
<input [formControlName]="prop.name" type="hidden" />
</ng-template>
<div
class="mb-3 form-group"
>
<ng-template ngSwitchCase="checkbox">
<div class="form-check" validationTarget>
<ng-template ngSwitchCase="input">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<input
#field
[id]="prop.id"
[formControlName]="prop.name"
[autocomplete]="prop.autocomplete"
[type]="getType(prop)"
[abpDisabled]="disabled"
type="checkbox"
class="form-check-input"
[readonly]="readonly"
class="form-control"
/>
<ng-template
[ngTemplateOutlet]="label"
[ngTemplateOutletContext]="{ $implicit: 'form-check-label' }"
></ng-template>
</div>
</ng-template>
</ng-template>
<ng-template ngSwitchCase="select">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<select
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
class="form-select form-control"
>
<option
*ngFor="let option of options$ | async; trackBy: track.by('value')"
[ngValue]="option.value"
>
{{ option.key }}
</option>
</select>
</ng-template>
<ng-template ngSwitchCase="hidden">
<input [formControlName]="prop.name" type="hidden"/>
</ng-template>
<ng-template ngSwitchCase="multiselect">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<select
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
multiple="multiple"
class="form-select form-control"
>
<option
*ngFor="let option of options$ | async; trackBy: track.by('value')"
[ngValue]="option.value"
<ng-template ngSwitchCase="checkbox">
<div class="form-check" validationTarget>
<input
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
type="checkbox"
class="form-check-input"
/>
<ng-template
[ngTemplateOutlet]="label"
[ngTemplateOutletContext]="{ $implicit: 'form-check-label' }"
></ng-template>
</div>
</ng-template>
<ng-template ngSwitchCase="select">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<select
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
class="form-select form-control"
>
{{ option.key }}
</option>
</select>
</ng-template>
<option
*ngFor="let option of options$ | async; trackBy: track.by('value')"
[ngValue]="option.value"
>
{{ option.key }}
</option>
</select>
</ng-template>
<ng-template ngSwitchCase="typeahead">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<div #typeahead class="position-relative" validationStyle validationTarget>
<input
<ng-template ngSwitchCase="multiselect">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<select
#field
[id]="prop.id"
[autocomplete]="prop.autocomplete"
[formControlName]="prop.name"
[abpDisabled]="disabled"
[ngbTypeahead]="search"
[editable]="false"
[inputFormatter]="typeaheadFormatter"
[resultFormatter]="typeaheadFormatter"
[ngModelOptions]="{ standalone: true }"
[(ngModel)]="typeaheadModel"
(selectItem)="setTypeaheadValue($event.item)"
(blur)="setTypeaheadValue(typeaheadModel)"
[class.is-invalid]="typeahead.classList.contains('is-invalid')"
multiple="multiple"
class="form-select form-control"
>
<option
*ngFor="let option of options$ | async; trackBy: track.by('value')"
[ngValue]="option.value"
>
{{ option.key }}
</option>
</select>
</ng-template>
<ng-template ngSwitchCase="typeahead">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<div #typeahead class="position-relative" validationStyle validationTarget>
<input
#field
[id]="prop.id"
[autocomplete]="prop.autocomplete"
[abpDisabled]="disabled"
[ngbTypeahead]="search"
[editable]="false"
[inputFormatter]="typeaheadFormatter"
[resultFormatter]="typeaheadFormatter"
[ngModelOptions]="{ standalone: true }"
[(ngModel)]="typeaheadModel"
(selectItem)="setTypeaheadValue($event.item)"
(blur)="setTypeaheadValue(typeaheadModel)"
[class.is-invalid]="typeahead.classList.contains('is-invalid')"
class="form-control"
/>
<input [formControlName]="prop.name" type="hidden"/>
</div>
</ng-template>
<ng-template ngSwitchCase="date">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<input
[id]="prop.id"
[formControlName]="prop.name"
(click)="datepicker.open()"
(keyup.space)="datepicker.open()"
ngbDatepicker
#datepicker="ngbDatepicker"
type="text"
class="form-control"
/>
<input [formControlName]="prop.name" type="hidden" />
</div>
</ng-template>
</ng-template>
<ng-template ngSwitchCase="date">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<input
[id]="prop.id"
[formControlName]="prop.name"
(click)="datepicker.open()"
(keyup.space)="datepicker.open()"
ngbDatepicker
#datepicker="ngbDatepicker"
type="text"
class="form-control"
/>
</ng-template>
<ng-template ngSwitchCase="time">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<ngb-timepicker [formControlName]="prop.name"></ngb-timepicker>
</ng-template>
<ng-template ngSwitchCase="time">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<ngb-timepicker [formControlName]="prop.name"></ngb-timepicker>
</ng-template>
<ng-template ngSwitchCase="dateTime">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<abp-date-time-picker [prop]="prop" [meridian]="meridian"></abp-date-time-picker>
</ng-template>
<ng-template ngSwitchCase="dateTime">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<abp-date-time-picker [prop]="prop" [meridian]="meridian"></abp-date-time-picker>
</ng-template>
<ng-template ngSwitchCase="textarea">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<textarea
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
[readonly]="readonly"
class="form-control"
></textarea>
</ng-template>
</div>
<ng-template ngSwitchCase="textarea">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<textarea
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
[readonly]="readonly"
class="form-control"
></textarea>
</ng-template>
</div>
</ng-container>
<ng-template #label let-classes>
<label [htmlFor]="prop.id" [ngClass]="classes || 'form-label'"
>{{ prop.displayName | abpLocalization }} {{ asterisk }}</label
>{{ prop.displayName | abpLocalization }} {{ asterisk }}</label
>
</ng-template>

17
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts

@ -77,8 +77,8 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
setTypeaheadValue(selectedOption: ABP.Option<string>) {
this.typeaheadModel = selectedOption || { key: null, value: null };
const { key, value } = this.typeaheadModel;
this.typeaheadModel = selectedOption || {key: null, value: null};
const {key, value} = this.typeaheadModel;
const [keyControl, valueControl] = this.getTypeaheadControls();
if (valueControl?.value && !value) valueControl.markAsDirty();
keyControl?.setValue(key);
@ -88,10 +88,10 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
search = (text$: Observable<string>) =>
text$
? text$.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap(text => this.prop.options(this.data, text)),
)
debounceTime(300),
distinctUntilChanged(),
switchMap(text => this.prop.options(this.data, text)),
)
: of([]);
typeaheadFormatter = (option: ABP.Option<any>) => option.key;
@ -190,7 +190,8 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
{
provide: FORM_PROP_DATA_STREAM,
useValue: currentProp
}
},
],
parent: this.injector,
});
@ -209,7 +210,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
const [keyControl, valueControl] = this.getTypeaheadControls();
if (keyControl && valueControl)
this.typeaheadModel = { key: keyControl.value, value: valueControl.value };
this.typeaheadModel = {key: keyControl.value, value: valueControl.value};
}
}

Loading…
Cancel
Save