Hello,
You can simply initiate it as new TreeAdapter(list)
.
The important bit is that the list
should have children that has fields like id
, parentId
which builds up the tree.
Hello @GregB,
We are utilizing this tree adapter which is available within @abp/ng.components
package.
Hope it helps.
Hello,
You can follow the guide here
If you simply want to enable users to choose a picture from their computer, you can use something like <input type="file" id="avatar" name="avatar" accept="image/png, image/jpeg">
. This is the native way of choosing files from your computer.
If you want them to choose a file that is already uploaded via the file-management module, you have to implement your own interface to do it. For the tree component, we use the tree component of ng-zorro
Hello,
I'm not quite sure about what you are trying to achieve. Could you explain your case little bit further with images if possible?
Thank you
Hello,
I will present two different ways to achieve what you are trying to do. However, keep in mind that the second option heavily relies on the internal implementation of the UsersComponent
which could change in the future and we may introduce some breaking changes for that component. If you choose to follow the second option, it is your responsibility to ensure that your code is working. If there are some breaking changes, again it is your responsibility to edit your code accordingly.
First Option: Override UsersComponent
You could implement your own users
page so that you can define any logic you'd like.
Please refer to the docs for more detail about replacing components.
The key for UsersComponent
is eIdentityComponents.Users
Second Option: Override Password field in the form
You can override password
field for New user
modal.
Please refer to the docs
Firstly, let's create a file and call it identity-create-form-prop-contributors.ts
and add the following code block in it.
export function customAsyncPasswordValidator(data: PropData<IdentityUserDto>) {
// validator will come here
}
const passwordField = new FormProp<IdentityUserDto>({
type: ePropType.Password,
name: 'password',
displayName: 'AbpIdentity::Password',
id: 'password',
autocomplete: 'new-password',
validators: _ => [Validators.required],
asyncValidators: customAsyncPasswordValidator,
});
export function userCreateFormContributor(formProps: FormPropList<IdentityUserDto>) {
const index = formProps.indexOf('password', (action, name) => action.name === name);
formProps.dropByIndex(index);
formProps.addByIndex(passwordField, index);
}
export const identityCreateFormContributors: IdentityCreateFormPropContributors = {
[eIdentityComponents.Users]: [userCreateFormContributor],
};
Up to this point, we haven't done anything hacky yet. You can use this part confidently. It is the trivial way of overriding a field within an extensible form. However, the implementation of customAsyncPasswordValidator
will be error-prone and depend on the internals of UsersComponent
. It is up to you to decide whether to use the following implementation. It contains some comment about
export function customAsyncPasswordValidator(data: PropData<IdentityUserDto>) {
const roleService = data.getInjected(IdentityRoleService);
const user = data.getInjected(UsersComponent);
/**
* Retrieve the existing roles and filter them with name `Super Admin`
*/
const superAdminRoleDetails = roleService.getAllList().pipe(
map(roles => roles.items.filter(role => role.name === 'Super Admin')),
shareReplay(), // this exists so that we will only retrieve this list once.
);
/**
* If `Super Admin` is not selected, we should keep the default validators.
* This function calls every validator with `control` to keep the default behavior.
*/
const defaultValidator = (control: FormControl) =>
of(
getPasswordValidators({ get: data.getInjected }).reduce(
(retVal, currValidator) => ({ ...retVal, ...currValidator(control) }),
{},
),
);
const superAdminPasswordValidator = (control: FormControl) =>
superAdminRoleDetails.pipe(
map(details => {
if (details?.length) {
const rules = details[0];
// You can write your custom rule here with rules.extraProperties
return control.value !== '123456'
? {
wrongPassword: true,
}
: null;
}
return null;
}),
);
const validator = control => {
/**
* Find if a role group exists with name `Super Admin`
*/
const superAdminGroup = user.roleGroups.find(roleGr => roleGr.contains('Super Admin'));
if (superAdminGroup) {
const isAdminSelected = superAdminGroup.controls['Super Admin'].value;
return isAdminSelected ? superAdminPasswordValidator(control) : defaultValidator(control);
}
return defaultValidator(control);
};
return [validator];
}
Finally, we need to add some imports to app.module
and app-routing.module
Import following into app.module
@NgModule({
// ...
imports: [
// ...
NgxValidateCoreModule.forRoot({
blueprints: {
wrongPassword: 'Please choose 123456',
},
})
]
export class AppModule {}
And, update app-routing.module
{
path: 'identity',
loadChildren: () =>
import('@volo/abp.ng.identity').then(m =>
m.IdentityModule.forLazy({
// this line should be added
createFormPropContributors: identityCreateFormContributors,
}),
),
},
Hello,
In the latest version of ABP, we replaced the Store
parameter with Injector
. Since you are running an early version, you should pass Store
instead of Injector
You can find the related commit here
Hello,
It is available within @abp/ng.theme.shared
package. You find an example of usage here
You can find the code of the function, getPasswordValidators
It is a simple function that takes injector
.
setPasswordForm = this.fb.group({
newPassword: ['', [Validators.required, ...getPasswordValidators(this.injector)]],
});
Hello @rbarbosa,
I assume you serve your angular application (built HTML and js files) and your APIs from the same domain.
On the localhost, it works just fine because your APIs running on https://localhost:44382
and your angular application on http://localhost:4200
. The XSRF-TOKEN
is set by a cookie which is marked as secure (meaning only the applications run on HTTPS can read and send this cookie). So, when the Angular application makes a request to the backend, that cookie is not being sent by the browser (as it should).
However, when you build and deploy your Angular application to a server, let's say https://www.yourdomain.com/ng-app
which also serves your APIs https://www.yourdomain.com/apis
things may get messy. If they are in the same domain, you should not write https://www.yourdomain.com
into environment.prod.ts
files.
Simply edit the apis
section in environment.prod.ts
to the following
export const environment = {
production: true,
...snip...
apis: {
default: {
url: '',
rootNamespace: 'ProjectName',
},
},
} as Config.Environment;
@Ryan.sposato@ethany.com could you please share your setup? I've tried it and it works with my setup.