Thứ hai, 13/11/2017 | 00:00 GMT+7

Trình cập nhật tiêu đề khai báo với Angular và ngrx


Cập nhật HTMLTitleElement thật dễ dàng với dịch vụ Tiêu đề của Angular. Việc mỗi tuyến đường trong SPA có một tiêu đề khác nhau là điều khá phổ biến. Điều này thường được thực hiện thủ công trong vòng đời ngOnInit của thành phần của tuyến đường. Tuy nhiên, trong bài đăng này, ta sẽ làm điều đó theo cách khai báo bằng cách sử dụng sức mạnh của @ ngrx / router-store với một RouterStateSerializer tùy chỉnh và @ ngrx / Effects .

Khái niệm như sau:

  • Có thuộc tính tiêu đề trong dữ liệu của định nghĩa tuyến đường.
  • Sử dụng @ ngrx / store để theo dõi trạng thái ứng dụng.
  • Sử dụng @ ngrx / router-store với RouterStateSerializer tùy chỉnh để thêm tiêu đề mong muốn vào trạng thái ứng dụng.
  • Tạo hiệu ứng updateTitle bằng cách sử dụng @ ngrx / Effects để cập nhật HTMLTitleElement mỗi khi tuyến thay đổi.

Cài đặt dự án

Để cài đặt nhanh chóng và dễ dàng, ta sẽ sử dụng @ angle / cli .

# Install @angular-cli if you don't already have it
npm install @angular/cli -g

# Create the example with routing
ng new title-updater --routing

Xác định một số tuyến đường

Tạo một vài thành phần:

ng generate component gators
ng generate component crocs

Và xác định các tuyến đường của chúng:

title-updater / src / app / app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GatorsComponent } from './gators/gators.component';
import { CrocsComponent } from './crocs/crocs.component';

const routes: Routes = [
  {
    path: 'gators',
    component: GatorsComponent,
    data: { title: 'Alligators'}
  },
  {
    path: 'crocs',
    component: CrocsComponent,
    data: { title: 'Crocodiles'}
  }
];

Chú ý thuộc tính tiêu đề trong mỗi định nghĩa tuyến, nó sẽ được sử dụng để cập nhật HTMLTitleElement .

Thêm Quản lý Nhà nước

@ngrx là một thư viện tuyệt vời để quản lý trạng thái ứng dụng. Đối với ứng dụng ví dụ này, ta sẽ sử dụng @ ngrx / router-store để tuần tự hóa bộ định tuyến vào @ ngrx / store để ta có thể lắng nghe các thay đổi về tuyến đường và cập nhật tiêu đề cho phù hợp.

Ta sẽ sử dụng @ngrx > 4.0 để tận dụng RouterStateSerializer mới

Tải về:

npm install @ngrx/store @ngrx/router-store --save

Tạo một RouterStateSerializer tùy chỉnh để thêm tiêu đề mong muốn vào trạng thái:

title-updater / src / app / shared / utils.ts
import { RouterStateSerializer } from '@ngrx/router-store';
import { RouterStateSnapshot } from '@angular/router';

export interface RouterStateTitle {
  title: string;
}
export class CustomRouterStateSerializer
 implements RouterStateSerializer<RouterStateTitle> {
  serialize(routerState: RouterStateSnapshot): RouterStateTitle {
    let childRoute = routerState.root;
    while (childRoute.firstChild) {
      childRoute = childRoute.firstChild;
    }
// Use the most specific title
const title = childRoute.data['title'];
return { title };

Xác định bộ giảm tốc bộ định tuyến:

title-updater / src / app / Reducers / index.ts
import * as fromRouter from '@ngrx/router-store';
import { RouterStateTitle } from '../shared/utils';
import { createFeatureSelector } from '@ngrx/store';

export interface State {
  router: fromRouter.RouterReducerState<RouterStateTitle>;
}
export const reducers = {
  router: fromRouter.routerReducer
};

Mỗi khi @ ngrx / store gửi một hành động (các hành động chuyển bộ định tuyến được gửi bởi StoreRouterConnectingModule ), một trình giảm tốc cần xử lý hành động đó và cập nhật trạng thái cho phù hợp. Ở trên, ta xác định trạng thái ứng dụng của bạn để có thuộc tính bộ định tuyến và giữ trạng thái bộ định tuyến được tuần tự hóa ở đó bằng cách sử dụng CustomRouterStateSerializer .

Một bước cuối cùng là cần thiết để kết nối tất cả:

title-updater / src / app / app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
import { StoreModule } from '@ngrx/store';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CrocsComponent } from './crocs/crocs.component';
import { GatorsComponent } from './gators/gators.component';
import { reducers } from './reducers/index';
import { CustomRouterStateSerializer } from './shared/utils';
@NgModule({
  declarations: [
    AppComponent,
    CrocsComponent,
    GatorsComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    StoreModule.forRoot(reducers),
StoreRouterConnectingModule
  ],
  providers: [
    /**

Rắc Magic @ ngrx / effect

Bây giờ khi ta chuyển đổi tuyến đường, @ ngrx / store của ta sẽ có tiêu đề mà ta muốn. Để cập nhật tiêu đề, tất cả những gì ta phải làm bây giờ là lắng nghe các hành động ROUTER_NAVIGATION và sử dụng tiêu đề trên trạng thái. Ta có thể làm điều này với @ ngrx / Effects .

Tải về:

npm install @ngrx/effects --save

Tạo hiệu ứng:

title-updater / src / app / Effects / title-updater.ts
import { Title } from '@angular/platform-browser';
import { Actions, Effect } from '@ngrx/effects';
import { ROUTER_NAVIGATION, RouterNavigationAction } from '@ngrx/router-store';
import 'rxjs/add/operator/do';
import { RouterStateTitle } from '../shared/utils';

@Injectable()
export class TitleUpdaterEffects {
  @Effect({ dispatch: false })
  updateTitle$ = this.actions
    .ofType(ROUTER_NAVIGATION)
    .do((action: RouterNavigationAction<RouterStateTitle>) => {
      this.titleService.setTitle(action.payload.routerState.title);
    });

Cuối cùng, kết nối hiệu ứng updateTitle bằng lệnh nó với EffectsModule.forRoot , điều này sẽ bắt đầu lắng nghe hiệu ứng khi module được tạo bằng cách đăng ký tất cả @Effect () s :

title-updater / src / app / app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
import { StoreModule } from '@ngrx/store';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CrocsComponent } from './crocs/crocs.component';
import { GatorsComponent } from './gators/gators.component';
import { reducers } from './reducers/index';
import { CustomRouterStateSerializer } from './shared/utils';
import { EffectsModule } from '@ngrx/effects';
import { TitleUpdaterEffects } from './effects/title-updater';

Và đó là nó! Đến đây bạn có thể xác định tiêu đề trong định nghĩa tuyến đường và chúng sẽ tự động được cập nhật khi tuyến đường thay đổi!

Tiến xa hơn, từ Tĩnh sang Động ⚡️

Tiêu đề tĩnh là tuyệt vời cho hầu hết các trường hợp sử dụng, nhưng nếu bạn muốn chào đón một user bằng tên hoặc hiển thị số lượng thông báo thì sao? Ta có thể sửa đổi thuộc tính tiêu đề trong dữ liệu tuyến đường thành một hàm chấp nhận một ngữ cảnh.

Đây là một ví dụ tiềm năng nếu thông báoCount có trên cửa hàng:

title-updater / src / app / app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GatorsComponent } from './gators/gators.component';
import { CrocsComponent } from './crocs/crocs.component';
import { InboxComponent } from './inbox/inbox.component';

const routes: Routes = [
  {
    path: 'gators',
    component: GatorsComponent,
    data: { title: () => 'Alligators' }
  },
  {
    path: 'crocs',
    component: CrocsComponent,
    data: { title: () => 'Crocodiles' }
  },
  {
  path: 'inbox',
  component: InboxComponent,
  data: {
    // A dynamic title that shows the current notification count!
    title: (ctx) => {
      let t = 'Inbox';
      if(ctx.notificationCount > 0) {
        t += (${ctx.notificationCount});
      }
      return t;
    }
  }
}
];

title-updater / src / app / Effects / title-updater.ts
import { Title } from '@angular/platform-browser';
import { Actions, Effect } from '@ngrx/effects';
import { ROUTER_NAVIGATION, RouterNavigationAction } from '@ngrx/router-store';
import { Store } from '@ngrx/store';
import 'rxjs/add/operator/combineLatest';
import { getNotificationCount } from '../selectors.ts';
import { RouterStateTitle } from '../shared/utils';

@Injectable()
export class TitleUpdaterEffects {
  // Update title every time route or context changes, pulling the notificationCount from the store.
  @Effect({ dispatch: false })
  updateTitle$ = this.actions
    .ofType(ROUTER_NAVIGATION)
    .combineLatest(this.store.select(getNotificationCount),
      (action: RouterNavigationAction<RouterStateTitle>, notificationCount: number) => {
        // The context we will make available for the title functions to use as they please.
        const ctx = { notificationCount };
        this.titleService.setTitle(action.payload.routerState.title(ctx));
    });

Bây giờ khi tuyến Hộp thư đến được tải, user cũng có thể thấy số lượng thông báo của họ được cập nhật theo thời gian thực! 💌

🚀 Tiếp tục thử nghiệm và khám phá RouterStateSerializers tùy chỉnh và @ngrx !


Tags:

Các tin liên quan