Reloading current route in Angular 5 / Angular 6 / Angular 7
问题: angular 从子状态回到当前的父级状态的时候,父级状态不会重新初始化。
https://github.com/angular-ui/ui-router/issues/2992
------------------------------------------------
Back in the days of AngularJS you were able to reload a route even if you were already viewing it. For example, clicking on the home option of a menu when you are already viewing the homepage would refresh the homepage. This was useful for a number of reasons, but most importantly for UX. Users expect to be able to click on a page menu item and have the page re-initialise. Setting up this type of reloading in AngularJS was straightforward. You could invoke reload() in your router and away you went.
When Angular 2 was released this feature was not present in the router and there was no easy way to reload the active route. Many people developed “hacky” techniques such as bouncing through a second route in the A -> B -> A sequence, effectively sending you off to a page and back again to trigger the reload. That had the desired effect but was rather inefficient. Another technique that was often suggested was outright reloading the page, which for a single page application is a bad idea.
As of Angular 5.1 there is a supported technique for route reloading. This can now be done using the onSameUrlNavigation
configuration option as part of the built-in Angular router. Unfortunately, the documentation does not make it very clear on how to implement it, so I have documented my approach below.
The first thing you will need to do is set the option within your app.routing.tsif you have one, or the file where your app routing is configured in your particular project.
There are two possible values for onSameUrlNavigation ’reload’ or false. The default value is false, causing nothing to happen when the router is asked to navigate to the active route. We want to set this value to reload. It is worth noting reload does not actually do the work of reloading the route, it only re-triggers events on the router that we then need to hook into.
@ngModule({
imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: ‘reload’})],
exports: [RouterModule],
})
To determine how those events are actually fired, you need to specify the runGuardsAndResolvers configuration option on your route. This can take one of three values
paramsChange — only fire when route params have changed e.g. where the id in /user/:id changes
paramsOrQueryParamsChange — fire when a route param changes or a query param changes. e.g. the id or the limit property change in /user/:id/invites?limit=10
always — Always fire when the route is navigated
We want to specify always in this case. An example route definition is shown below.
export const routes: Routes = [
{
path: ‘invites’,
component: InviteComponent,
children: [
{
path: ‘’,
loadChildren: ‘./pages/invites/invites.module#InvitesModule’,
},
],
canActivate: [AuthenticationGuard],
runGuardsAndResolvers: ‘always’,
}
]
With these two changes your router is configured. The next step is to handle the events that your router will produce within one of your components. To do this you will need to import the Router into your component and then hook into the events of interest. In this example, I have hooked into the NavigationEnd event which is fired once the router has completed its navigation from one route to another. Due to the way we have configured the app, this will now fire even if you try to navigate to the current route.
export class InviteComponent implements OnInit, OnDestroy{
// ... your class variables here
navigationSubscription;
constructor(
// … your declarations here
private router: Router,
) {
// subscribe to the router events - storing the subscription so
// we can unsubscribe later.
this.navigationSubscription = this.router.events.subscribe((e: any) => {
// If it is a NavigationEnd event re-initalise the component
if (e instanceof NavigationEnd) {
this.initialiseInvites();
}
});
} initialiseInvites() {
// Set default values and re-fetch any data you need.
}
ngOnDestroy() {
// avoid memory leaks here by cleaning up after ourselves. If we
// don't then we will continue to run our initialiseInvites()
// method on every navigationEnd event.
if (this.navigationSubscription) {
this.navigationSubscription.unsubscribe();
}
}
}
The heavy lifting goes into the initialiseInvites() method, this is where you reset properties to their default values and fetch data from services to get the component back to its initial state.
You need to repeat this pattern across each component that you would like to to reload, being sure to add the runGuardsAndResolvers option to each route in the routing file.
** Updated 05/03/2018 **
Thanks to Changyu Geng and Dennis de Laat for pointing this out in the comments.
I have added an unsubscribe handler in the ngOnDestroy hook in the above example.
As router.events
is global, if we do not unsubscribe our event handler on component destruction then it will continue to fire for every NavigationEnd
event across our application even when we are not on the invites screen. This is less than ideal because
a) We will be running our event handler for invites even if we are on another screen.
b) Every time we navigate back to invites we will resubscribe to the event. This would cause our initialise function to run n times, where n is the number of times we have landed on the invites page.
If you’ve enjoyed this blog, please take a couple of minutes to check out Gurn and see how it can make you a more productive developer.
---------------------------------------------------------------------------
2I want to extract only the last event entry of type NavigationEnd from router.events. But somehow I can't find a proper way to do this. Whatever I try the following code snipped is the only way to get access to these objects of interest.
let ne: any; router.events.filter(e => e instanceof NavigationEnd)
.forEach(e => {
ne = e as NavigationEnd;
}); console.log('target page: ', ne.urlAfterRedirects);But do I really have to use .forEach() letting it run though all entries and using then the last entry? Isn't there a better way to handle the events as a kind of array and then say
ne = arrayOfEvents[arrayOfEvents.length-1]
?
I'm getting crazy about it but it seems that I can't see the wood for the trees...
1Have you looked at using thelast
operator on observables? reactivex.io/documentation/operators/last.html – Daniel W Strimpel Apr 8 '18 at 20:29 Yes, I tried it. But it unfortunately doesn't work in my case as there is no processable return value. – Lynx 242Apr 8 '18 at 20:45 2Did you see this article? toddmotto.com/dynamic-page-titles-angular-2-router-events – Vega Apr 8 '18 at 20:49 1That's it! This helps a lot. Thank you. – Lynx 242 Apr 8 '18 at 21:00 If the events observable never completes thenlast
never does anything. What do you mean by last? YOUmean the last in the group. But the computer can wait 100 years for the stream to close, and that's whatlast()
means to RxJS! So I think actuallylast()
will NEVER return (it possibly might as the page is being unloaded but that's no use). – Simon_Weaver Jan 23 at 22:104Okay, after reading through the posted articles above and rethinking what I really want to achieve I found out that my approach was definitely too complicated. Because actually I only need access to the currently called route. And so I started from scratch and came across this small but very effective solution:
this.router.events.subscribe(value => {
console.log('current route: ', router.url.toString());
});Thanks to all who shared a comment in oder to support me! It helped al lot as I was able to tie up loose ends.
4PS. There's a better way to filter using a 'typeguard', you then get the proper type without having to assert it again:
firstChildData$ = this.router.events.pipe( filter((e): e is NavigationEnd => e instanceof NavigationEnd), map(e => { // e is now NavigationEnd }
This is actually necessary in strict mode.
Reloading current route in Angular 5 / Angular 6 / Angular 7的更多相关文章
- Angular学习笔记:Angular CLI
定义 Angular CLI:The Angular CLI is a command line interface tool that can create a project, add files ...
- angular enter事件,angular回车事件
angular回车键搜索,angular enter搜索 对于搜索框,用户在输入内容后的搜索习惯不是鼠标点击搜索按钮,而是直接按enter键,那我们怎么给enter键绑定事件呢,其实很简单,代码如下: ...
- Angular 2 升级到 Angular 5
Angular 2 升级到 Angular 5 ts文件最上面的import语句里不要添加 .ts 后缀 , 不然 npm start 编译会失败 . 虽然浏览器能打开项目的URL , 但是内容会丢失 ...
- Angular系列一:Angular程序架构
Angular程序架构 Angular程序架构 组件:一段带有业务逻辑和数据的Html服务:用来封装可重用的业务逻辑指令:允许你向Html元素添加自定义行为模块: 环境搭建 安装nodeJs安装好no ...
- Angular系列文章之angular路由
路由(route),几乎所有的MVC(VM)框架都应该具有的特性,因为它是前端构建单页面应用(SPA)必不可少的组成部分. 那么,对于angular而言,它自然也有内置的路由模块:叫做ngRoute. ...
- [Angular 2] ROUTING IN ANGULAR 2 REVISITED
Let's say we have a list of contacts, click each contact, we can render a new route to get the detai ...
- Angular - 预加载 Angular 模块
Angular - 预加载延迟模块 在使用路由延迟加载中,我们介绍了如何使用模块来拆分应用,在访问到这个模块的时候, Angular 加载这个模块.但这需要一点时间.在用户第一次点击的时候,会有一点延 ...
- Angular企业级开发(3)-Angular MVC实现
1.MVC介绍 Model-View-Controller 在20世纪80年代为程序语言Smalltalk发明的一种软件架构.MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并 ...
- 30行代码让你理解angular依赖注入:angular 依赖注入原理
依赖注入(Dependency Injection,简称DI)是像C#,java等典型的面向对象语言框架设计原则控制反转的一种典型的一种实现方式,angular把它引入到js中,介绍angular依赖 ...
随机推荐
- 白嫖百度 Tesla V100 笔记(在 AI Studio 上使用 tensorflow 和 pytorch 的方法)
登陆百度 AI Studio 并按照教程创建新项目 启动项目并进入控制台 下载 Anaconda3/Miniconda3 安装脚本 安装在 ~/work/*conda3 目录 输入命令 source ...
- mysql主从同步原理及错误解决
mysql主从同步的原理: 1.在master上开启bin-log日志功能,记录更新.插入.删除的语句. 2.必须开启三个线程,主上开启io线程,从上开启io线程和sql线程. 3.从上io线程去连接 ...
- java枚举的线程安全及序列化
原文链接:https://www.cnblogs.com/z00377750/p/9177097.html https://www.cnblogs.com/chiclee/p/9097772.html ...
- PTA 8-1 jmu-java-流、文件与正则表达式 (5 分)
0.字节流与文件 我的代码: public static byte[] readFile(String path){ File file = new File(path); FileInputStre ...
- QSqlDatabase
QSqlDatabase 使用静态方法addDatabase来创建一个数据库连接. 如果你的程序中只有一个数据库连接,可以使用如下语句创建连接 QSqlDatabase db = QSqlDatab ...
- CentOs7环境下手动配置JDK7
下载: JDK7下载地址:http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7- ...
- 4.JVM 实战操作
1.1 JVM参数 1.1.1 标准参数 -version -help -server -cp 1.1.2 -X参数 非标准参数,也就是在JDK各个版本中可能会变动 -Xint 解释执行 -Xcomp ...
- Python基础 第5章 条件、循环及其他语句(1)
1. print和import 1.1 打印多个参数 可用 + 连接多个字符串,可保证被连接字符串前无空格: 可用sep=“_”,自定义各种分隔符: print("I"," ...
- python第五天---集合与format格式化
""" 集合:set 1.由不同元素组成, 2.无序 3.不可变:数字.字符串.元组 不可变类型 """ s = {1, 2, 3, 4, ...
- 探索grafana
因为zabbix的监控图形不够美观,功能也不够强大, 那么就用到了grafana 填写zabbix插件配置: 如下需要根据主机群组和主机名来完成图形: grafana报警如下: 解决如下: 更改标准设 ...