diff --git a/docs/zh-Hans/UI/Angular/Custom-Setting-Page.md b/docs/zh-Hans/UI/Angular/Custom-Setting-Page.md index f7854ac6bf..2b888e8d75 100644 --- a/docs/zh-Hans/UI/Angular/Custom-Setting-Page.md +++ b/docs/zh-Hans/UI/Angular/Custom-Setting-Page.md @@ -2,38 +2,33 @@ 不同的模块提供它们的设置选项卡. 你可以通过3个步骤在项目中自定义设置页面. -1. 创建一个组件 +1. 使用以下命令创建一个组件 -```js -import { Select } from '@ngxs/store'; -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-your-custom-settings', - template: ` - custom-settings works! - `, -}) -export class YourCustomSettingsComponent { - // Your component logic -} +```bash +yarn ng generate component my-settings ``` -2. 添加 `YourCustomSettingsComponent` 到 `AppModule` 中的 `declarations`和 `entryComponents` 数组中. - -3. 打开 `app.component.ts` 在 `ngOnInit` 添加以下内容: +2. 打开 `app.component.ts` 做以下修改: ```js -import { addSettingTab } from '@abp/ng.theme.shared'; -// ... - -ngOnInit() { - addSettingTab({ - component: YourCustomSettingsComponent, - name: 'Type here the setting tab title (you can type a localization key, e.g: AbpAccount::Login', - order: 4, - requiredPolicy: 'type here a policy key' - }); +import { Component } from '@angular/core'; +import { SettingTabsService } from '@abp/ng.core'; // imported SettingTabsService +import { MySettingsComponent } from './my-settings/my-settings.component'; // imported MySettingsComponent + +@Component(/* component metadata */) +export class AppComponent { + constructor(private settingTabs: SettingTabsService) // injected MySettingsComponent + { + // added below + settingTabs.add([ + { + name: 'MySettings', + order: 1, + requiredPolicy: 'policy key here', + component: MySettingsComponent, + }, + ]); + } } ``` diff --git a/docs/zh-Hans/UI/Angular/Localization.md b/docs/zh-Hans/UI/Angular/Localization.md index 60af06a976..f90260fc8b 100644 --- a/docs/zh-Hans/UI/Angular/Localization.md +++ b/docs/zh-Hans/UI/Angular/Localization.md @@ -146,16 +146,6 @@ this.store.selectSnapshot( "build": { "options": { "styles": [ - { - "input": "node_modules/@abp/ng.theme.shared/styles/bootstrap-rtl.min.css", - "inject": false, - "bundleName": "bootstrap-rtl.min" - }, - { - "input": "node_modules/bootstrap/dist/css/bootstrap.min.css", - "inject": true, - "bundleName": "bootstrap-ltr.min" - }, { "input": "node_modules/@fortawesome/fontawesome-free/css/all.min.css", "inject": true, @@ -166,6 +156,16 @@ this.store.selectSnapshot( "inject": true, "bundleName": "fontawesome-v4-shims.min" }, + { + "input": "node_modules/@abp/ng.theme.shared/styles/bootstrap-rtl.min.css", + "inject": false, + "bundleName": "bootstrap-rtl.min" + }, + { + "input": "node_modules/bootstrap/dist/css/bootstrap.min.css", + "inject": true, + "bundleName": "bootstrap-ltr.min" + }, "apps/dev-app/src/styles.scss" ], } @@ -174,6 +174,7 @@ this.store.selectSnapshot( } } } +``` #### 步骤 2. 清除AppComponent中延迟加载的Fontawesome @@ -192,6 +193,32 @@ import { Component } from '@angular/core'; export class AppComponent {} ``` +## 文化名称到语言环境文件名的映射 + +.NET中定义的某些文化名称与Angular语言环境不匹配. 在这种情况下Angular应用程序在运行时会引发如下错误: + +![locale-error](./images/locale-error.png) + +如果你看到这样的错误,你应该像下面这样传递 `cultureNameToLocaleFileNameMapping` 属性到CoreModule的forRoot静态方法. + +```js +// app.module.ts + +@NgModule({ + imports: [ + // other imports + CoreModule.forRoot({ + // other options + cultureNameToLocaleFileNameMapping: { + "DotnetCultureName": "AngularLocaleFileName", + "pt-BR": "pt" // example + } + }) + //... +``` + +查看 [Angular中所有的语言环境文件](https://github.com/angular/angular/tree/master/packages/common/locales). + ## 另请参阅 * [ASP.NET Core中的本地化](../../Localization.md) diff --git a/docs/zh-Hans/UI/Angular/Migration-Guide-v3.md b/docs/zh-Hans/UI/Angular/Migration-Guide-v3.md index 36afffa54f..eb16c21e03 100644 --- a/docs/zh-Hans/UI/Angular/Migration-Guide-v3.md +++ b/docs/zh-Hans/UI/Angular/Migration-Guide-v3.md @@ -18,7 +18,7 @@ yarn ng update @angular/cli @angular/core --force - 更新你的package.json并安装新的软件包 - 修改tsconfig.json文件创建一个"Solution Style"配置 -- 重命名 `browserlist` 为 `.browserlistrc` +- 重命名 `browserslist` 为 `.browserslistrc` 另一方面,如果你单独使用 `yarn ng update` 命令检查首先要更新哪些包会更好. Angular会给你一个要更新的包列表. @@ -144,42 +144,33 @@ export class AppModule {} AppRoutingModule: ```js -import { DynamicLayoutComponent } from '@abp/ng.core'; import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: '', - component: DynamicLayoutComponent, - children: [ - { - path: '', - pathMatch: 'full', - loadChildren: () => import('./home/home.module') - .then(m => m.HomeModule), - }, - { - path: 'account', - loadChildren: () => import('@abp/ng.account') - .then(m => m.AccountModule.forLazy({ redirectUrl: '/' })), - }, - { - path: 'identity', - loadChildren: () => import('@abp/ng.identity') - .then(m => m.IdentityModule.forLazy()), - }, - { - path: 'tenant-management', - loadChildren: () => import('@abp/ng.tenant-management') - .then(m => m.TenantManagementModule.forLazy()), - }, - { - path: 'setting-management', - loadChildren: () => import('@abp/ng.setting-management') - .then(m => m.SettingManagementModule.forLazy()), - }, - ], + pathMatch: 'full', + loadChildren: () => import('./home/home.module').then(m => m.HomeModule), + }, + { + path: 'account', + loadChildren: () => + import('@abp/ng.account').then(m => m.AccountModule.forLazy({ redirectUrl: '/' })), + }, + { + path: 'identity', + loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()), + }, + { + path: 'tenant-management', + loadChildren: () => + import('@abp/ng.tenant-management').then(m => m.TenantManagementModule.forLazy()), + }, + { + path: 'setting-management', + loadChildren: () => + import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()), }, ]; @@ -190,7 +181,7 @@ const routes: Routes = [ export class AppRoutingModule {} ``` -> 你可能已经注意到我们在top级别路由组件上使用了 `DynamicLayoutComponent`. 我们这样做是为了避免不必要的渲染和闪烁. 这不是强制的,但是我们建议在你的应用程序路由中做同样的事情. +> 你可能已经注意到我们在AppComponent模板中使用了 `` 而不是 ``. 我们这样做是为了避免不必要的渲染和闪烁. 这不是强制的,但是我们建议在你的应用程序路由中做同样的事情. #### 如何迁移? @@ -200,7 +191,7 @@ export class AppRoutingModule {} - 调用 `ThemeBasicModule` 的静态 `forRoot` 方法(或商业上的 `ThemeLeptonModule`),并从导入中删除 `SharedModule`(除非已在其中添加了根模块所需的任何内容). - 在app路由模块中直接导入延迟ABP模块 (如 `() => import('@abp/ng.identity').then(...)`). - 在所有延迟模块 `then` 中调用的静态 `forLazy` 方法,即使配置没有被传递. -- [可选]使用 `DynamicLayoutComponent` 添加空的父路由,获得更好的性能和UX. +- [可选]添加 `` 到AppComponent模板并且删除 ``,获得更好的性能和UX. ### RoutesService @@ -233,9 +224,10 @@ export class AppRoutingModule {} 从ABP v3开始,我们已切换到经过严格测试,执行良好的数据表格:[ngx-datatable](https://github.com/swimlane/ngx-datatable). 所有的ABP模块都已经实现了ngx-datatable. `ThemeSharedModule` 已经导出了 `NgxDatatableModule`. 因此如果你在终端运行 `yarn add @swimlane/ngx-datatable` 来安装这个包,它将在你的应用的所有模块中可用. -为了正确设置样式,你需要在angular.json文件的样式部分中添加以下内容: +为了正确设置样式,你需要在angular.json文件的样式部分中添加以下内容(在其他所有元素之上): ```json +"styles": [ { "input": "node_modules/@swimlane/ngx-datatable/index.css", "inject": true, @@ -250,7 +242,9 @@ export class AppRoutingModule {} "input": "node_modules/@swimlane/ngx-datatable/themes/material.css", "inject": true, "bundleName": "ngx-datatable-material" - } + }, + // other styles +] ``` 由于尚未删除 `abp-table`, 因此以前由ABP v2.x构建的模块不会突然丢失所有. 但是它们的外观与内置ABP v3模块有所不同, 因此你可能希望将这些模块中的表转换为ngx-datatable. 为了减少将abp-table转换为ngx-datatable所需的工作量,我们修改了 `ListService` 以使其与 `ngx-datatable` 一起很好地工作,并引入了两个新指令: `NgxDatatableListDirective` 和 `NgxDatatableDefaultDirective`. @@ -348,7 +342,103 @@ export class SomeComponent { - 如果可以的话,根据上面的例子更新你的模. - 如果你稍后需要这样做,并且打算保留abp-table一段时间,请确保根据此处描述的[破坏性更改](List-Service.md)更新分页. -**重要说明:**abp-table没有被删除,但已被弃用并在以后的版本中删除. 请考虑切换到ngx-datatable。 +**重要说明:**abp-table没有被删除,但已被弃用并在以后的版本中删除. 请考虑切换到ngx-datatable. + +### 扩展系统[商业版] + +扩展程序系统现在是开源的, 可以从 `@abp/ng.theme.shared/extensions` 而不是从 `@volo/abp.commercial.ng.ui` 中获取. 同样,根据config软件包的新结构,如上所述通过 `forLazy` 静态方法进行配置. + +#### 如何迁移? + +如果你以前从未使用过扩展系统,则无需执行任何操作. 否则请再次检查文档以查看更改. 扩展系统本身的工作原理与以前相同,唯一的变化是你从中导入的包,静态方法以及您将贡献者传递给的模块. + + +### Lepton 主题Logo [商业版] + +在ABP v2.x中,Lepton每个颜色主题都有一个亮徽标和一个暗徽标. 我们意识到我们可以使它仅使用一个浅色和一个深色徽标. 因此我们更改了Lepton查找徽标图像的方式,现在你只需要在项目中包含 `logo-light.png` 和 `logo-dark.png`. + +#### 如何迁移? + +如果你之前已切换模板徽标PNG,则更改很简单: + +- 转到 `/assets/images/logo` 目录. +- 重命名 `theme1.png` 为 `logo-light.png` 并且重命名 `theme1-reverse.png` 为 `logo-dark.png`. +- 删除所有其他 `theme*.png` 文件. + +如果你更换了徽标组件,则更改有些不同,但仍然很简单. `LayoutStateService` 有两个新成员: `primaryLogoColor` 和 `secondaryLogoColor`. 它们有 `'light'` 和 `'dark'` 设置值做为可观察流. 你可以使用 `async` 管道在自定义徽标组件模板中使用它们的值. 这是一个完整的示例,其中涵盖了主要和辅助(帐户)布局徽标. + +```js +import { AddReplaceableComponent } from '@abp/ng.core'; +import { CommonModule } from '@angular/common'; +import { APP_INITIALIZER, Component, Injector, NgModule } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { eAccountComponents } from '@volo/abp.ng.account'; +import { + AccountLayoutComponent, + eThemeLeptonComponents, + LayoutStateService, +} from '@volo/abp.ng.theme.lepton'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +@Component({ + template: ` + + + + + + `, +}) +export class LogoComponent { + isAccount: boolean; + + logoColor: Observable<'dark' | 'light'>; + + get logoUrl() { + return this.logoColor.pipe(map(color => `url(/assets/images/logo/logo-${color}.png)`)); + } + + constructor(injector: Injector) { + const layout = injector.get(LayoutStateService); + this.isAccount = Boolean(injector.get(AccountLayoutComponent, false)); + this.logoColor = this.isAccount ? layout.secondaryLogoColor : layout.primaryLogoColor; + } +} + +@NgModule({ + imports: [CommonModule], + declarations: [LogoComponent], + exports: [LogoComponent], +}) +export class LogoModule {} + +export const APP_LOGO_PROVIDER = [ + { provide: APP_INITIALIZER, useFactory: switchLogos, multi: true, deps: [Store] }, +]; + +export function switchLogos(store: Store) { + return () => { + store.dispatch( + new AddReplaceableComponent({ + component: LogoComponent, + key: eThemeLeptonComponents.Logo, + }), + ); + + store.dispatch( + new AddReplaceableComponent({ + component: LogoComponent, + key: eAccountComponents.Logo, + }), + ); + }; +} +``` + +只要将 `APP_LOGO_PROVIDER` 添加到根模块的提供程序(通常是 `AppModule` ),你就会有一个调整主题颜色的自定义徽标组件. ### 过时的接口 diff --git a/docs/zh-Hans/UI/Angular/Modifying-the-Menu.md b/docs/zh-Hans/UI/Angular/Modifying-the-Menu.md index 1f4e626bd3..82c1fe41ad 100644 --- a/docs/zh-Hans/UI/Angular/Modifying-the-Menu.md +++ b/docs/zh-Hans/UI/Angular/Modifying-the-Menu.md @@ -2,8 +2,6 @@ 菜单在 @abp/ng.theme.basic包 `ApplicationLayoutComponent` 内部. 有几种修改菜单的方法,本文档介绍了这些方法. 如果你想完全替换菜单,请参考[组件替换文档]了解如何替换布局. - - ## 如何添加Logo 环境变量中的 `logoUrl` 是logo的url. @@ -212,51 +210,65 @@ this.routes.remove(['Your navigation']); ## 如何在菜单的右侧添加元素 -右侧的元素存储在 @abp/ng.theme.basic 包的 `LayoutState` 中. - -`LayoutStateService` 的 `dispatchAddNavigationElement` 方法添加元素到右侧的菜单. - -你可以通过将模板添加到 `app.component` 调用 `dispatchAddNavigationElement` 方法来插入元素: +你可以通过调用 `NavItemsService` 的 `addItems` 方法将元素添加到菜单的右侧. 这是一个单例服务,即以根身份提供. 因此你可以立即注入并使用它. ```js -import { Layout, LayoutStateService } from '@abp/ng.theme.basic'; // added this line +import { NavItemsService } from '@abp/ng.theme.shared'; +import { Component } from '@angular/core'; @Component({ - selector: 'app-root', template: ` - - - + `, }) -export class AppComponent { - // Added ViewChild - @ViewChild('search', { static: false, read: TemplateRef }) searchElementRef: TemplateRef; - - constructor(private layout: LayoutStateService) {} // injected LayoutStateService +export class MySearchInputComponent {} - // Added ngAfterViewInit - ngAfterViewInit() { - const newElement = { - name: 'Search', - element: this.searchElementRef, - order: 1, - } as Layout.NavigationElement; - this.layout.dispatchAddNavigationElement(newElement); +@Component(/* component metadata */) +export class AppComponent { + constructor(private navItems: NavItemsService) { + navItems.addItems([ + { + id: 'MySearchInput', + order: 1, + component: MySearchInputComponent, + }, + { + id: 'SignOutIcon', + html: '', + action: () => console.log('Clicked the sign out icon'), + order: 101, // puts as last element + }, + ]); } } ``` -上面我们在菜单添加了一个搜索输入,最终UI如下: +上面我们在菜单添加了一个搜索输入和退出登录图标,最终UI如下: ![navigation-menu-search-input](./images/navigation-menu-search-input.png) -## 如何删除右侧菜单元素 +> 默认元素的排序为 `100`. 如果要将自定义元素放在默认值之前,请指定一个排序,最高为 `99`. 如果要将自定义元素放在默认值之后,请指定排序从 `101` 开始. 最后如果必须在默认值之间放置一个项目,请按如下所述修补默认元素顺序. 但有一个警告:我们将来可能会添加另一个默认元素,排序也为 `100`. + +## 如何修补或删除右侧部分元素 + +`NavItemsService` 的 `patchItem` 方法通过 `id` 查找元素,并将配置替换为第二个参数传递的新配置. `removeItem` 方法会找到一个元素并删除. + +```js +export class AppComponent { + constructor(private navItems: NavItemsService) { + navItems.patchItem(eThemeBasicComponents.Languages, { + requiredPolicy: 'new policy here', + order: 1, + }); + + navItems.removeItem(eThemeBasicComponents.CurrentUser); + } +} +``` -TODO +* 使用新的 `requiredPolicy` 和新的 `order` 修补了语言下拉菜单元素. +* 删除了当前用户的下拉菜单元素. ## 下一步是什么? diff --git a/docs/zh-Hans/UI/Angular/Permission-Management.md b/docs/zh-Hans/UI/Angular/Permission-Management.md index 5c1ba5b4fb..7f28035105 100644 --- a/docs/zh-Hans/UI/Angular/Permission-Management.md +++ b/docs/zh-Hans/UI/Angular/Permission-Management.md @@ -55,7 +55,9 @@ export class YourComponent { 如果你想要在导航过程中控制经过身份验证的用户对路由的访问权限,可以使用 `PermissionGuard`. -将 `requiredPolicy` 添加到路由模块中的 `routes`属性. +* 从@abp/ng.core导入PermissionGuard. +* 添加 `canActivate: [PermissionGuard]` 到你的路由对象. +* 添加 `requiredPolicy` 到路由模块路由的 `data` 属性. ```js import { PermissionGuard } from '@abp/ng.core'; @@ -66,9 +68,7 @@ const routes: Routes = [ component: YourComponent, canActivate: [PermissionGuard], data: { - routes: { - requiredPolicy: 'AbpIdentity.Roles.Create', - }, + requiredPolicy: 'YourProjectName.YourComponent', // policy key for your component }, }, ]; diff --git a/docs/zh-Hans/UI/Angular/Service-Proxies.md b/docs/zh-Hans/UI/Angular/Service-Proxies.md index 29aafebdae..2824bc44a7 100644 --- a/docs/zh-Hans/UI/Angular/Service-Proxies.md +++ b/docs/zh-Hans/UI/Angular/Service-Proxies.md @@ -33,7 +33,7 @@ abp generate-proxy 服务的 `providerIn` 属性定义为 `'root'`. 因此无需将服务作为提供程序添加到模块. 你可以通过将服务注入到构造函数中来使用它,如下所示: ```js -import { AbpApplicationConfigurationService } from '../app/shared/services'; +import { AbpApplicationConfigurationService } from '../abp/applicationconfiguration/services'; //... export class HomeComponent{ @@ -49,14 +49,14 @@ Angular编译器会从最终输出中删除那些没有被注入的服务. 参 ### Models -生成的模型与后端中的dto匹配. 每个模型在 `src/app/*/shared/models` 文件夹生成一个类. +生成的模型与后端中的dto匹配. 每个模型在 `src/app/*/models` 文件夹生成一个类. `@abp/ng.core` 包有一些[基类](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/dtos.ts). 一些模型扩展了这些类. 可以如下所示创建一个类的实例: ```js -import { IdentityRoleCreateDto } from '../identity/shared/models'; +import { IdentityRoleCreateDto } from '../identity/role/models' //... const instance = new IdentityRoleCreateDto({name: 'Role 1', isDefault: false, isPublic: true}) ``` diff --git a/docs/zh-Hans/UI/Angular/Subscription-Service.md b/docs/zh-Hans/UI/Angular/Subscription-Service.md new file mode 100644 index 0000000000..fb248d4d95 --- /dev/null +++ b/docs/zh-Hans/UI/Angular/Subscription-Service.md @@ -0,0 +1,205 @@ +# 轻松取消将你的观察取消订阅 + +`SubscriptionService` 是一个实用工具服务,它提供了一个简单的取消订阅Angular组件和指令中的RxJS可观察对象的功能. 请参见[为什么在实例销毁时要取消订阅可观察对象](https://angular.io/guide/lifecycle-hooks#cleaning-up-on-instance-destruction). + +## 入门 + +你必须在组件或指令级别提供 `SubscriptionService`,因为它没有在**根中提供**,而且它与组件/指令的生命周期同步. 只有在此之后,您才能注入并开始使用它。 + +```js +import { SubscriptionService } from '@abp/ng.core'; + +@Component({ + /* class metadata here */ + providers: [SubscriptionService], +}) +class DemoComponent { + count$ = interval(1000); + + constructor(private subscription: SubscriptionService) { + this.subscription.addOne(this.count$, console.log); + } +} +``` + +由 `count$` 发出的值将被记录下来,直到组件被销毁. 你不必手动退订. + +> 请不要尝试使用单例 `SubscriptionService`. 这是行不通的. + +## 用法 + +## 如何订阅可观察对象 + +你可以传递 `next` 函数和 `error` 函数. + + + +```js +@Component({ + /* class metadata here */ + providers: [SubscriptionService], +}) +class DemoComponent implements OnInit { + constructor(private subscription: SubscriptionService) {} + + ngOnInit() { + const source$ = interval(1000); + const nextFn = value => console.log(value * 2); + const errorFn = error => { + console.error(error); + return of(null); + }; + + this.subscription.addOne(source$, nextFn, errorFn); + } +} +``` + +或者,你可以传递一个观察者. + +```js +@Component({ + /* class metadata here */ + providers: [SubscriptionService], +}) +class DemoComponent implements OnInit { + constructor(private subscription: SubscriptionService) {} + + ngOnInit() { + const source$ = interval(1000); + const observer = { + next: value => console.log(value * 2), + complete: () => console.log('DONE'), + }; + + this.subscription.addOne(source$, observer); + } +} +``` + +`addOne` 方法返回单个订阅以便你以后使用它. 有关详细信息,请参见下面的主题. + +### 实例销毁之前如何退订 + +有两种方法可以做到这一点. 如果你不想再次订阅.可以使用 `closeAll` 方法. + +```js +@Component({ + /* class metadata here */ + providers: [SubscriptionService], +}) +class DemoComponent implements OnInit { + constructor(private subscription: SubscriptionService) {} + + ngOnInit() { + this.subscription.addOne(interval(1000), console.log); + } + + onSomeEvent() { + this.subscription.closeAll(); + } +} +``` + +这将清除所有订阅,你将无法再次订阅. 如果你打算添加另一个订阅,可以使用`reset`方法. + +```js +@Component({ + /* class metadata here */ + providers: [SubscriptionService], +}) +class DemoComponent implements OnInit { + constructor(private subscription: SubscriptionService) {} + + ngOnInit() { + this.subscription.addOne(interval(1000), console.log); + } + + onSomeEvent() { + this.subscription.reset(); + this.subscription.addOne(interval(1000), console.warn); + } +} +``` + +### 如何取消单个订阅 + +有时你可能需要取消订阅特定的订阅,但保留其他订阅. 在这种情况下,你可以使用 `closeOne` 方法. + +```js +@Component({ + /* class metadata here */ + providers: [SubscriptionService], +}) +class DemoComponent implements OnInit { + countSubscription: Subscription; + + constructor(private subscription: SubscriptionService) {} + + ngOnInit() { + this.countSubscription = this.subscription.addOne( + interval(1000), + console.log + ); + } + + onSomeEvent() { + this.subscription.closeOne(this.countSubscription); + console.log(this.countSubscription.closed); // true + } +} +``` + +### 如何从跟踪的订阅中删除单个订阅 + +你可能需要控制特定的订阅. 在这种情况下你可以使用 `removeOne` 方法将其从跟踪的订阅中删除. + +```js +@Component({ + /* class metadata here */ + providers: [SubscriptionService], +}) +class DemoComponent implements OnInit { + countSubscription: Subscription; + + constructor(private subscription: SubscriptionService) {} + + ngOnInit() { + this.countSubscription = this.subscription.addOne( + interval(1000), + console.log + ); + } + + onSomeEvent() { + this.subscription.removeOne(this.countSubscription); + console.log(this.countSubscription.closed); // false + } +} +``` + +### 如何检查是否全部取消订阅 + +使用 `isClosed` 检查 `closeAll` 是否被调用. + +```js +@Component({ + /* class metadata here */ + providers: [SubscriptionService], +}) +class DemoComponent implements OnInit { + constructor(private subscription: SubscriptionService) {} + + ngOnInit() { + this.subscription.addOne(interval(1000), console.log); + } + + onSomeEvent() { + console.log(this.subscription.isClosed); // false + } +} +``` + +## 下一步是什么? + +- [ListService](./List-Service.md) diff --git a/docs/zh-Hans/UI/Angular/Track-By-Service.md b/docs/zh-Hans/UI/Angular/Track-By-Service.md index 53c9dcbf1c..f941b1f0ca 100644 --- a/docs/zh-Hans/UI/Angular/Track-By-Service.md +++ b/docs/zh-Hans/UI/Angular/Track-By-Service.md @@ -99,4 +99,4 @@ class DemoComponent { ## 下一步是什么? -- [ListService](./List-Service.md) \ No newline at end of file +- [SubscriptionService](./Subscription-Service.md) \ No newline at end of file diff --git a/docs/zh-Hans/UI/Angular/images/custom-settings.png b/docs/zh-Hans/UI/Angular/images/custom-settings.png index 05dd3f695a..dc40ad3fa9 100644 Binary files a/docs/zh-Hans/UI/Angular/images/custom-settings.png and b/docs/zh-Hans/UI/Angular/images/custom-settings.png differ diff --git a/docs/zh-Hans/UI/Angular/images/generated-files-via-generate-proxy.png b/docs/zh-Hans/UI/Angular/images/generated-files-via-generate-proxy.png index 77a120a35d..0d062cc2d3 100644 Binary files a/docs/zh-Hans/UI/Angular/images/generated-files-via-generate-proxy.png and b/docs/zh-Hans/UI/Angular/images/generated-files-via-generate-proxy.png differ diff --git a/docs/zh-Hans/UI/Angular/images/locale-error.png b/docs/zh-Hans/UI/Angular/images/locale-error.png new file mode 100644 index 0000000000..de385a59c0 Binary files /dev/null and b/docs/zh-Hans/UI/Angular/images/locale-error.png differ diff --git a/docs/zh-Hans/UI/Angular/images/navigation-menu-search-input.png b/docs/zh-Hans/UI/Angular/images/navigation-menu-search-input.png index ebdc05e3e0..e93b7927d1 100644 Binary files a/docs/zh-Hans/UI/Angular/images/navigation-menu-search-input.png and b/docs/zh-Hans/UI/Angular/images/navigation-menu-search-input.png differ diff --git a/docs/zh-Hans/UI/AspNetCore/Dynamic-JavaScript-Proxies.md b/docs/zh-Hans/UI/AspNetCore/Dynamic-JavaScript-Proxies.md new file mode 100644 index 0000000000..391a63a910 --- /dev/null +++ b/docs/zh-Hans/UI/AspNetCore/Dynamic-JavaScript-Proxies.md @@ -0,0 +1,3 @@ +# Dynamic JavaScript HTTP API Proxies + +TODO \ No newline at end of file diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 683bf750c0..a3ffaaea38 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -440,6 +440,10 @@ "text": "TrackByService", "path": "UI/Angular/Track-By-Service.md" }, + { + "text": "SubscriptionService", + "path": "UI/Angular/Subscription-Service.md" + }, { "text": "ListService", "path": "UI/Angular/List-Service.md"