Preface
Recently, angular is always used as a background system. I found the Ng Alain framework for a long time, and it's quite easy to use. It's just that the official document is a little more concise. In the process of using it, we have to combine some small examples and official demo to determine the syntax. The previous use has been very smooth, even if there are some problems, we can find the blog or materials related to the problems on the Internet. But in the past two days, when we used the access control list, we encountered some problems, which took some time and many twists and turns to solve. Although it's outside the framework, we want to take this opportunity to write the first blog. (there are development notes before, but it's easy to write them down in Youdao cloud every time you meet them. I didn't consciously sort them out in my spare time at weekends. In fact, I'm lazy =; I'll sort them out and paste them together later ~ set up a little flag ~)
Problem
After the acl parameter is added to the custom button group in the st component, the role will be reset for the first entry and refresh. The reason is that the can() is used to print out false, and the switch route reloads the page to print true, which can display normally. The problem is that there is no way to make the first entry and every refresh display normal.
(acl parameters are also added to the menu data in app-data.json, and the startup.service.ts file has set roles, but no permission points for granularity control are used, all of which are controlled through roles.)
Code display
Parameters of custom button group of st component in API document
Set acl parameter of button group in page
The role is set in the startup file. At the beginning, setRole() is used. I'm afraid that the problem of clearing all roles in each assignment of this function causes the problem of changing to attachRole() to be solved
Console debugging, red box is the output of can() function in ngOnInit in the page
Effect display
With the right logic, entering the widget page should look like this
However, due to the asynchronous role setting, the page refreshed and displayed for the first time is as follows
Then switch the route and then switch back to reload the page. The page displays normally again
Solve the problem
Reason
In the process of writing demo, we found the cause of this problem
The reason is that my original user rights are obtained through asynchronous requests. In the process of writing the demo, I used settimeout instead of asynchronous requests. After commenting settimeout in the demo, I found that the problem was solved
Original file:
demo file:
Solution
Get the permission variable in advance and store it in localstorage, and get setRole() at startup, so there is no asynchronous problem.
Add the local.storage.ts file to src/app/core/net (the path can be set according to your preference)
// local.storage.ts file contents import { Provider } from '@angular/core'; export class LocalStorage { public localStorage: any; constructor() { if (!localStorage) { throw new Error('Current browser does not support Local Storage'); } this.localStorage = localStorage; } public set(key: string, value: string): void { this.localStorage[key] = value; } public get(key: string): string { return this.localStorage[key] || false; } public setObject(key: string, value: any): void { this.localStorage[key] = JSON.stringify(value); } public getObject(key: string): any { return JSON.parse(this.localStorage[key] || '{}'); } public remove(key: string): any { this.localStorage.removeItem(key); } }
Introduce in app.module.ts
login.component.ts file:
// Add content to login.component.ts file // ... import { LocalStorage } from '@core/net/local.storage'; // ... export class UserLoginComponent implements OnDestroy { constructor( private localStorage: LocalStorage, // Introducing localstorage ) { // Clear roles every time you enter the landing page this.localStorage.remove('role'); } submit() { // ... this.api .loginCheck({ username: this.userName.value, password: this.password.value, }) .subscribe((res: any) => { // ... // Set user Token information this.tokenService.set({ token: res.data.token }); this.api.findUserRights().subscribe( resp => { // Save role permissions obtained asynchronously this.localStorage.set('role', resp.data.acl); }, () => null, () => { // Function after execution // To retrieve the startups service content, we always believe that the application information is generally affected by the authorization scope of the current user this.startupSrv.load().then(() => { let url = this.tokenService.referrer.url || '/'; if (url.includes('/passport')) url = '/'; this.router.navigateByUrl(url); }); }, ); }); } }
startup.service.ts file:
Write at the end
This solves the problem of asynchrony, but I always think it may not be the best solution. There are several questions I haven't found out yet: where are the variables set in aclservice stored? Does alain have its own way of writing that I don't need to save in localstorage?
The reason why I found the reason for writing demo is that I delayed two or three days for this problem, baidu did not find the problem when checking the data, but only sent an email to ask Ng Alain's developer card color (the email left on GitHub). Before that, I did consider that it might be asynchronous. After turning the asynchronous request await into synchronous, I found that page rendering precedes the execution of the startup file, and the problem has not been solved. Subconsciously, I thought it was not asynchronous. Then, the debug test to eliminate the write dead parameters of asynchronous requests was not carried out because of such problems. This is the first time I wrote an email to ask the author. I'm really sorry to disturb the God...