Angular 2 从 ComponentInstruction 获取 URL [英] Angular 2 get URL from ComponentInstruction

查看:14
本文介绍了Angular 2 从 ComponentInstruction 获取 URL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的 router-outlet 缓存组件.

I have a custom router-outlet that caches components.

代码如下:https://gist.github.com/waeljammal/467286d64f59f8340a93#file-persistentrouteroutlet-ts-L75

代码示例使用组件类型作为缓存键 - 但是,我需要通过 URL 缓存我的组件类型,以便我可以缓存同一组件的两个不同实例.

The code example uses the component type as the cache key - however, I need mine to cache by the URL so that I can cache two different instances of the same component.

有没有办法根据ComponentInstruction获取URL?

Is there any way to get the URL based on the ComponentInstruction?

推荐答案

所以我现在开始工作了.错误是我将 PersistenRouterOutlet 应用到顶级路由器.

So I got this working now. The mistake was that I was applying the PersistenRouterOutlet to the top level router.

考虑urlPath:/space/settings/general.

我的 App 组件中有一个 router-outlet,然后我有一个 WorkspaceComponent 绑定到 space urlPath.

I have a router-outlet in my App component, and then I have a WorkspaceComponent that was bound to the space urlPath.

WorkspaceComponent 然后托管它自己的 router-outlet 并定义一组子路由 - 从 URL,它监听 settings/general部分.

The WorkspaceComponent then hosts its own router-outlet and defines a set of child routes - from the URL, this listens to the settings/general part.

为了解决这个问题,我从我的 App 组件中删除了 persistent-router-outlet(替换为默认的 router-outlet.

To solve this, I removed persistent-router-outlet from my App component (replaced with the default router-outlet.

然后在 WorkspaceComponent 的模板中,我将默认的 router-outlet 替换为 persistent-router-outlet.

Then in the template for the WorkspaceComponent I replaced the default router-outlet with persistent-router-outlet.

最后但并非最不重要的 - 将由子路由器(在 WorkspaceComponent 内部)实例化的组件类型需要实现 CanReuse 接口,并实现 routerCanReuse 方法:

Last but not least - the component types that will be instantiated by the child router (inside WorkspaceComponent) needs to implement the CanReuse interface, and implement the routerCanReuse method:

routerCanReuse(next: ComponentInstruction, prev: ComponentInstruction) {
    return next.urlPath === prev.urlPath;
}

PersistentRouterOutlet 的代码在这里:

"use strict";

import * as hookMod from 'angular2/src/router/lifecycle/lifecycle_annotations';
import * as routerMod from 'angular2/src/router/router';
import {isBlank, isPresent} from 'angular2/src/facade/lang';
import {StringMapWrapper} from 'angular2/src/facade/collection';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {BaseException} from 'angular2/src/facade/exceptions';
import {
ElementRef, DynamicComponentLoader, Directive, Injector, provide, ComponentRef, Attribute
} from 'angular2/core';
import {
ComponentInstruction, CanReuse, OnReuse, CanDeactivate,
RouterOutlet, OnActivate, Router, RouteData, RouteParams, OnDeactivate
} from 'angular2/router';
import {hasLifecycleHook} from 'angular2/src/router/lifecycle/route_lifecycle_reflector';

/**
 * Reference Cache Entry
 */
class RefCacheItem {
    constructor(public componentRef: ComponentRef) {

    }
}

/**
 * Reference Cache
 */
class RefCache {
    private cache: any = {};

    public getRef(type: any) {
        return this.cache[type];
    }

    public addRef(type: any, ref: RefCacheItem) {
        this.cache[type] = ref;
    }

    public hasRef(type: any): boolean {
        return !isBlank(this.cache[type]);
    }
}

/**
 * An outlet that persists the child views and re-uses their components.
 * 
 * @author Wael Jammal
 */
@Directive({ selector: 'persistent-router-outlet' })
export class PersistentRouterOutlet extends RouterOutlet {
    private currentInstruction: ComponentInstruction;
    private currentElementRef;
    private refCache: RefCache = new RefCache();
    private resolveToTrue = PromiseWrapper.resolve(true);
    private currentComponentRef: ComponentRef;

    constructor(elementRef: ElementRef,
        private loader: DynamicComponentLoader,
        private parentRouter: Router,
        @Attribute('name') nameAttr: string) {
        super(elementRef, loader, parentRouter, nameAttr);

        this.currentElementRef = elementRef;
    }

    /**
     * Called by the Router to instantiate a new component during the commit phase of a navigation.
     * This method in turn is responsible for calling the `routerOnActivate` hook of its child.
     */
    public activate(nextInstruction: ComponentInstruction): Promise<any> {
        let previousInstruction = this.currentInstruction;

        this.currentInstruction = nextInstruction;

        if (!this.refCache.hasRef(nextInstruction.urlPath)) {
            let componentType = nextInstruction.componentType;
            let childRouter = this.parentRouter.childRouter(componentType);

            let providers = Injector.resolve([
                provide(RouteData, { useValue: nextInstruction.routeData }),
                provide(RouteParams, { useValue: new RouteParams(nextInstruction.params) }),
                provide(routerMod.Router, { useValue: childRouter })
            ]);

            return this.loader.loadNextToLocation(componentType, this.currentElementRef, providers)
                .then((componentRef) => {
                    this.refCache.addRef(nextInstruction.urlPath, new RefCacheItem(componentRef));

                    this.currentComponentRef = componentRef;

                    if (hasLifecycleHook(hookMod.routerOnActivate, componentType)) {
                        return (<OnActivate>componentRef.instance)
                            .routerOnActivate(nextInstruction, previousInstruction);
                    }
                });
        }
        else {
            let ref = this.refCache.getRef(nextInstruction.urlPath);
            ref.componentRef.location.nativeElement.hidden = false;

            this.currentComponentRef = ref.componentRef;

            return PromiseWrapper.resolve(
                hasLifecycleHook(hookMod.routerOnReuse, this.currentInstruction.componentType) ?
                    (<OnReuse>ref.componentRef.instance).routerOnReuse(nextInstruction, previousInstruction) : true
            );
        }
    }

    /**
     * Called by the Router during the commit phase of a navigation when an outlet
     * reuses a component between different routes.
     * This method in turn is responsible for calling the `routerOnReuse` hook of its child.
     */
    public reuse(nextInstruction: ComponentInstruction): Promise<any> {
        let previousInstruction = this.currentInstruction;
        this.currentInstruction = nextInstruction;

        if (isBlank(this.currentComponentRef)) {
            throw new BaseException(`Cannot reuse an outlet that does not contain a component.`);
        }

        let ref = this.refCache.getRef(nextInstruction.urlPath);
        let currentRef = ref ? ref.componentRef : null;

        return PromiseWrapper.resolve(
            hasLifecycleHook(hookMod.routerOnReuse, this.currentInstruction.componentType) ?
                (<OnReuse>currentRef.instance).routerOnReuse(nextInstruction, previousInstruction) : true
        );
    }

    /**
     * Called by the Router when an outlet disposes of a component's contents.
     * This method in turn is responsible for calling the `routerOnDeactivate` hook of its child.
     */
    public deactivate(nextInstruction: ComponentInstruction): Promise<any> {
        let next = this.resolveToTrue;
        let ref = this.currentComponentRef;

        if (isPresent(ref) && isPresent(this.currentInstruction) &&
            hasLifecycleHook(hookMod.routerOnDeactivate, this.currentInstruction.componentType)) {
            next = PromiseWrapper.resolve(
                (<OnDeactivate>ref.instance)
                    .routerOnDeactivate(nextInstruction, this.currentInstruction));
        }

        return next.then(() => {
            if (isPresent(ref)) {
                ref.location.nativeElement.hidden = true;
            }
        });
    }

    /**
     * Called by the Router during recognition phase of a navigation.
     *
     * If this resolves to `false`, the given navigation is cancelled.
     *
     * This method delegates to the child component's `routerCanDeactivate` hook if it exists,
     * and otherwise resolves to true.
     */
    public routerCanDeactivate(nextInstruction: ComponentInstruction): Promise<boolean> {
        if (isBlank(this.currentInstruction)) {
            return this.resolveToTrue;
        }

        let ref = this.currentComponentRef;

        if (!ref) {
            let foundRef = this.refCache.getRef(this.currentInstruction.urlPath);
            ref = foundRef ? foundRef.componentRef : null;
        }

        if (hasLifecycleHook(hookMod.routerCanDeactivate, this.currentInstruction.componentType)) {
            return PromiseWrapper.resolve(
                (<CanDeactivate>ref.instance)
                    .routerCanDeactivate(nextInstruction, this.currentInstruction));
        }

        return this.resolveToTrue;
    }

    /**
     * Called by the Router during recognition phase of a navigation.
     *
     * If the new child component has a different Type than the existing child component,
     * this will resolve to `false`. You can't reuse an old component when the new component
     * is of a different Type.
     *
     * Otherwise, this method delegates to the child component's `routerCanReuse` hook if it exists,
     * or resolves to true if the hook is not present.
     */
    public routerCanReuse(nextInstruction: ComponentInstruction): Promise<boolean> {
        let result;

        let ref = this.currentComponentRef;

        if (!ref) {
            let foundRef = this.refCache.getRef(nextInstruction.urlPath);
            ref = foundRef ? foundRef.componentRef : null;
        }

        if (isBlank(this.currentInstruction) || !this.refCache.hasRef(nextInstruction.urlPath) || this.currentInstruction.componentType !== nextInstruction.componentType) {
            result = false;
        }
        else if (hasLifecycleHook(hookMod.routerCanReuse, this.currentInstruction.componentType)) {
            result = (<CanReuse>ref.instance)
                .routerCanReuse(nextInstruction, this.currentInstruction);
        }
        else {
            result = nextInstruction === this.currentInstruction ||
                (isPresent(nextInstruction.params) && isPresent(this.currentInstruction.params) &&
                    StringMapWrapper.equals(nextInstruction.params, this.currentInstruction.params));
        }

        return PromiseWrapper.resolve(result);
    }
}

这篇关于Angular 2 从 ComponentInstruction 获取 URL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆