[英]What is the best way to do routing of angular components using node.js as backend
I am trying to to navigate through angular components (signup and dashboard). 我试图浏览角度组件(注册和仪表板)。 If the user has already signed up then he should be redirected to the dashboard component and if not then to signup component.
如果用户已经注册,则应将其重定向到仪表板组件,如果没有,则重定向到注册组件。 Running only lib.js file as the server.
仅运行lib.js文件作为服务器。 The angular files are deployed after using
ng build
command (making use of dist folder). 使用
ng build
命令(使用dist文件夹)后部署角度文件。 Both the front-end and back-end are in the same folder 前端和后端都在同一个文件夹中
Here are the some code snippets: 以下是一些代码片段:
lib.js (node.js back-end file) lib.js(node.js后端文件)
app.use(exp.static(path.join(__dirname, 'dist')));
app.listen(PORT, function() {
console.log('Express server listening on port ', PORT); // eslint-disable-line
});
app.post('/check_account',function(req,res){
console.log(req.body);
connection.query('SELECT * FROM login_table WHERE m_pub_key LIKE '+'\"'+req.body.m_pub_key+'\"' ,function(error,rows,fields){
if(!!error){
console.log('error!');
res.send('Error!');
}
else
{
console.log(rows);
if(rows.length!=0){
data={
is_signed_up: 1
}
res.send(data);
}
else{
data={
is_signed_up: 0
}
res.send(data);
}
}
});
});
app.get('/dashboard',function(req,res){
console.log("inside dashboard backend");
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
app.get('/signup', function (req,res) {
console.log("signup backend");
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
app.get('/', function (req,res) {
console.log("slash backend");
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
app.component.ts app.component.ts
constructor(private router: Router,private _appService: AppService, private zone: NgZone, private http: HttpClient, private route: ActivatedRoute){
console.log("inside app component constructor");
this.checkAndInstantiateWeb3();
this.onReady();
}
checkAccount(){
let data_send = JSON.stringify({
'm_pub_key': this.m_pub_key
});
this.zone.runOutsideAngular(()=>{
this._appService.post_method(this.url+"check_account", data_send).subscribe(
data => {
this.is_signed_up=data["is_signed_up"];
console.log(this.is_signed_up+"***************8");
if(this.is_signed_up==1){
console.log("navigating to dash");
this.router.navigate(['/dashboard']);
//this.http.get("/dashboard");
}
else{
console.log("navigating to signuo");
this.router.navigate(['/signup']);
//this.http.get("/signup");
}
},
error => {
// console.log('post error');
});
});
}
public checkAndInstantiateWeb3 = () => {
if (typeof window.web3 !== 'undefined') {
console.warn('Using injected web3');
this.web3 = new Web3(window.web3.currentProvider);
} else {
// when running in browser, use incognito mode or log out of metamask
console.warn('No web 3 detected, falling back to Ganache');
this.provider = new Web3.providers.HttpProvider('http://localhost:7545');
this.web3 = new Web3(this.provider);
}
window.ethereum.enable();
}
public onReady = () => {
// get initial account balance so it can be displayed
this.web3.eth.getAccounts((err, accs) => {
if (err != null) {
console.log(err);
alert('There was an error fetching your accounts.');
return;
}
if (accs.length === 0) {
alert('You are not connected to an Ethereum client.');
return;
}
this.m_pub_key=accs[0];
console.log(this.m_pub_key);
this.checkAccount();
});
}
}
app-routing.module.ts APP-routing.module.ts
const routes: Routes = [
{ path: 'signup', component: SignupComponent },
{ path: '', pathMatch: 'full', redirectTo: 'signup' },
{ path: 'dashboard', component: DashboardComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule { }
Now the problem is that if the user has already signed up and then when he tries to go to any page he is redirected to 1st the signup page and then dashboard page but both the pages overlap and also the dashboard component does not work properly. 现在的问题是,如果用户已经注册,然后当他尝试转到任何页面时,他将被重定向到第一个注册页面,然后重定向到仪表板页面,但两个页面重叠,仪表板组件也无法正常工作。 When user directly goes to the dashboard component using the url then the dashboard component works as expected.
当用户使用URL直接转到仪表板组件时,仪表板组件将按预期工作。 Any help in this problem would be appreciated.
任何有关这个问题的帮助将不胜感激。
EDIT 1 编辑1
Following the answer given by "k0hamed". 按照“k0hamed”给出的答案。 Using the canActivate attriute like this
{ path: 'signup', component: SignupComponent, canActivate:[AuthGuard] }
This are the guard and service files i have created and its not working as expected. 像这样使用canActivate attriute
{ path: 'signup', component: SignupComponent, canActivate:[AuthGuard] }
这是我创建的防护和服务文件,它不能按预期工作。 The val
in the auth.guard.ts file does not change and nothing gets loaded when i go to localhost:8080/ or localhost:8080/signup but the dashboard component loads when i type in localhost:8080/dashboard 当我转到localhost:8080 /或localhost:8080 / signup时,auth.guard.ts文件中的
val
不会更改并且没有任何内容被加载,但当我输入localhost时,仪表板组件会加载:8080 / dashboard
auth.guard.ts: auth.guard.ts:
export class AuthGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> {
console.log('AuthGuard#canActivate called');
return this.signupService.onReady()
.pipe(tap(val=>!val && this.router.navigate(['/signup'])));
}
constructor(private signupService: AuthService, private router: Router) {}
}
auth.service.ts: auth.service.ts:
export class AuthService {
provider: any;
account: any;
accounts: any;
web3: any;
m_pub_key="";
title = 'project2';
is_signed_up:any;
url = "http://localhost:8080/";
val = of(false);
constructor(private _appService: AppService, private zone: NgZone, private router: Router){
}
onReady():Observable<boolean> {
// get initial account balance so it can be displayed
// (async () => {
if (typeof window.web3 !== 'undefined') {
console.warn('Using injected web3');
this.web3 = new Web3(window.web3.currentProvider);
} else {
// when running in browser, use incognito mode or log out of metamask
console.warn('No web 3 detected, falling back to Ganache');
this.provider = new Web3.providers.HttpProvider('http://localhost:7545');
this.web3 = new Web3(this.provider);
}
window.ethereum.enable();
this.web3.eth.getAccounts((err, accs) => {
if (err != null) {
console.log(err);
alert('There was an error fetching your accounts.');
return;
}
if (accs.length === 0) {
alert('You are not connected to an Ethereum client.');
return;
}
this.m_pub_key=accs[0];
console.log(this.m_pub_key);
// this.isSigned();
});
let data_send = JSON.stringify({
'm_pub_key': this.m_pub_key
});
this._appService.post_method(this.url+"check_account", data_send).subscribe(
data => {
this.is_signed_up=data["is_signed_up"];
console.log(this.is_signed_up+"***************8");
if(this.is_signed_up==1){
console.log("navigating to dash");
//this.router.navigate(['/dashboard']);
//this.http.get("/dashboard");
this.val = of(false);
// this.router.navigate(['/dashboard']);
}
else{
console.log("navigating to signup");
//this.router.navigate(['/signup']);
//this.http.get("/signup");
this.val = of(true);
// this.router.navigate(['/signup']);
}
console.log(this.val);
},
// console.log(this.val);
error => {
// console.log('post error');
});
// });
console.log(this.val);
return this.val
}
}
first of 首先
your shouldn't handle literally every route in the back-end if angular does so 如果有角度的话,你不应该在后端的每条路线上按字面处理
app.get('/*', function(req,res) {
res.sendFile(path.join( __dirname + '/dist/index.html'));
});
adding this as the last route in your express app will redirect every request not handled above it to angular and angular will use it's own router 添加此作为您的快递应用程序中的最后一个路由将重定向每个未处理它上面的请求角度和角度将使用它自己的路由器
second of, you need to use a canActive guard for your use case and move the checking function within it, if user is not signed it will redirect to signup
page, else it will allow him to pass, something like: 第二,你需要为你的用例使用canActive防护并在其中移动检查功能,如果用户没有签名,它将重定向到
signup
页面,否则它将允许他通过,例如:
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> {
console.log('AuthGuard#canActivate called');
return this.signupService.isSigned()
.pipe(tap(val => !val && this.router.navigate(['/signup']))); // Navigate to signup when it returns false
}
constructor(private signupService: SignupService, private router: Router) {}
}
While SignupService
is a service with method isSigned()
that return an Observable<boolean>
; 虽然
SignupService
是一个带有方法isSigned()
的服务,它返回一个Observable<boolean>
;
You might need to create another guard for the signup
page route, to check if not signed and redirect to dashboard otherwise. 您可能需要为
signup
页面路由创建另一个防护,以检查是否未签名并以其他方式重定向到仪表板。
UPDATE: You need to either turn your whole code into promises or observables, to handle asynchronous functions as the guards accepts observable and promise 更新:您需要将整个代码转换为promises或observable,以处理异步函数,因为守卫接受可观察和承诺
So for example to use the observables way you need to turn getAcounts
function to return observable instead of depending on callback, fortunately rxJs has a build-in function to do so it's bindNodeCallback you can simply do 所以例如使用observables方式你需要把
getAcounts
函数转换为observable而不是依赖回调,幸运的是rxJs有一个内置函数来做这个它的bindNodeCallback你可以简单地做
const getAccountsAsObservable = bindNodeCallback(
callback => this.web3.eth.getAccounts(callback));
now you can use rxJs magic to chain the code through pipes and you need to handle error with a pipe also and make it return an observable of false. 现在你可以使用rxJs magic通过管道链接代码,你也需要用管道处理错误,并使它返回一个可观察的false。
and your service will be something like: 你的服务将是这样的:
onReady():Observable<boolean> {
// ..
const getAccountsAsObservable = Observable.bindNodeCallback(
callback => this.web3.eth.getAccounts(callback));
return getAccountsAsObservable()
.pipe(
switchMap(acc => {
if (accs.length === 0) {
alert('You are not connected to an Ethereum client.');
// throw an error to skip to "cathError" pipe
return throwError(new Error('You are not connected to an Ethereum client.'));
}
const m_pub_key=accs[0];
console.log(this.m_pub_key);
const data_send = JSON.stringify({
'm_pub_key': m_pub_key
});
return of(data_send);
}),
switchMap(data_send => {
this._appService.post_method(this.url+"check_account", data_send)
}),
map(data => {
this.is_signed_up=data["is_signed_up"];
console.log(this.is_signed_up+"***************8");
if(this.is_signed_up==1){
console.log("navigating to dash");
//this.router.navigate(['/dashboard']);
//this.http.get("/dashboard");
return false;
// this.router.navigate(['/dashboard']);
} else {
console.log("navigating to signup");
//this.router.navigate(['/signup']);
//this.http.get("/signup");
return true;
// this.router.navigate(['/signup']);
}
}),
catchError(err => {
//handle error of getAccounts or post_method here
console.log(err);
alert('There was an error fetching your accounts.');
return of(false);
})
)
}
you can turn the whole thing into promises and/or use async/await you can turn _appService.post_method
to promise with .pipe(take(1)).toPromise
你可以将整个事情变成promises和/或使用async / await你可以将
_appService.post_method
转为使用.pipe(take(1)).toPromise
承诺.pipe(take(1)).toPromise
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.