GVKun编程网logo

Azure上的Angular2应用程序“您无权在子路由上查看此目录或页面”(azure application insight)

16

对于想了解Angular2–来自JSON数据的动态路由的读者,本文将是一篇不可错过的文章,我们将详细介绍angularjs路由原理,并且为您提供关于Angular4动态路由、Angular6Meta服

对于想了解Angular 2 – 来自JSON数据的动态路由的读者,本文将是一篇不可错过的文章,我们将详细介绍angularjs路由原理,并且为您提供关于Angular 4动态路由、Angular 6 Meta服务,包含来自Web服务的动态元数据、Angular JS POST请求未发送JSON数据、Angular 学习系列 - - angular.uppercase、angular.lowercase、angular.fromJson、angular.toJson的有价值信息。

本文目录一览:

Angular 2 – 来自JSON数据的动态路由(angularjs路由原理)

Angular 2 – 来自JSON数据的动态路由(angularjs路由原理)

在Angular 2.0 stable中,我有一个应用程序,我必须根据收到的 JSON数据定义/配置路由.我没有任何预定义的路由.我在我的bootstrap组件的构造函数中获取此数据.

我怎样才能实现这一目标?可能吗?

解决方法

我实现这一点的方法是在引导角应用程序之前加载路由.这样,当应用程序启动时,所有动态路由都已存在.

所以你必须在platformbrowserDynamic()之前加载main.ts文件中的所有路由.bootstrapModule(AppModule);线.

下面是main.ts文件的示例,其中路由作为json获取并在引导之前加载.

import { enableProdMode } from '@angular/core';
import { platformbrowserDynamic } from '@angular/platform-browser-dynamic';

import { environment } from './environments/environment';
import { AppModule } from './app/app.module';
import { IRoute,IRouteData } from './core/models/route';
import { getComponent } from './core/utils/type-component-mapper';

import { AppRoutes } from './app/app.routes';

export function main() {
    console.log('[main]')
    return platformbrowserDynamic()
        .bootstrapModule(AppModule)
        .catch(err => console.error(err));
}

switch (document.readyState) {
    case 'interactive':
    case 'complete':
        getRoutes();
        break;
    case 'loading':
    default:
        document.addEventListener('DOMContentLoaded',() => getRoutes());
}

function getRoutes() {
    // This is where you load the routes json from your api
    fetch(environment.apiUrl + '/api/routes/get').then((value: Response)  =>                         
    {
        return value.json();
    }).then((routes: IRoute[]) => {
        routes.forEach((o: IRoute) => {
            iterate(o);
        });

        // add each dynamic route to the angular route collection
        AppRoutes.unshift(routes[0]);

        // all dynamic routes have been added,start the angular app
        main();
    });
}

function iterate(route: IRoute) {
    var children = route.children;
    if (children) {
        Array.from(children).forEach((o: IRoute) => {
            iterate(o)
        });
    }

    var component = getComponent(route.data.type);
    if (component) {
            route.component = component;
    }
}

在这个例子中,从api返回的路径json将采用以下形式:

[{
    "path" : Shop,"data" : {
        "type" : ShopPage
    },"children" : [{
        "path" : Bread,"data" : {
            "type" : ProductPage
        }
    },{
        "path" : Milk,"data" : {
            "type" : ProductPage
        }
    }]
}]

此Json数据被解析为IRoute和IRouteData类型:

export interface IRoute {
    path: string;
    data: IRouteData;
    children?: IRoute[];
}

export interface IRouteData {
    type: string;
}

导出AppRoutes const也很重要,这样您就可以将新的动态路由推送到AppRoutes集合.它看起来像这样:

export const AppRoutes: Routes = [
    {
        path: 'hardCodedWelcome',component: WelcomeComponent
    }
];

您还需要为每个路径添加正确的组件.在这种情况下,我会对数据类型属性进行切换以获取正确的组件.这就是我从类型组件映射器文件导入get组件函数的原因,如下所示:

import { Router,Route } from '@angular/router';

import { Type } from '@angular/core';
import { PageTypes } from './page-types';
import { ShopComponent } from '../../app/Shop/shop.component';
import { ProductComponent } from '../../app/Product/Product.component';

export function getComponent(type: string): Type<any> {
    switch (type) {
        case PageTypes.Shop: {
            return ShopComponent;
        }
        case PageTypes.Product: {
            return ProductComponent;
        }
    }
}

这里的页面类型只是一个简单的页面类型列表,所以我不必使用魔术字符串.

export const PageTypes = {
    Shop: 'ShopPage',Product: 'ProductPage',};

当应用程序启动时,路径集合中的所有动态路径都可以通过角度正常解析.这会为应用程序增加一些启动时间,具体取决于有多少路由.但是一旦应用程序启动,所有路由都在config routes集合中,并且对性能没有进一步的影响.

请注意,仅当AOT为false时才有效.如果你想在AOT中使用它,你必须将路由器注入app.component构造函数,然后添加以下行:router.resetConfig(allRoutes);其中所有路由都是您在引导之前将路由推送到的数组.

Angular 4动态路由

Angular 4动态路由

我想在angular 4应用程序中实现动态路由.我想要做的是将新的Route对象推送到Router config.代码看起来像

@
NgModule({
declarations: [
    AppViewComponent
],imports: [
    RouterModule.forRoot([
        { path: '',redirectTo: 'home',pathMatch: 'full' },{ path: 'home',component: HomeComponent },{ path: 'appview',component: AppViewComponent }
        { path: '**',redirectTo: 'home' }
    ])
],providers: []})


export class AppModuleShared {
constructor(router: Router,routerModule: RouterModule) {
    console.log('Routes: ',JSON.stringify(router.config,undefined,1));
    router.config.push({ path: 'new/random/path',component: AppViewComponent });
    router.config.forEach((x,i) => {
        console.log(`${i}: ${JSON.stringify(x,1)}`);
    });
}}

当应用程序启动时,我想将新的Route Object推送到配置并转到构造函数中的新路径.执行构造函数后,在控制台日志中我有这样的事情:

5: {
    "path": "new/random/path"
}

看起来新的Route Object被成功推送到配置数组,但是当我尝试进入这个新的路径时,应用程序将我重定向到主页.你能告诉我我做错了什么吗?

解决方法

使用unshift而不是push

例:router.config.unshift({path:’new / random / path’,component:AppViewComponent});

Angular 6 Meta服务,包含来自Web服务的动态元数据

Angular 6 Meta服务,包含来自Web服务的动态元数据

我正在尝试使用从Web服务检索的数据来更新Angular 6(更新:现在的Angular 7)Universal应用程序(使用Meta和Title)中的元数据.我专门为Twitter和Facebook卡做这个.我知道他们的抓取工具不执行 JavaScript,这就是我使用Angular Universal在服务器端设置元数据的原因.我正在使用 Facebook Sharing debugger tool检查结果.

我尝试了几种不同的方法,并且我已经找到了示例,但是我没有找到一个在设置元数据之前从对Web服务的异步调用中检索数据的方法. (请注意,我在Angular Universal 4应用程序中成功使用此服务与Web服务.)

使用下面的代码,“og:url”标记被正确设置为不需要Web服务调用来获取数据.但是,标题未正确设置.如果我将“setTitle”调用移动到ngOnInit并提供一个字符串,那么它可以工作 – 但是从Web服务获取数据却没有.

我已经尝试使用服务来收集数据然后设置元数据,但这也不起作用.我从解析器获取数据,但它没有解决Facebook / Twitter问题.

ngOnInit() {
    const MetaUrl = 'https://www.test.com' + this._router.url;
    this._MetaService.updateTag({ property: 'og:url',content: MetaUrl });

    this._sub = this._route.params.subscribe(params => {
      const code = params['person'];
      this.getInfo(code);
    });
}

getInfo(code: string) {
  this._myWebService.getPerson(code).subscribe(
      data => {
        this._person = data;
        // set dynamic Metadata
        const MetaTitle = this._person.name + ' | site description';
        this._titleService.setTitle(MetaTitle);
        this._MetaService.updateTag({ name: 'twitter:title',content: MetaTitle });
  });

}

更新:我还尝试使用解析器首先获取数据,以便我可以在onInit中使用它.它不起作用.

{ path: 'view/:person',component: ViewComponent,resolve: { person: ViewResolver },data: { person: ViewResolver }
  }

然后在onInit:

const data: any = this._routeActive.snapshot.data;
this.MetaTitle = data.person.value.name;
this._MetaService.updateTag({property: 'og:title',content: this.MetaTitle });
this._MetaService.updateTag({name: 'twitter:title',content: this.MetaTitle });
我找到了解决方案.在决定这不一定是代码问题之后,我去了 Angular Universal starter repo并更新了我的配置(例如,tsconfig.json,angular.json等)直到它工作.我的项目已升级了几次,我没有复制起始仓库的所有更改.

Angular JS POST请求未发送JSON数据

Angular JS POST请求未发送JSON数据

如何解决Angular JS POST请求未发送JSON数据?

如果你要序列化数据对象,那么它将不是正确的json对象。充分利用现有内容,然后将数据对象包装在中JSON.stringify()。

$http({
    url: ''/user_to_itsr'',
    method: "POST",
    data: JSON.stringify({application:app, from:d1, to:d2}),
    headers: {''Content-Type'': ''application/json''}
}).success(function (data, status, headers, config) {
    $scope.users = data.users; // assign  $scope.persons here as promise is resolved here 
}).error(function (data, status, headers, config) {
    $scope.status = status + '' '' + headers;
});

解决方法

我正在尝试将一个对象作为JSON发送到Flask中的Web服务,该对象期望请求数据中包含JSON。

我已经通过发送JSON数据手动测试了该服务,并且工作正常。但是,当我尝试通过角度控制器发出http POST请求时,Web服务器向我发送一条消息,说它未接收到JSON。

当我检查Chrome中的请求标头时,似乎不是以JSON格式发送数据,而是通过内容类型将常规键/值对设置为application / json

Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:application/json,text/plain,/
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:49
Content-Type:application/json;charset=UTF-8
DNT:1
Host:localhost:5000
Origin:http://localhost:5000
Referer:http://localhost:5000/
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/27.0.1453.116 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payload
application=AirFare&d1=10-APR-2013&d2=14-APR-2013
如果您看到了请求有效载荷下面的最后一行,则可以看到数据不是JSON格式。

这是我的角度控制器中的HTTP POST调用:

$http({
url: ‘/user_to_itsr’,
method: “POST”,
data: {application:app,from:d1,to:d2},
headers: {‘Content-Type’: ‘application/json’}
}).success(function (data,status,headers,config) {
$scope.users = data.users; // assign $scope.persons here as promise is resolved here
}).error(function (data,config) {
$scope.status = status + ‘ ‘ + headers;
});
};
我将数据作为对象{}发送,但是在JSON.stringify进行序列化之后,我尝试发送数据,但是,我似乎没有任何操作将JSON发送到服务器。

真的很感谢有人能帮忙。

Angular 学习系列 - - angular.uppercase、angular.lowercase、angular.fromJson、angular.toJson

Angular 学习系列 - - angular.uppercase、angular.lowercase、angular.fromJson、angular.toJson

高春辉、王春生、朱峰:关于开源创业的 15 件小事

angular.uppercase

将指定的字符串转换成大写

格式:angular.uppercase(string);

string: 被转换成大写的字符串。

使用代码:

var str = "ABCabc";  var upperCase = angular.uppercase(str);//ABCABC

angular.lowercase

将指定的字符串转换成小写

格式:angular.lowercase(string);

string: 被转换成小写的字符串。

使用代码:

 var str = "ABCabc";  var lowerCase = angular.lowercase(str);//abcabc

这两个方法的翻译也不是很难,也很容易理解。我们在做比较或者做一些字符串处理的时候,需要把大小写都存在的字符串转换为全部大写或者全部小写,这两个方法就是在这时候使用的...

angular. fromJson

反序列化 JSON 字符串

格式:angular.fromJson(str)

str: json 格式的字符串

使用代码:

var str = ''[{ "name""A""age""1" }, { "name""B""age""2" }, { "name""C""age""3" }]'';var con = angular.fromJson(str);//con=[{ "name""A""age""1" }, { "name""B""age""2" }, { "name""C""age""3" }]

angular. toJson

序列化 JSON 字符串

格式:angular.toJson(str)

str: 要转 string(json 格式的字符串)的 json 数据。

使用代码:

var str = [{ "name""A""age""1" }, { "name""B""age""2" }, { "name""C""age""3" }];var con = angular.toJson(str);  //con = "[{ \"name\": \"A\", \"age\": \"1\" }, { \"name\": \"B\", \"age\": \"2\" }, { \"name\": \"C\", \"age\": \"3\" }]"

以上是这两个方法的使用,angular.fromJson 是将 json 格式的字符串转换为 json 格式数据,江湖人称 “反序列化 JSON 字符串”;angular.toJson 是将 json 格式的数据转换 “json 格式的字符串”(虽然有点绕口,但其本质是字符串),江湖人称 “序列化 JSON 字符串”。

今天关于Angular 2 – 来自JSON数据的动态路由angularjs路由原理的介绍到此结束,谢谢您的阅读,有关Angular 4动态路由、Angular 6 Meta服务,包含来自Web服务的动态元数据、Angular JS POST请求未发送JSON数据、Angular 学习系列 - - angular.uppercase、angular.lowercase、angular.fromJson、angular.toJson等更多相关知识的信息可以在本站进行查询。

在本文中,我们将给您介绍关于angular-cli路由器延迟加载的详细内容,并且为您解答angular路由懒加载的相关问题,此外,我们还将为您提供关于Angular 4延迟加载,命名路由器插座无法正常工作、Angular 4延迟加载参数、Angular 4延迟加载和路由不起作用、Angular 9-无法停用延迟加载的模块上的路由器出口的知识。

本文目录一览:

angular-cli路由器延迟加载(angular路由懒加载)

angular-cli路由器延迟加载(angular路由懒加载)

我正在尝试运行一个示例Web应用程序来了解Angular模块的延迟加载是如何工作的.我通过使用角度2.4.1的angular-cli 1.0.0-beta.24生成了应用程序.我生成了核心应用程序,然后是3个组件.然后我在应用程序级别添加了路由,并通过将组件导入app模块直接引用前两个组件.对于第三个组件,我只是使用 Angular routing docs中指定的loadChildren方法添加路由.我的主应用程序的路由配置如下:

const appRoutes: Routes  = [
    { path: 'comp1',component: Comp1Component},{ path: 'comp2',component: Comp2Component},{ path: 'comp3',loadChildren: 'app/comp3/comp3.module'}
];

export default RouterModule.forRoot(appRoutes);

我将第三个组件的代码转换为模块,并将所有从应用程序导入到第三个组件.该模块的路由配置如下:

const routes: Routes = [
    {path: '',component:Comp3Component}
];

export default RouterModule.forChild(routes);

当我运行应用程序时,Comp1和Comp2的路由工作正常,当我单击Comp3的链接(模块路由)时,我得到以下错误记录到控制台:

EXCEPTION: Uncaught (in promise): Error: Cannot find module ./comp3/comp3.module'.
Error: Cannot find module './comp3/comp3.module'.
    at webpackEmptyContext (http://localhost:4200/main.bundle.js:77:8) [angular]

似乎webpack没有处理延迟加载.我已尝试过“loadChildren”调用的各种路径变体,包括:

loadChildren: 'app/comp3/comp3.module#Comp3Module'

没有改变行为(仍然得到上面的错误). angular2的新功能可能是我的代码中的内容,但我看到其他人得到了相同的错误.我的google / stackoverflow foo并未引导我找到解决方案.
我加了我的sample app to my Github account here.

I saw this issue logged by another developer with the Angular team but they kicked it as a support issue to StackOverflow because the sample worked on plunkr.我确定那里有一个线索,但是我对webpack并不是很了解,以及它是如何找到应用程序的plunkr与ng服务运行中的差异所做的.

添加其他信息.该应用程序的html模板如下所示:(also available on github repo):

<h1>
    {{title}}
 </h1>
 <ul>
    <li><arouterLink="/comp1" routerLinkActive="active">Component 1</a></li>
    <li><arouterLink="/comp2" routerLinkActive="active">Component 2</a></li>
    <li><arouterLink="/comp3" routerLinkActive="active">Component 3</a></li>
  </ul>
  <p></p>
  <router-outlet></router-outlet>

我复制了这个应用程序的源代码树(从src / app下来)到angular2 seed project,并且有一些小的预期tweek,它在那里运行良好,并且在angular-cli设置的环境中继续失败.我对TS源的唯一更改是使用相对路径:

{ path: 'comp3',loadChildren: './comp3/comp3.module#Comp3Module'}

用于loadChildren调用.我更改了我的Github示例代码以反映此更新,但它仍然在angular-cli环境下失败.

解决方法

更改你的comp3.routes.ts:

export default RouterModule.forChild(routes);

至:

export const comp3Routing = RouterModule.forChild(routes);

在你的comp3.module.ts替换:

import comp3Routes from "./comp3.routes";

至:

import { comp3Routing } from "./comp3.routes";

最后导入comp3Routing,所以看起来应该是这样的:

@NgModule({
    imports: [
        CommonModule,RouterModule,comp3Routing,],declarations: [
        Comp3Component
    ],exports: [
        Comp3Component
    ],providers: [],})
export class Comp3Module { }

你的comp3的延迟加载应该工作.

Angular 4延迟加载,命名路由器插座无法正常工作

Angular 4延迟加载,命名路由器插座无法正常工作

我有一个延迟加载的问题,而不是路由到指定的路由器插座.有人可以看看我错在哪里吗?我有一个主页,其中有一个指向Product的产品 – >默认路由器插座和产品详细信息 – >命名路由器插座.
<div>
   <div><a [routerLink]="['product']"> Product </a> </div>
   <div><a [routerLink]="['productdetail',{outlets:{productdetail: 'detail'}}]"> Product Detail </a> </div>
  <div> <router-outlet></router-outlet></div>
  <div> <router-outlet name="detail"></router-outlet>
</div>

以下是plunker代码.

Plunker Code

这是已知的bug,你可以跟踪问题 here

The workaround or we can say solution to this issue is,use non-empty paths for your top
level routes if auxilary(i.e. named) routes exist in a lazy loaded module.

我能看到的唯一缺陷是,在路线中增加了一个额外的网址段

MainRoutingModule:顶级非空路径(即“路径:’加载’”)

import { ModuleWithProviders,NgModule } from '@angular/core';
import { Routes,RouterModule } from '@angular/router';

import { MainpageComponent } from './mainpage.component';
import { ProductComponent } from './product.component';
import { ProductDetailComponent } from './productdetail.component';

const childroutes: Routes = [

 { path: 'load',component: MainpageComponent,children: [ 
      {path: 'product',component: ProductComponent
      {path: 'productdetail',component: ProductDetailComponent,outlet: 'detail' 
      },]
 },];

export const routing: ModuleWithProviders = RouterModule.forChild(childroutes);

const newLocal: NgModule = {
    imports: [RouterModule.forChild(childroutes) ],exports: [RouterModule,],declarations: []
};

@NgModule(newLocal)


export class MainRoutingModule { }

MainpageComponent:使用辅助路由的正确语法.

[routerLink]=”[{outlets:{detail:[‘productdetail’]}}]”

import { Component,OnInit,ViewEncapsulation } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-main',template: `
  <div>

  <div><a [routerLink]="['product']"> Product </a> </div>
  <div><a [routerLink]="[{outlets:{detail:['productdetail']}}]"> Product Detail </a> </div>
  <div> <router-outlet></router-outlet></div>
  <div> <router-outlet name="detail"></router-outlet>

</div>
  `,encapsulation: ViewEncapsulation.None,})

export class MainpageComponent {}

LoginComponent:

Use [routerLink]=”[‘mainpage/load’]” to load the main module.

import { Component,OnDestroy } from '@angular/core';

@Component({
  selector: 'app-login',template: `This is login page place holder <br> <a [routerLink]="['mainpage/load']">Go to Main Page</a>`,})

export class LoginComponent implements Oninit,OnDestroy {
constructor() {}

ngOnInit(): void {}

}

演示:https://plnkr.co/edit/0ZpNL3lvbRbexLzQqRZh?p=preview

Angular 4延迟加载参数

Angular 4延迟加载参数

您好我试图延迟加载“详细模块”,同时通过URL发送参数.

这是我的懒加载路线:

{
    path: 'venue/:name/:id',loadChildren: () => System.import('../containers/activity-detail/activity-detail.module').then((file: any) => {
        return file.default;
    })
},

我想路由到这个’activity-detail.module’,然后使用“:name”和“id:”参数加载详细信息.

加载的模块有自己的路由文件.

export const VenueDetailRoutes: Route[] = [
    {
        path: '',redirectTo: 'venue/:name/:id',pathMatch: 'full'
    },{
        path: 'venue/:name/:id',component: VenueDetailComponent,data: {
            shouldDetach: true,// Route will be resused. See CustomresuseStrategy.
            title: null
        }
    },{
        path: '**',redirectTo: '/'
    }

];

似乎没有第一个默认对象没有任何作用.我收到错误:

{
    path: '',pathMatch: 'full'
},TypeError: Cannot read property 'path' of null

使用默认对象我得到错误:

Error: Cannot redirect to 'venue/:name/:id'. Cannot find ':name'.

任何帮助将不胜感激.

解决方法

我认为这不起作用:

{
    path: '',

它无法匹配带参数的路径的“空”路径.

延迟加载路由的语法比我的复杂得多.我看起来像这样:

{
    path: 'movies',loadChildren: './movies/movie.module#MovieModule'
},

请注意,“父”路由(此示例中为“电影”)在延迟加载的路由中定义,并且不会在加载的模块路由中重复.

例如:

RouterModule.forChild([
  { path: '',component: MovieListComponent },{ path: 'search',component: MovieSearchComponent },{ path: ':id',component: MovieDetailComponent }
])

在你的情况下,我认为加载模块的路由应该如下所示:

export const VenueDetailRoutes: Route[] = [
    {  
       path: ':name/:id',// Route will be resused. See CustomresuseStrategy.
            title: null
        }
    }    
];

(尽管您可能需要考虑在基本路由工作之前不要使用自定义重用策略.)

Angular 4延迟加载和路由不起作用

Angular 4延迟加载和路由不起作用

我有一个模块与我的应用程序的路线.其中一条路线是延迟加载模块.

问题是这个延迟加载模块内部有子组件的路由.但是在我的路由器配置上这条路线没有出现……所以当我打电话给懒人模块时,我的屏幕上没有显示任何内容.

这是我的路由器配置(主模块):

export const MODULE_ROUTES: Route[] =[
    { path: '',redirectTo: 'dashboard',pathMatch: 'full' },{ path: 'dashboard',component: HomeComponent,canActivate: [AuthGuard] },{ path: 'calendar',loadChildren: 'app/dashboard/calendar/calendar-module.module#CalendarModuleModule',canActivate: [AuthGuard]},{ path: '**',component: nopageFoundComponent,pathMatch: 'full' }
]
.
.
.


@NgModule({
    imports: [
        RouterModule.forChild(MODULE_ROUTES)
.
.
.

在我的懒惰模块上:

export const MODULE_CALENDAR_ROUTES: Route[] = [
    {
        path: 'calendar',component: CalendarComponent,canActivateChild: [AuthGuard,CalendarGuard],children: [
            {
                path: '',component: MainCalendarComponent,CalendarGuard]
            },{

                path: 'user',component: EditEventComponent,CalendarGuard]
            }
        ]
    }
]

.
.
.

@NgModule({
    imports: [
        SharedModule,.
.
.
        RouterModule.forChild(MODULE_CALENDAR_ROUTES)

如果我打印我的路由器配置,我的懒惰模块上的路由声明不显示:

Routes:  [
  {
    "path": "dashboard","canActivate": [
      null
    ]
  },{
    "path": "calendar","loadChildren": "app/dashboard/calendar/calendar-module.module#CalendarModuleModule",{
    "path": "**","pathMatch": "full"
  },{
    "path": "dashboard"
  }
]

你能帮助我吗?

解决方法

问题在于我在懒惰模块上声明我的路线的方式:

export const MODULE_CALENDAR_ROUTES: Route[] = [
    {
        path: 'calendar',CalendarGuard]
            }
        ]
    }
]

CalendarComponent的路径必须从以下更改:

path: 'calendar',// wrong
component: CalendarComponent,...

到下面:

path: '',// right
component: CalendarComponent,...

感谢@jotatoledo on gitter帮助我解决这个问题.

Angular 9-无法停用延迟加载的模块上的路由器出口

Angular 9-无法停用延迟加载的模块上的路由器出口

我想这与延迟加载无关。 您只需通过实现组件的 ngOnDestroy()即可重置条件,该组件会在单击“后退”按钮时呈现。

,

我已经找到了这种解决方法(丑陋,恕我直言)。在包含 router-outlet 指令的组件中,我订阅了 router事件以跟踪首次激活Router-Outlet时URL中的更改。然后,当url更改回与父组件路径匹配的URL时,我将停用路由器出口。

onActiveOutlet(component: Component) {
    let previousUrl = this.router.url;
        this.router.events.subscribe(
          event => {
            if (event instanceof NavigationEnd) {
              if (previousUrl != this.router.url && previousUrl.includes(this.router.url)) {
                this.outlet.deactivate();
              }
            }
        }
    )
}

在父组件模板中,只需捕获插座激活时发出的事件

<router-outlet #outlet="outlet" name='lto-list' (activate)='onActiveOutlet($event)' ></router-outlet>

关于angular-cli路由器延迟加载angular路由懒加载的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Angular 4延迟加载,命名路由器插座无法正常工作、Angular 4延迟加载参数、Angular 4延迟加载和路由不起作用、Angular 9-无法停用延迟加载的模块上的路由器出口等相关知识的信息别忘了在本站进行查找喔。

本文将介绍Angular 2子路由是否会刷新父路由的详细情况,特别是关于angular多级路由的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于Angular 2 RC5子路由问题、Angular 2使用子路由进行身份验证、Angular 2路由器在路由时刷新页面、Angular 2:共享相同解析器的兄弟姐妹子路由的知识。

本文目录一览:

Angular 2子路由是否会刷新父路由(angular多级路由)

Angular 2子路由是否会刷新父路由(angular多级路由)

我有一个应用程序,在某些情况下我在父路由的子路由之间路由.一个看起来像example.com/a/1/另一个example.com/a/2/将从1切换到2触发重新加载/渲染页面a?

就像在视频中播放视频并将路径出口视为该视频的兄弟一样,此页面更改是否会触发视频重新加载?

如果是这样,可以预防吗?

解决方法

不,它不会.如果您离开它,然后再次导航到父组件,则只会刷新父组件.

Angular 2 RC5子路由问题

Angular 2 RC5子路由问题

我试图让子路由工作,这是我得到的错误:

EXCEPTION: Error: Uncaught (in promise): Error: Cannot match any routes: 'settings'

这是我的app.modules.ts

import { browserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { routeComponents,routing,appRoutingProviders } from './app.routes';


@NgModule({
    declarations: [
        AppComponent,routeComponents
    ],imports: [
        browserModule,CommonModule,FormsModule,routing
    ],providers: [ appRoutingProviders ],entryComponents: [AppComponent],bootstrap: [AppComponent]
})
export class AppModule {

}

这是我的app.routes.ts

import { Routes,RouterModule } from '@angular/router';
import { DashboardComponent } from './dashboard/';
import { settingsRoutes,settingsComponents } from './settings/';

const appRoutes: Routes = [
    { path: '',redirectTo: 'dashboard',pathMatch: 'full'},{ path: 'dashboard',component: DashboardComponent },...settingsRoutes
];

export const appRoutingProviders: any[] = [

];

export const routeComponents: any[] = [
    DashboardComponent,...settingsComponents
];

export const routing = RouterModule.forRoot(appRoutes,{useHash: true});

这是我的settings.routes.ts

import { Routes } from '@angular/router';
import { SettingsComponent } from "./settings.component";
import { DashboardSettingsComponent } from "./dashboard-settings/dashboard-settings.component";

export const settingsRoutes: Routes = [
    {
        path: 'settings',component: SettingsComponent,children: [
            { path: 'dashboard-settings',component: DashboardSettingsComponent }
        ]
    }
];

export const travelSettingsComponents = [
    SettingsComponent,DashboardSettingsComponent
];

**如果我从settings.routes.ts文件中删除此行,则没有错误,它允许我转到设置路径:

{ path: 'dashboard-settings',component: DashboardSettingsComponent }

解决方法

如果你有一个带孩子的路线,我相信你需要指定一个默认的子路径,如下所示:

children: [
    { path: '',component: SettingsComponent },{ path: 'dashboard-settings',component: DashboardSettingsComponent }
]

这将生成以下URL:/ settings和/ settings / dashboard-settings

Angular 2使用子路由进行身份验证

Angular 2使用子路由进行身份验证

我有一个角度2应用程序,我需要在每个页面上进行身份验证.所以我已经实现了一个自定义的RouterOutlet来确认我在每次更改页面时都已登录.
@Directive({
   selector: 'auth-outlet'
})
export class AuthOutlet extends RouterOutlet {
   publicRoutes: any;
   private parentRouter: Router;
   private authService: AuthService;
   constructor(_elementRef: ElementRef,_loader: DynamicComponentLoader,_parentRouter: Router,@Attribute('name') nameAttr: string,_authService: AuthService) {

      super(_elementRef,_loader,_parentRouter,nameAttr);
      this.parentRouter = _parentRouter;
      this.authService = _authService;
      this.publicRoutes = {
          'Login': true
      };
  }

  activate(oldInstruction: ComponentInstruction) {
      var url = this.parentRouter.lastNavigationAttempt;
      console.log('attemping to nav');
      if (!this.publicRoutes[url] && !this.authService.loggedIn){
          var newInstruction = new ComponentInstruction('Login',[],new RouteData(),Login,false,1);
          return super.activate(newInstruction);
      } else {
          return super.activate(oldInstruction);
      }
   }
}

这是一个有效的代码:
http://plnkr.co/edit/YnQv7Mh9Lxc0l0dgAo7B?p=preview

当用户未经过身份验证时,是否有更好的方法来拦截路由更改并重定向登录?

对于任何发现这一点的人来说,现在Angular 2中的答案是使用“Guards”作为新路由器的一部分.请参阅Angular 2文档:

https://angular.io/docs/ts/latest/guide/router.html#!#guards

一个基本的守卫只是实现“CanActivate”,并可以如下工作:

import {Injectable} from "@angular/core";
import {CanActivate,Router} from "@angular/router";
import {AuthService} from "../services/auth.service";

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private authService:AuthService,private router:Router){}

    canActivate(){
        if(this.authService.isAuthenticated())
            return true;

        this.router.navigate(["/login"]);
        return false;
    }
}

正如您在本示例中所看到的,我在其他地方运行了一个AuthService(实现并不重要),它可以告诉警卫用户是否已经过身份验证.如果有,则返回true,导航按常规进行.如果他们没有,我们返回false并将其重定向到登录屏幕.

Angular 2路由器在路由时刷新页面

Angular 2路由器在路由时刷新页面

我正在尝试在学习Angular 2的同时设置一条简单的路线,每当我点击一个链接时,浏览器就会被路由到新的路线,但浏览器会重新请求所有资源(不像单页应用程序那样).

我的索引文件,

<!--... . .  varIoUs scripts and styles . . . . . --->
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>

<script>
  System.config({
    packages: {        
      app: {
        format: 'register',defaultExtension: 'js'
      }
    }
  });
  System.import('app/main')
        .then(null,console.error.bind(console));
</script>
</head>
<body>
  <app></app>
</body>

应用来源,

main.ts

import {bootstrap}    from 'angular2/platform/browser';
import {RoutingApp} from './routing/routing.app'
import {ROUTER_PROVIDERS} from 'angular2/router'

bootstrap(RoutingApp,[ROUTER_PROVIDERS]);

RoutingApp

import {Component} from "angular2/core"
import {RouteComponent} from './route.component'
import { RouteConfig,ROUTER_DIRECTIVES,ROUTER_PROVIDERS } from 'angular2/router';


@Component({
    selector : 'app',template :  `
        go to this <a href="javascript:void()"data="/link">link</a>
        <br />
        <router-outlet></router-outlet>

    `,directives: [ROUTER_DIRECTIVES],providers: [ROUTER_PROVIDERS]
})
@RouteConfig([
    {path: '/link',name: 'Link',component: RouteComponent}
])
export class RoutingApp{

}

和RouteComponent

import {Component} from 'angular2/core'

@Component({
    template: `
        hello from RouteComponent
    `
})
export class RouteComponent{}

我做错了什么? Angular版本是2.0.0-beta.7.

谢谢您的任何见解.

解决方法

您应该使用routerLink指令导航到路由:

<a [routerLink]="['Link']">link</a>

由于您已将ROUTER_DIRECTIVES指定到组件的directives属性中,因此该指令可直接使用

Angular 2:共享相同解析器的兄弟姐妹子路由

Angular 2:共享相同解析器的兄弟姐妹子路由

我想弄清楚是否有一种更优化的方式在两个同级儿童路线之间共享相同的解析器.以下是路线与解析器相关的示例.

import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
export const routes = [{
        path: '',component: parentComponent,canActivate: [AuthGuard],resolve: {
            someData: someDataResolver
        },children: [
            { path: '',redirectTo: '0',pathMatch: 'full' },{ path: '0',component: someComponent1,resolve: {
                    someData1: someData1Resolver,someData2: someData2Resolver,}
            },{ path: '2',component: someComponent2,resolve: {
                    someData2: someData2Resolver
                }
            }
            ... a bunch more children routes/components with resolvers

        ]
    }]

现在,我正在重复每个儿童路线的解析器呼叫,我认为这不是最佳的.有谁知道是否有更好的方法来共享共享兄弟儿童解析器的数据?我考虑将数据从重复的解析器设置为共享服务,然后另一个子兄弟路由将从服务访问数据(而不是在解析器中进行另一个api调用).还有其他更优化的解决方案吗?

解决方法

您可以使用无组件父路线添加其他级别,并将解析器向上移动到此级别:

import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
export const routes = [{
        path: '',resolve: {
                    someData2: someData2Resolver
                },children: [
                { path: '',resolve: {
                        someData1: someData1Resolver,}
                },}
                ... a bunch more children routes/components with resolvers
            ]
        ]
    }]

今天关于Angular 2子路由是否会刷新父路由angular多级路由的讲解已经结束,谢谢您的阅读,如果想了解更多关于Angular 2 RC5子路由问题、Angular 2使用子路由进行身份验证、Angular 2路由器在路由时刷新页面、Angular 2:共享相同解析器的兄弟姐妹子路由的相关知识,请在本站搜索。

本文将分享angular – 页面上的多个路由器插座,用于相同的路由的详细内容,并且还将对angular配置路由进行详尽解释,此外,我们还将为大家带来关于Angular 2使用多个路由器插座向URL添加尾随斜杠、Angular 2在路由器插座中设置默认内容、Angular 2路由器不能处理传递的多个参数、Angular 2路由器在路由时刷新页面的相关知识,希望对你有所帮助。

本文目录一览:

angular – 页面上的多个路由器插座,用于相同的路由(angular配置路由)

angular – 页面上的多个路由器插座,用于相同的路由(angular配置路由)

在我的根组件中,我有以下模板:

<main>
  <div>
    <div>
      <router-outlet></router-outlet>
    </div>
    <div>
      <router-outlet name="aside"></router-outlet>
    </div>
  </div>
</main>

我想在主路由器插座中加载一些组件,在辅助路由器插座中加载一些其他组件用于相同的路由(当然,我有几条路由).因此,我定义了这样的路线:

export const AppRoutes: Routes = [
  {
    path: "",component: HomeSummaryComponent
  },{
    path: "",component: AskSummaryComponent,outlet: "aside"
  },{
    path: "payments",component: PaymentComponent
  },component: DataSummaryComponent,outlet: "aside"
  }
];

当页面加载时,它运行良好,我在主路由器插座中有HomeSummaryComponent,在旁边路由器插座中有AskSummaryComponent.但是,在导航中,我有这个:

<a routerLink="/payments">Payments</a></span>

当我点击此链接时,主路由器插座的内容将由PaymentComponent替换,但旁边的路由器插座仍会显示AskSummaryComponent.

我还试图通过“/ payements-aside”重命名第二个“付款”路线,并将链接替换为:

<a routerLink="/payments(aside:payments-aside)">Payments</a>

但它仍然无效.但是,当我直接访问http:// localhost:8083 / payments(除了:付款旁),它确实有效,但这个URL并不是真正干净…它不能用于面向公众的网站,因为.

有没有人知道如何实现这个简单的需求?

解决方法

以下对我有用

{
       path: 'customers',canActivate: [AuthGuard],children: [
       {
          path: '',component: CustomersComponent,outlet: 'main'
       },{
          path: '',component: SideBarComponent,outlet: 'sideBar'
       }
     ]
    }

Angular 2使用多个路由器插座向URL添加尾随斜杠

Angular 2使用多个路由器插座向URL添加尾随斜杠

我有一个应用程序组件,有两个出口:

模板:’< router-outlet>< / router-outlet>< router-outlet name =“popup”>< / router-outlet>‘

我按照this link中的示例创建路由和routerLinks,只要routerLinks在app组件内部,一切正常.但是,我创建了一个带有菜单的主要布局组件,以便我可以在所有页面上重复使用它,并使用loadChildren加载相应的模块和组件.

<app-main-menu></app-main-menu>
<h1>
  {{title}}
</h1>
<div>
  <router-outlet></router-outlet>
</div>

问题是当我将弹出插座的routerLinks移动到菜单中时,它包含主路径的尾部斜杠,结果url不起作用.所以例如这个routerLink:

<a [routerLink]="[{ outlets: { popup : ['login'] } }]">Login</a>

创建url’localhost / mainroute(popup:login)'(如果它放在app组件中)和’localhost / mainroute /(popup:login)'(如果它放在菜单组件中).

当第一个网址有效时,第二个网址会产生错误:
错误:无法匹配任何路线:’mainroute’

我不明白为什么它以不同的方式处理这两种情况.我也不明白,即使url’localhost / mainroute /’工作,第二个生成的url也不会因为斜杠.

有人能帮我吗?

解决方法

我找到了这个 issue,它描述了完全相同的行为.显然它已被提到开发人员的注意力,他们认为这是正确的行为.相同的路由器链接表达式可能会产生不同的结果,具体取决于它的使用位置.

建议的解决方案是使用这样的相对链接:

<a [routerLink]="['../',{ outlets: { popup: 'login' } }]">

或使用这样的绝对链接:

<a [routerLink]="['/',{ outlets: { popup: 'login' } }]">

在这里描述的情况下,绝对链接工作并给出了正确的链接.

我仍然不明白这种行为.所以,如果有人有一个很好的解释,请详细说明.

Angular 2在路由器插座中设置默认内容

Angular 2在路由器插座中设置默认内容

我想在路由器插座内设置一些默认文本,直到它被填充.

我有一个父组件,将在该页面上的路由器插座中显示子路由组件.

单击时,有2个按钮将使用子组件填充路由器插座.如何将内容放置在路由器插座内部,例如. “单击选项以显示数据”,然后单击该按钮后此消息将清除,子组件将显示在路由器插座中?

<div>
    <div>
        <divrouterLink="/unpaid/people">
            View People
        </div>
        <divrouterLink="/unpaid/bills">
            View Bills
        </div>
    </div>
</div>
<router-outlet>Click an options to display the data</router-outlet>

编辑
这是我的路线

path: 'unpaid',component: UnpaidBillsComponent,children: [
      {path: 'people',component: UnpaidPeopleComponent},{path: 'bills',component: UnpaidBillListComponent}
    ]

解决方法

default text inside the router-outlet until it is populated

首先,你的假设是错误的,内容不是插在插座内,而是插在插座下面.

您无法在模板中设置默认内容,但可以设置包含默认内容的默认路由.只需使用路径:”并使用带有“默认”模板的组件.

使用您需要的“默认”模板创建组件:

@Component({template: `Default template here`})
export class DefaultTemplateComponent {}

并将其添加到您的路线.

children: [
  {path: '',component: DefaultTemplateComponent},{path: 'people',component: UnpaidBillListComponent},]

Angular 2路由器不能处理传递的多个参数

Angular 2路由器不能处理传递的多个参数

我创建了一个示例plunker,将多个参数传递到下一页,但它不起作用.这是一个plunker演示,点击项目后危机中心路由不起作用.

http://plnkr.co/edit/ngNSsKBzAuhaP0EjKVJX?p=preview

onSelect(crisis: Crisis) {
    // Navigate with Absolute link
    //this.router.navigate(['/crisis-center',1]); //this is working.
     this.router.navigate(['/crisis-center',{ id: '1',id2:'2'}]); //this is not working
    }

//下面是路线:

//{ path: 'crisis-center/:id',component: CrisisDetailComponent } //-- this is working
  { path: 'crisis-center/:id /:id2',component: CrisisDetailComponent},// this is not working

ngOnInit() {
    this.sub = this.route
      .params
      .subscribe(params => {
        let id = +params['id'];
        let id2 = +params['id2']; //Unable to read id and id2 values
        this.service.getCrisis(id)
          .then(crisis => {
            if (crisis) {
              this.editName = crisis.name;
              this.crisis = crisis;
            } else { // id not found
              this.gotoCrises();
            }
          });
      });
  }

我有三个分层导航,它从危机中心转移到危机细节,然后从危机细节转移到> transactiondetail.因此,在我导航到危机细节之后,我想通过危机等待和危机等待,以便遍历细节,然后再回到危机清单.

我试图传递多个参数在这里有人有这个问题?

此外,我想隐藏浏览器URL中的URL参数并显示别名,以前用作“as”关键字现在它不起作用.

任何帮助赞赏

解决方法

使用路由器组件(来自’@ angular / router’,而不是’@ angular / router-deprecated’),您将传递多个参数,如下所示:

this.router.navigate(['/crisis-center',1,2]);

你试图这样做:

this.router.navigate(['/crisis-center',id2:'2'}]); //this is not working

因为您已将对象作为第二个参数传递,所以您传递的是查询参数而不是路由器参数.所以,它的URL是:

localhost:3000/crisis-center;id=1&id2=2

你可以在这里阅读更多相关信息:https://angular.io/docs/ts/latest/guide/router.html#!#query-parameters

Angular 2路由器在路由时刷新页面

Angular 2路由器在路由时刷新页面

我正在尝试在学习Angular 2的同时设置一条简单的路线,每当我点击一个链接时,浏览器就会被路由到新的路线,但浏览器会重新请求所有资源(不像单页应用程序那样).

我的索引文件,

<!--... . .  varIoUs scripts and styles . . . . . --->
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>

<script>
  System.config({
    packages: {        
      app: {
        format: 'register',defaultExtension: 'js'
      }
    }
  });
  System.import('app/main')
        .then(null,console.error.bind(console));
</script>
</head>
<body>
  <app></app>
</body>

应用来源,

main.ts

import {bootstrap}    from 'angular2/platform/browser';
import {RoutingApp} from './routing/routing.app'
import {ROUTER_PROVIDERS} from 'angular2/router'

bootstrap(RoutingApp,[ROUTER_PROVIDERS]);

RoutingApp

import {Component} from "angular2/core"
import {RouteComponent} from './route.component'
import { RouteConfig,ROUTER_DIRECTIVES,ROUTER_PROVIDERS } from 'angular2/router';


@Component({
    selector : 'app',template :  `
        go to this <a href="javascript:void()"data="/link">link</a>
        <br />
        <router-outlet></router-outlet>

    `,directives: [ROUTER_DIRECTIVES],providers: [ROUTER_PROVIDERS]
})
@RouteConfig([
    {path: '/link',name: 'Link',component: RouteComponent}
])
export class RoutingApp{

}

和RouteComponent

import {Component} from 'angular2/core'

@Component({
    template: `
        hello from RouteComponent
    `
})
export class RouteComponent{}

我做错了什么? Angular版本是2.0.0-beta.7.

谢谢您的任何见解.

解决方法

您应该使用routerLink指令导航到路由:

<a [routerLink]="['Link']">link</a>

由于您已将ROUTER_DIRECTIVES指定到组件的directives属性中,因此该指令可直接使用

关于angular – 页面上的多个路由器插座,用于相同的路由angular配置路由的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Angular 2使用多个路由器插座向URL添加尾随斜杠、Angular 2在路由器插座中设置默认内容、Angular 2路由器不能处理传递的多个参数、Angular 2路由器在路由时刷新页面的相关信息,请在本站寻找。

对于为Angular2添加到MdDialog的路由感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解angular配置路由,并且为您提供关于angular material dialog应用、Angular Material对话框Dialog、angular – [mat-dialog-close]的用法、Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)的宝贵知识。

本文目录一览:

为Angular2添加到MdDialog的路由(angular配置路由)

为Angular2添加到MdDialog的路由(angular配置路由)

我需要添加路由到mddialog组件,我不知道解决这个问题的最佳方法是什么.

目前,在foo页面(www.app.com/foo/1)上,用户可以单击一个按钮,它将打开一个mddialog组件,栏.

我想要做的是,在打开mddialog时,它会将/ bar /:id附加到组件.因此,例如它将类似于www.app.com/foo/1/bar/1.目标是让用户拥有可以导致foo的可共享链接,然后打开mddialog.

到目前为止,这就是我的应用程序的结构.

app/
  app.component.html <- <router-outlet> is found here
  app.component.ts
  app.module.ts

  foo/
    foo-routing.module.ts
    foo.component.html
    foo.component.ts
    foo.module.ts

    bar/
      bar.component.html <- This bar component file for the mddialog
      bar.component.ts

  baz/ <- Another section of the website with it's own routing
    baz-routing.module.ts
    baz.component.html
    baz.component.ts
    baz.module.ts
    ...

目前在我的foo-routing.module.ts中,我有这个:

const routes: Routes = [
  {
    path: 'foo/:fooId',component: FooComponent,children: [
      {
        path: 'bar/:barId',component: BarDialogComponent
      }
    ]
  }
];

但是,这不起作用.所有这一切都是打开模块,重新路由到/,并且不允许我点击其他链接.

有人有什么建议或想法吗?谢谢!

解决方法

实现这一目标的简单方法如下

bar.component.ts

constructor(
  public dialog: MatDialog,@Inject(DOCUMENT) private doc: any,private router: Router) {
  dialog.afterOpen.subscribe(() => {
    if (!doc.body.classList.contains('no-scroll')) {
      doc.body.classList.add('no-scroll');
    }
  });

  this.openModal();
}

openModal() {
  this.dialogRef = this.dialog.open(JazzDialog,this.config);

    this.dialogRef.afterClosed().subscribe((result: string) => {
    this.dialogRef = null;
    this.router.navigate(['../']);
    this.doc.body.classList.remove('no-scroll');
  });
}

Plunker Example

angular material dialog应用

angular material dialog应用

1. 打开弹窗的点击事件

project.component.html

<button mat-icon-button(click)="editDialog(project)">
          <mat-icon>create</mat-icon>编辑
      </button>
<button mat-mini-fab color="warn"(click)="openDialog()">
  <mat-icon>add</mat-icon>
</button>

project.component.ts

import { Component, OnInit } from ''@angular/core'';
import { MatDialog } from ''@angular/material'';
import { NewProjectComponent } from ''../new-project/new-project.component'';

@Component({
  selector: ''app-project'',
  templateUrl: ''./project.component.html'',
  styleUrls: [''./project.component.scss'']
})
export class ProjectComponent implements OnInit {

  projects=[
    {
      "name":''企业协作平台'',
      "desc":''这是一个企业内部项目'',
      "coverImg":''assets/img/covers/0.jpg''
    },
    {
      "name":''员工管理平台'',
      "desc":''这是一个企业内部项目'',
      "coverImg":''assets/img/covers/1.jpg''
    }
  ];
  constructor(public dialog:MatDialog) { }

  ngOnInit() {
  }

  // 新建项目
  openDialog(){
    const dialogRef = this.dialog.open(NewProjectComponent, {
      width: ''250px''
    });

    dialogRef.afterClosed().subscribe(result => {
      console.log(''The dialog was closed'',result);
    });
  }

  // 编辑项目
  editDialog(data){
    const dialogRef = this.dialog.open(NewProjectComponent,{
      width:''250px'',
      data:data
    });
    dialogRef.afterClosed().subscribe(result=>{
      console.log(''The dialog was closed'',result);
    })
  }

}

2. 弹窗

new-project.component.html

<h1 mat-dialog-title>新建项目</h1>
<div mat-dialog-content>
  <mat-form-field>
    <input matInput [(ngModel)]="project.name" placeholder="项目名称">
  </mat-form-field>
  <mat-form-field>
      <input matInput [(ngModel)]="project.desc" placeholder="项目描述">
    </mat-form-field>
</div>
<div mat-dialog-actions>
  <button mat-raised-button (click)="onNoClick()">关闭</button>
  <button mat-raised-button  [mat-dialog-close]="project"  cdkFocusInitial  color="primary">保存</button>
</div>

new-project.component.ts

import { Component, OnInit, Inject } from ''@angular/core'';
import { MatDialogRef, MAT_DIALOG_DATA } from ''@angular/material'';

@Component({
  selector: ''app-new-project'',
  templateUrl: ''./new-project.component.html'',
  styles: []
})
export class NewProjectComponent implements OnInit {

  project:Object;
  constructor(
    public dialogRef:MatDialogRef<NewProjectComponent>,
    @Inject(MAT_DIALOG_DATA) public data
  ) { }

  ngOnInit() {
    this.project = this.data||{};
  }

  onNoClick(){
    this.dialogRef.close();
  }

}

3. 特别注意:new-project组件是一个服务。在project.module.ts中必须写入entryComponent中,否则会报错

import { NgModule } from ''@angular/core'';
import { ProjectComponent } from ''./project/project.component'';
import { SharedModule } from ''../shared/shared.module'';
import { NewProjectComponent } from ''./new-project/new-project.component'';

@NgModule({
  imports: [
    SharedModule
  ],
  declarations: [ProjectComponent, NewProjectComponent],
  entryComponents:[
    NewProjectComponent
  ]
})
export class ProjectModule { }

 

Angular Material对话框Dialog

Angular Material对话框Dialog

一、引入对话框模块

  import {MatDialogModule} from ''@angular/material''; 并在import中声明。

二、使用

1.对话框组件

   mat-dialog-title:对话框元素的标题。 滚动时保持固定在对话框顶部。

   mat-dialog-content:对话框的可滚动内容容器。

   mat-dialog-actions:对话框中底部操作按钮的容器。 滚动时固定在底部。

2.需要打开对话框的组件

import {MatDialog} from ''@angular/material/dialog'';

 3.对话框组件接收数据、回传数据

import {MatDialogRef, MAT_DIALOG_DATA} from ''@angular/material/dialog'';

效果:

 

 

angular – [mat-dialog-close]的用法

angular – [mat-dialog-close]的用法

我对[mat-dialog-close]的用法有点困惑.

所以,我有一个表格对话框.如果用户单击提交按钮,则验证表单.如果输入有效,则关闭对话框并提交表单.但是,如果输入无效,则对话框将保持打开状态并显示错误消息.为此,我想使用[mat-dialog-close],因为它在official documentation中描述,其使用如下:

<button mat-button [mat-dialog-close]="true">Yes</button>

我以为我可以传递一个布尔值,标签是否有效取决于变量的布尔值.但是,这不起作用.我试过这样的:

<button type="submit" (click)="addUser()" [mat-dialog-close]="formisvalid" mat-button>Submit</button>

我传递了变量formisvalid.除非输入无效,否则它的值为true.但是现在对话框始终关闭,无论formisvalid的值如何.
我也尝试用假替换它.我认为无论发生什么事情,对话框都会保持打开状态,但它也会一直关闭.

所以,我的问题是:我是否错误地使用了[mat-dialog-close],或者我只是做错了什么?如果使用[mat-dialog-close]指令无法实现这一点,那么实现我想要做的事情的另一种方法是什么?

解决方法

如果表单无效,请将按钮设置为禁用.这样,除非表单有效,否则无法单击该按钮,这意味着除非表单有效,否则不会关闭该按钮

<button type="submit" (click)="addUser()" mat-dialog-close [disabled]="formisvalid" mat-button>Submit</button>

Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)

Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)

更新 :  2020-02-13

关于 position 的细节

1. withFlexibleDimensions(true) 

默认是 true 

overlay 在决定 position 时, 它会依据我们给的先后 position 

顺序去看,如果其中一个可以完全显示就马上用那个。

 

如果全部都不能完整显示,那么就要试试看调位置, 然后比分数

 

 然后是这样

 

 最后比分数

 

 所以这个是配合 minHeight, minWidth 来使用的. 

 

还有一个设置也要留意

withLockedPosition(true)
overlay 在 2 种情况下会 reposition
一个是 on scroll 一个是 window resize
window resize 的情况下, position 100% 会重新计算, 不管有没有 lock 
而 scroll 则是可以被 lock 的. 

window resize 之所以可以绕过 lock 是通过 _isInitialRender 实现的

另外还有一种就是我们手动调用 updatePosition. 

如果我们的内容是动态的,或者是 ajax 比较慢加载回来的话, 那么一般上我们都需要使用这个 reposition 来 update 一下. 

总结 : 

3 种情况下我们会需要 update position 

1. onscroll, (lock/nolock)

2. on resize, (no lock)

3. on content change (lock/nolock)

遇到的问题是 1,3 只可以用同一个config, 比如你 lock 那么 2 个都得 lock, 如果 nolock 2个都得 nolock

因为目前 material 并没有给多得接口用, 除非我们调用 private 的 _isInitialRender

 

 

 

更新: 2019-11-24 

dialog vs router link 

refer : https://stackoverflow.com/questions/51821766/angular-material-dialog-not-closing-after-navigation

今天发现一些场景可能导致 dialog 不会关闭. 比如当子组件打开一个 dialog 后

某一个操作把父组件给销毁了.这个时候 dialog content 会一起销毁掉, 

因为 content 是 under 这个逻辑树中 (当然如果你是放到 appRef 里头就另外说)

content 销毁了,但是 overlay 留在 body 丫. 

 

material team 有考虑到这种情况所以做了一个 fallback 机制, 但是这个并不能解决上面的问题,因为无论如何 dialog 要求至少要启动 animation start 

如果是 router link 切换的话,渲染会在同一个 detech change 下完成,所以 animation start 是不会被触发的。

目前 dialog 没有提供 displose 的方法,所以基本上不无法做到的,除非你去监听 router event 之类的。

那我觉得比较合理的处理方式是。如果组件负责打开 dialog or overlay 

那么当这个组件 onDestroy 的时候,必须要确保它负责的 overlay 一定要 displose. 为此 dialog 应该要公开这个接口让我们使用的. 

 

 

 

更新 : 2019-11-14 

小总结一下 angular 动态组件 -> portal -> overlay -> dialog 

ComponentFactoryResolver 是我们用 angular 做动态组件的基础. cdk, material 都是基于它的。
在 ng 要做一个动态组件是这样的
 
注入 factory resolver 服务
constructor(
  private componentFactoryResolver: ComponentFactoryResolver,
) { }

 

制作出组件工厂, 把动态组件丢进去就可以了

const componentFactory = this.componentFactoryResolver.resolveComponentFactory(DynamicComponent);

 

然后就可以创建组件实例了,这个时候需要基于一个注入器

通过 Injector.create 创建出一个新的 injector 并且继承 parent injector, ng 的 injector 有分层的概念 ngModule 的 provider 通常会放到 root injector 里头, lazy load module 则像下面那样创建出第 2 层级的 injector 

const componentFactory = this.componentFactoryResolver.resolveComponentFactory(DynamicComponent);
const injector = Injector.create({
  providers: [{ provide: ''extraProvider'', useValue: ''dada'' }],
  parent: this.injector
});
const componentRef = componentFactory.create(this.injector);

这个时候组件就已经被实例化了,但是还没有发生 detech change, OnInit 也还没跑.

这个时候组件是独立的,我们知道 angular 把所有东西看成 VIew 

组件就是组件 view, 模板就是 embedded view

然后所有 view 都必须放到 logical view tree 里头. 这样 change detech 才能遍历执行

所以现在组件创建好以后,我们需要给它一个家. 

可以是 ViewContainerRef 或 ApplicationRef

像这样

this.applicationRef.attachView(componentRef.hostView);
this.container.insert(componentRef.hostView, 0);

2 者最大的区别是在 detech change 上, 如果你放到 app 里头, 那么组件是在最上层, 一旦 app.tick 触发. 此组件就会触发 doCheck 

如果你是放到 container 里头,那么要看这个 container 在 logical tree 里面的第几层. app.tick 时就不一定触发 doCheck 了,要看 detech change 有没有流到这一层里头 (OnPush 的情况下)

此外, applicationRef.attachVIew 和 container 还有一个不同是, appRef attach 并不会把 dom append 出去

它只是把组件放进去 logical view tree 而且,并没有 append to dom. 

view container 则会做这个事情. 

那我们得自己搞, 比如... 

document.body.appendChild((componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement);

当然绝大部分情况下,我们应该使用 view container 因为这个是官方教我们正确插入 dom 的方式.

上面这个通常是用在 dialog 那种要 append to body 最外层的情况. 由于那里已经脱离的 angular 的 scope 所以我们得自己弄. 

不管是 container.insert 还是 appRef.attachView 调用后,组件就会被 detech change OnInit 了

组件 append 出去或需要一个 detech change 的 cycle 才会渲染哦. viewContainer 并不会替我们渲染组件. 它只是单纯的 append 而已.

 

注意 : 

动态组件的 detech change 是比较难懂的. 我是在发现问题,看了源码之后,找特定关键字才找到了相关的文章

https://netbasal.com/things-worth-knowing-about-dynamic-components-in-angular-166ce136b3eb

意思是 componentRef.hostview.detechChange 只会让 component DoCheck 而已. 

因为 componentRef.hostView 并不是 componentRef.instance.changeDetectorRef 

componentRef.hostView 是一个 RootView 而不是 LView

RootView 重写了 detech change

LView 的 detechChanges 是这样的

 所以你会发现 hostView[''_lView''] === instance.changeDetectorRef[''_IView''] 

但是 detechChange 却不一样. 至于为什么这样设计我也不清楚. 总之只有动态 create 出来的 component 才会有这个 RootViewRef 

那么问题来了, 外部如何让内部 detech change 呢 ? 

第一种方法就是传 rxjs 流进去咯. 里面监听然后 mark for check.

第二种是通过 componentRef.injector 获取到内部的 changeDetectorRef, 然后调用 markForCheck

此外别无它法, componentRef.detechChange 由于是上层,它只能让 component DoCheck 而已. 记住了。

所以,记住这几个点.

1. componentFactory.create 

这个时候组件只是被实例化, 没有 detech change, 没有 OnInit 没有 DoCheck.此时它也没有在 logical tree 里头

2. ComponentRef.hostView 是 RootViewRef 而不是平常我们看到的 LView 

RootViewRef 重写了 changesDetech 方法,所以当我们调用 hostView.changesDetech 的时候,我们的组件并没有渲染, 因为它执行的是 component 的上一层, 这只会让 component 执行 DoCheck 而已. 

3. appRef.attachView(componentRef.hostView) 

插入到 logical tree 顶端. 每一次 app.tick 就会被执行 hostView.detechChange. <-- 记住它只是让 component DoCheck 而不是 render. 

appRef.attach 不会 append dom, 我们需要自己写代码去 append dom.

4.container.insert 

插入到 container 这一层级的 logical tree, app.tick 如果有流到这一次就会被 detech change. <-- 还是一样它只能让 component DoCheck 而不是 render. 

会 append dom 到 container 的位置.

5. 唯一能让 component detech change render 的方式是传一个 rxjs 流进去, 或者通过 componentRef.injector 获取到内部的 ViewRef (也就是 ChangeDetectorRef)

 

好说完 component,现在说说 template 

template 是通过 <ng-template> 制作出来的。

const context = {};
const viewRef = this.templateRef.createEmbeddedView(context);

和 component 相同的,这个时候 viewRef 还没有被 detech change. 也没有在 logical tree 里头.

我们可以通过 appRef.attachView 或者 container.insert 让它插入到 logical tree 里头.

这里主要说说它和 component 不同的地方.

首先它没有 RootView 这个概念, 我们获取到的就是 ViewRef. 

另外 template 和 component 一个很大的区别在于它的通讯值. 

template 本身就被定义在某个 component 当中, 然后又被丢到另一个可能千里之外的 component.container 里头.

<ng-template #template let-age="age" >
  {{ value }} and {{ age }}
</ng-template>

value 来自定义 template 的 component, age 来自使用 template 的 component. 

那它的 detech change 是这样工作的。

当定义它的 component 发生 detech change 时, value 就被更新了, 使用它的组件并不会因此触发 detech change 之类的, age 也不会从新去拿. 

就只是更新了 value 然后渲染出效果而已. 如果你在期中偷偷的修改了 age,ng 是不会发现的, 因为它不会去 get age. 

反过来如果是使用 template 的组件做了 detech change, 定义它的组件也不会发生 detech change, 但是呢 value 却会去 getter 一下 (这里和 age 的表现不相同).

 

上面说了 component 和 template 的基本用法和 detech change 的更新机制.

现在说说 cdk 的 portal 

cdk 提我们封装了上面这些动态创建 component 和 template 的方法. 其实也没有什么好封装的啦,不就那几行...

但是还是得要搞清楚它是怎样用起来的。

我们通常会用到是

ComponentPortal 

 

4个都很合理,我们上一段都有用到这些. 至于为什么可以替换 componentFactory 呢, 这个不是很清楚,不是都一样的吗.. ? 

另一个可能会用到得是 

PortalInjector

mat dialog 传递 data 和 dialogRef 就是用这种简单方式做的. 它不像上一段使用 Injector.create 然后提供 provider

它只是用一个 weakmap 来实现而已. 

然后是 TemplatePortal 

 

 都是动态创建需要的东西. 

TemplatePortal 和 ComponentPortal 都继承了 Portal 类

 

 没什么特别的,只是有 attach 和 detech 的方法而已。然后主要, 这 2 个方法其实内部是调用了 outlet.attach 和 detech 

也就是说逻辑根本没有写在这里,这 2 个方法只是一个委托方法而已,除了让初学者乱没有看出其它意义.

再来一个 DomPortal

 很简单,就是放了一个 dom 在里面...

最后是 PortalOutlet, outlet 的职责是 container 用来 append dom 的,

这个是最常用到的,可以简单理解它就是 container 

 另一个是专门给 append body 用的,类似上段我们说的 appRef 然后自己 append body 

 整个 portal 看下来没有什么奇特的地方,就真的只是封装而已. 

我觉得最需要懂得逻辑在这里, portal.attach 

cdk outlet 和 dom outlet 区别就在于此

先看看 ckd outlet attach template 

关键在 viewContainerRef, 这个 container 说的是 outlet 这个指令依赖注入得 container (outlet 这个位置)

再看看 ckd outlet attach component 

关键也在 container, 如果 portal 本身有 container, 就用,不然就用 outlet 的. 

这里和刚才 template 不同,template 没有判断 portal 是否有 container 

这样的设计我是觉得挺奇怪的,我把 portal 交给了 outlet 结果, portal 被 attach 在原本的 container 里, 这里关 outlet 什么是呢 ? 

然后 outlet 被 destroy 时也 destroy 掉 portal ? 

我们把疑点留着,等下一起讨论. 继续往下走.

这是 dom outlet 的 attach template 

 dom outlet 不是指令,它是 new 出来的,所以它本身不会有 view container ref, 所以 portal 理应要有 view container ref 

这里没有任何判断就直接使用了 portal.viewContainerRef ... 挺勇敢的嘛...

此外这里还有一个 cut and paste 的动作. 当 portal 内容 attach 到 container 后, 这里做了一个 dom 操作就是把内容 cut and paste 到 outlet element 里头.

这应该是和 cdk outlet 最大的不同点. 

最后是 dom outlet 的 attach component 

 

 这里有做 viewcontainer 判断, 和 template 的处理手法不同. 

如果 portal 没有 viewcontainer 那么就放到 appRef 里头. 最后依然会 cut and paste. 

解析完了。总结一下我觉得不太容易理解的几个点.

1. outlet 决定位置

cdk outlet attach template, dom outlet attach component/template 都可以确保最终的内容渲染在 outlet 位置上. 

但是 cdk outlet attach component 却不是这样..

这个确定是一个 bug, https://github.com/angular/components/issues/17650 -> https://github.com/angular/components/pull/17731

所以 cdk outlet 的会确保最终内容出现在 outlet 里

2. cdk outlet append component 时,有可能把 component 系在 appRef 上, 但是 append template 时却不会这样. 

反而强制要求 portal 一定要有 container (我的想到的一个解是, template 定义在 component 里,所以它肯定是有 container 的)

在我的理解中. template 和 component 应该保持行为一致. 让使用者决定要用哪一种. 可以简单的替换. 

可能 cdk 很灵活时因为 mat 需要这么灵活. 但对我来说这些不一致会导致维护起来比较麻烦. 

所以我的做法通常是 portal 不需要带 container 逻辑. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

更新: 2019-11-08 

记入一下 overlay 的使用

material 有 8 个组件用到了 overlay 

autocomplete
datepicker
select
menu
bottom sheet
dialog
snackbar
tooltip

在真实项目中,还有很多组件是没有的. 比如 

小 form 

 

 

 比如大 message tip

 

这些都得我们自己去实现. 所以就需要用到 overlay 了.

先说说它的过程

当我们调用 overlay.create 的时候, overlay 会在 body 层创建一个 div 

然后依据我们的 width height 在放一个 div 在里面 (其实好像有 3 - 4 层 div)

如果我们要 backdrop 也可以通过 overlay 设置. 

有了 backdrop 我们就可以监听点击事件然后关掉 overlay 了. 

这里有一个小体验. 很久以前,我是用 body click + stop bubble 来实现这种 modal close 的. 后来发现大家都用 overlay + 透明 backdrop 来做

省去了不少麻烦. stop bubble 在多层次的情况下不太好处理, 但是这个做法也有它的局限. 比如只能 body scroll 因为 backdrop 在最上层, 会把其它 div 挡住, 如果我们依赖其它 div 来做 scroll 

那么就 scroll 不了的. 所以多用 body scroll 还是比较正确的姿势. 

我还发现一个小秘密,就是 material tooltip 没有使用 backdrop 但是缺可以点击 body 关闭. 它也是通过监听 body click 实现的,因为 tooltip 内只可以是字, 所以不会有点击事件也就不需要顾虑 bubble 的问题. 很巧妙的在设计上躲过了实现的难题. 

做小 modal 要搞懂 position strategy

const positionStrategy = this.overlay.position()
  .flexibleConnectedTo(origin)
  .withTransformOriginOn(''.transformOrigin'')
  .withFlexibleDimensions(false)
  .withViewportMargin(8)
  .withPush(false)
  .withLockedPosition(true)
  .withPositions([
    { originX: ''start'', originY: ''top'', overlayX: ''start'', overlayY: ''top'' },
    { originX: ''start'', originY: ''top'', overlayX: ''start'', overlayY: ''bottom'' },
    { originX: ''end'', originY: ''top'', overlayX: ''end'', overlayY: ''top'' },
    { originX: ''end'', originY: ''top'', overlayX: ''end'', overlayY: ''bottom'' }
  ]);

const overlayRef = this.overlay.create({
    positionStrategy,
    scrollStrategy: this.overlay.scrollStrategies.reposition(),
    hasBackdrop: true,
});

scroll strategy 用的是 reposition, 这个很好里理解, 就是当 scroll 的时候我们的 modal 需要始终维持对的位置.

来说说 position strategy, 和 big modal 不同, small modal 需要一个位置, 通常是在我们点击按钮的附近. 

可以叫它 origin element, 我们要呈现的内容 (content) 必须和 origin element 做一个定位.

flexibleConnectedTo(origin element) 就 content connect to origin 的意思

withPositions 提供一个位置匹配, origin 9 个点, content 9 个点, 所以总共可以摆出 81 一个位置. 

 

 

我们提供一个 array 写上各种匹配方式, 要有顺序之分哦,overlay 会先后判断可见范围,找出一个可见度最高的作为展现, 比如 drop down 在屏幕上方,显示位置是下,在屏幕下方显示位置是上,这种体验.

withTransformOriginOn(content element selector string) 主要是给我们做 animation scale 用的,由于 content 出现的位置是不固定的

所以 animation 展示的位置也是不固定的,overlay 会通过我们传入的 selector 找到 element 然后把 transform origin 设置进去. 

withFlexibleDimensions 这个我到现在都没有搞懂是啥, default 是 true, 但是我发现它的效果怪怪的,所以就不用了. 跳

withViewportMargin 我们不希望我们的 content 和 viewport 黏在一起, 就可以放这个 margin 给它. 

红色区域就是那个 margin 

withPush 默认是 true, 有了这个, 用户不管 scroll 上下左右, 我们的 content 就会一直保持在可见区, 会跟着 scroll 走. 

withScrollableContainers(element) 这个是用于当我们有多层 scroll bar 时用到的,默认情况下, overlay 是通过 scrollDispatcher 去监听 body scroll 的. 

但是如果我们的 origin 在一个 div scroll 里, 只监听 body scroll 是无法做出正确体验的,所以我们要让 overlay 知道这个事情. 

做法是这样的, 我们得把我们能 scroll 的 element 都注册进去 scrollDispatcher (可以自己调用 register 或者用 cdkScrollable 指令)

当 scrollDispatcher 有了所有的 scrollable div, 当我们调用 withScrollableContainers,它会拿我们传入的 element 去 match (element 的 parent 如果有在 scrollable list 中就去监听这个 scrollable 的滚动事件) 

这样当 scroll 的时候, 我们的 content 就会正确的被 reposition 了.

withLockedPosition 当我们 scroll 的时候, overlay 会替我们 reposition 但是有时候这种跳来跳去不一定是好的体验,这个时候我们可以使用 lock, content 显示时会用最佳位置,然后就一直保持这个位置,不管用户 resize or scroll.

到这个环境, overlay 算是做出来了. 下一个是做 content 的 animation

通常 overlay append content 我们都希望有同一种 animation 体验,所以一般上会封装 animation 

它的具体做法是做一个 container 组件, overlay 每次 append 都是这个 container 组件,然后这个组件在 append 我们的动态组件.

const containerInjector = new PortalInjector(this.vcr.injector, new WeakMap());
const containerPortal = new ComponentPortal(ContainerComponent, this.vcr, containerInjector);
const container = overlayRef.attach(containerPortal).instance;

overlay 内部有一个 dom portal outlet (这个和我们经常用的 cdk portal outlet 指令不是同一个哦),我们调用 overlay.attach(我们的 portal)

overlay 会调用 DomPortalOutlet.attachComponent.

这里的关键是我们传入的 portal 是否有 viewContainerRef  它会决定之后的 detech change 时机和 injection.

如果有 viewcontainer 那么会把 portal  先创建到 view container 然后通过 outletElement (body 的 div) appendchild (cut and paste) 出去.

如果没有会直接创建 component 然后放入 appRef.views 里面. 然后依然 append to body 

大部分情况下我们 portal 应该要有 view container ref.

下一个动作就是 container append 动态组件了. 

<ng-template cdkPortalOutlet></ng-template>

我们可以在 container.html 使用 cdkPortalOutlet 

@ViewChild(CdkPortalOutlet, { static: true }) portalOutlet: CdkPortalOutlet;

通过 viewchild + static 获取到这个指令. (看到 static true 的用途了吧...嘻嘻)

static 的特色是,在 component construtor 运行完后就可以获取到这个属性值了, 不需要等到 after view init.

container.animationStateChanged.pipe(filter(e => e.toState === ''enter'' && e.phaseName === ''done''), take(1)).subscribe(e => {
  container.autoFocus();
});
const contentInjector = new PortalInjector(this.vcr.injector, new WeakMap([[MODAL_DATA, ''data'']]));
const contentPortal = new ComponentPortal(AbcComponent, null, contentInjector); // 这里 view container ref 是 null
container.attachComponentPortal(contentPortal);

注意那个 animationStateChanged. overlay dispose 是很突兀的,所以我们几乎不可能直接调用。

正确的做法是通过控制我们 container 的 animation 来完成关闭, 比如先 fade out container,然后监听 container fade out done 才调用 overlay dispose.

上面这个例子是做了一个 autofocus, 看的出来 container 内部封装了 cdk focus trap 功能.

另一个要留意的是, container.attachComponent 

刚才我们说 container 内有一个 cdk portal outlet, 拿我们只需要开一个接口接受动态组件,然后就可以 attach 出去了。

cdk portal outlet vs dom portal outlet 

 cdk portal outlet 处理 view container ref 的方式有点不同, cdk poral outlet 本身有自己的 view container ref (刚才 dom outlet 是用 appRef)

如果 portal 自带 view container ref, 那么会直接把 portal 插入到其中, 所以内容不会被 append 到 cdk portal outlet 的位置哦. (这有点怪,注释说了只是逻辑树会插入到 portal 的 view container, 但是渲染应该是在 portal outlet 的位置才对呀. 但是没有..)

提了一个 issue 希望能问个明白

https://github.com/angular/components/issues/17650

如果没有, 就会使用 cdk portal outlet 的 viewcontainer 了. 这通常会是我们想要的结果.

 

 

 

 

 

 

在学习 overlay 和 portal 的时候,一直没有弄明白 viewContainerRef 在其中扮演的角色

这里说一下来龙去脉

当我们创建一个 overlay 时,同时创建了一个 portal outlet

 

 当我们要 append 内容时,内部其实时调用了 DomPortalOutlet 的 attachComponentPortal 方法

 

这时候会依据 portal <-- 传入的component portal,不是 portal outlet 哦,不要搞混了.

时候有 viewContainerRef 决定如何创建 component.

如果有就调用 viewContainerRef create component 方法, 这时会 insert component to container 渲染. 然后再通过 dom 操作 cut and paste 去 portal outlet (body)。

如果没有的话就直接通过 component factory create component 然后把 view 放入到全局 appRef 里面. 这时候组件并没有 append to dom 任何地方. 

然后 cut and paste to portal outlet.

当 app.tick 时,所有的 appRef.views 就会 detech change. 

 

2 者有什么区别呢 ? 

 

在 portal 的文档里并没有解释太多... 只是说什么逻辑树和 view 树的不同而已. 

反而是 dialog 的文档里解释了

 

从源码上看确实如此.

在使用了 viewContainerRef 之后, detech change 的时机是依据 viewContainerRef 的

而放入 appRef 的情况, detech change 的时机是 app.tick 每一次都触发.

 

 appRef.attachView 将 view 放入了一个 array 中.

 

 在 tick 的时候调用 detech change.

 

至于 injector 其实蛮困惑的,因为 attachComponentPortal injector 是基于 component portal 的 injector,跟 viewContainerRef 没有啥关系丫. 那为什么 dialog 文档说有关系呢

 

看了源码就会发现了,dialog 创建 portal 使用的 injector 是 userInjector || rootInjector, 而所谓的 userInjector 就是 viewContainerRef.injector.

这样就真相大白了咯。

 

今天的关于为Angular2添加到MdDialog的路由angular配置路由的分享已经结束,谢谢您的关注,如果想了解更多关于angular material dialog应用、Angular Material对话框Dialog、angular – [mat-dialog-close]的用法、Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)的相关知识,请在本站进行查询。

如果您对Azure上的Angular2应用程序“您无权在子路由上查看此目录或页面”azure application insight感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解Azure上的Angular2应用程序“您无权在子路由上查看此目录或页面”的各种细节,并对azure application insight进行深入的分析,此外还有关于Angular2 SEO-如何使Angle 2应用程序可抓取、Angular2 – 在Azure中托管时页面刷新404、angular2 – 如何部署Angular 2应用程序开发的Typescript到生产?、angular2应用程序中的Karma测试异常的实用技巧。

本文目录一览:

Azure上的Angular2应用程序“您无权在子路由上查看此目录或页面”(azure application insight)

Azure上的Angular2应用程序“您无权在子路由上查看此目录或页面”(azure application insight)

我发布了一个Angular2应用程序并将其部署在Azure Web Apps上.如果我通过浏览到它的根目录启动它,应用程序工作正常:
http://cafeserver.azurewebsites.net/Web/

但是,如果我直接浏览到应用程序中的子路径,例如:
http://cafeserver.azurewebsites.net/Web/customers

它将抛出一个错误,指出“您没有权限查看此目录或页面.”

我该如何解决这个问题?

解决方法

您需要更新web.config以将所有路由重定向到索引页面,以便Angular路由可以启动.我使用以下配置将SPA部署到Azure:

<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="SPA">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

请注意,我的设置免除了对包含/ api的文件,目录和请求URI的请求,因为我为后端HTTP路由保留了这个.您可以根据您的豁免需求更新您的.

Angular2 SEO-如何使Angle 2应用程序可抓取

Angular2 SEO-如何使Angle 2应用程序可抓取

我正在使用Angular-Meteor框架构建Angular 2应用程序。

我想实现快速和一致 的索引 谷歌和其他搜索引擎,让Facebook的分享者和其他 刮削器 生成我的JS生成内容的预览。

通常,SPA使用PhantomJS在服务器端呈现页面并将静态HTML发送给客户端。

当然,当我拦截_escaped_fragment_或看到google或scraper用户代理时,我可以自己生成PhantomJS,但是当我直接在流量较大的网站上生成PhantomJS时,我总是遇到内存泄漏和孤立的Phantom实例的情况(我使用NodeJS和此模块)。

对于Angular 1应用程序,我曾经使用Angular-SEO之类的角度模块来解决此问题,但似乎很难将此类模块转换为angular 2。

我还没有找到合适的 Angular 2 模块。我应该自己构建它,还是有其他好的方法可以实现这一目标?

Angular2 – 在Azure中托管时页面刷新404

Angular2 – 在Azure中托管时页面刷新404

我正在开发一个Angular2应用程序.它使用“@ angular / common”:“2.0.0-rc.4”和“@ angular / router”:“3.0.0-beta.2”.

我的问题是,当我在某些页面上使用浏览器刷新时,我看到一个错误说…

“您要查找的资源已被删除,名称已更改,或暂时无法使用.”

如果我直接点击网址也会发生这种情况.

一个示例网址是……
https://tilecasev2.azurewebsites.net/profile/therichmond

但是,如果您通过主页查看页面,它们可以正常工作,但只能刷新(https://tilecasev2.azurewebsites.net).

我的index.html头文中有以下内容…

<base href="/">

为什么会发生这种情况,我该如何解决?

HashLocationStrategy通过在所有角度路由中包含#但不能真正修复它来避免此问题.

要使没有哈希的角度路由在本地开发环境中以与在本地开发环境中相同的方式工作,您只需将IIS配置为以root身份重写所有请求.这使角度处理路由.

为此,请使用以下内容将Web.config文件添加到站点的根文件夹:

<configuration>
<system.webServer>
    <rewrite>
      <rules>
        <rule name="Main Rule" stopProcessing="true">
                <match url=".*" />
                <conditions logicalGrouping="MatchAll">
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                </conditions>
                <action type="Rewrite" url="/" />
            </rule>
        </rules>
    </rewrite>
</system.webServer>
</configuration>

angular2 – 如何部署Angular 2应用程序开发的Typescript到生产?

angular2 – 如何部署Angular 2应用程序开发的Typescript到生产?

我是Angular 2的新手。我困惑于Angular 2如何在生产环境中工作。

>在生产服务器中运行Angular 2应用程序的先决条件是什么?
>是否可能在IIS服务器中部署应用程序或需要节点服务器?
>在开发机器中使用节点编译文件后,我们需要将.js和.ts部署到生产环境吗?

我使用JSPM使我的angular2项目生产准备。其他流行的工具,如JSPM包括webpack和browserfy。 JSPM将完成的重要任务之一是捆绑构成您的angular2项目的各个模块。我还将“selfExecutingBundle”标志设置为true,并让JSPM制作一个捆绑的js文件(例如myApp.bundled.js),并从那里我minify它(myApp.bundled.min.js)和这一个脚本引用用于index.html文件。
<html>

<head>
    <title>Hello Angular World</title>
</head>
<body>
<div>
    <my-app>Loading...</my-app>
</div>
    <script src="/js/myApp.bundle.min.js"></script>
</body>

</html>

这就是你需要的!

在将来,当HTTP / 2规范更常见时,可能不太需要捆绑基于模块的项目,但现在我认为需要捆绑。

没有对你的typescript文件的引用(因为它们已经在制作myApp.bundled.js的过程中被传递)。正如Zama所说,你可以在任何服务器上运行angular2(我使用IIS和工作正常)。

更新:自从Angular 2的最终版本,我已经切换到使用角度cli为建设生产。安装很容易(没有意大利面条的gulp任务),最后的包是超优化的(esp由于树摇晃)。我建议检查angular-cli设置,开发和构建您的ng2项目。

angular2应用程序中的Karma测试异常

angular2应用程序中的Karma测试异常

我可以获得更好的日志吗?我不知道在哪里寻找错误.

Chrome 57.0.2987 (Linux 0.0.0) ERROR
  Uncaught Response with status: 0  for URL: null
  at webpack:///~/rxjs/Subscriber.js:238:0 <- src/test.ts:737
PhantomJS 2.1.1 (Linux 0.0.0): Executed 31 of 31 ERROR (1.258 secs / 1.352 secs)

解决方法

您的代码正在发出HTTP请求并失败.根据错误消息,URL为空且状态代码为0. 0不是实际的HTTP状态代码,但它可能意味着发生了超时.这个 Stack Overflow question and answer对0的意思有一些指示.

我在测试组件时遇到了这个问题.模拟HTTP请求解决了问题.为了做到这一点,我推荐这篇关于testing HTTP services的tratra文章.

今天关于Azure上的Angular2应用程序“您无权在子路由上查看此目录或页面”azure application insight的讲解已经结束,谢谢您的阅读,如果想了解更多关于Angular2 SEO-如何使Angle 2应用程序可抓取、Angular2 – 在Azure中托管时页面刷新404、angular2 – 如何部署Angular 2应用程序开发的Typescript到生产?、angular2应用程序中的Karma测试异常的相关知识,请在本站搜索。

本文标签: