簡體   English   中英

如何在Angular2中操作特定路徑上的組件

[英]How to manipulate a component on specific routes in Angular2

我有一個簡單的TopbarComponent ,它基本上在我的視圖頂部添加了一個bootstrapish導航欄。

由於90%的模板都應包含此指令,我想通過我的app.component處理它,如下所示:

import ...;

@Component({
    selector: 'my-app',
    templateUrl: 'app/app.component.html',
    directives: [ROUTER_DIRECTIVES, TopbarComponent, ...],
    providers: [ROUTER_PROVIDERS, ...]
})

@RouteConfig([
{
    path: '/login',
    name: 'Login',
    component: LoginComponent
},
{
    path: '/dashboard',
    name: 'Dashboard',
    component: DashboardComponent,
    useAsDefault: true
}
])

其模板看起來像這樣:

<my-topbar></my-topbar>

<div class="container-fluid">
    <div class="row">
        <router-outlet></router-outlet>
    </div>
</div>

現在我想使用ngIf (或除了用css隱藏它之外的任何其他方式)來隱藏多個路由上的ngIf ,例如/login 我嘗試了幾種方法,使用@CanAcitvate()或在我的LoginComponent實現OnActivate (以及從我的AppComponent嘗試)但沒有任何效果(甚至有問題甚至讓函數觸發)。 我得到的最接近的是直接在我的AppComponent使用Router ,如下所示:

export class AppComponent implements OnInit{
    showTopbar:boolean;

    constructor(private _router:Router) {}

    ngOnInit():any {
        this.showTopbar = this._router.lastNavigationAttempt != '/login';
    }
}

在我的app.component.html我將指令更改為<my-topbar *ngIf="showTopbar"></my-topbar>

但這僅適用於我的應用程序的初始加載,因為每次狀態更改都不會觸發ngOnInit 有沒有類似的方法我可以使用(並且找不到)或者我在這里走向錯誤的方向?


編輯:

目前,PierreDuc的答案對我不起作用,但我嘗試使用location.path()這樣的類似方法:

constructor(private _location:Location) {}

private get _hideTopbar() : boolean {
    switch(this._location.path()){
        case '/register':
        case '/login':
            return true;
        default:
            return false;
    }
};

太糟糕了,我不能在這種方法中使用@RouteConfig中的data屬性。 感覺會好一些。

我已經在一段時間內遇到了類似的問題。 我發現的解決方案起初可能會被視為棘手,但可以在將來為我解決此類問題。

基本上,您必須讓router-outlet在路由更改時發出事件,讓AppComponent偵聽該自定義事件。

第一步是創建自定義路由器插座:

@Directive({
selector: 'custom-router-outlet'
})
export class CustomRouterOutlet extends RouterOutlet {
    private parentRouter:Router;

    constructor(_elementRef: ElementRef,
            _loader: DynamicComponentLoader,
            _parentRouter: Router,
            @Attribute('name') nameAttr: string) {
    super(_elementRef, _loader, _parentRouter, nameAttr);
    this.parentRouter = _parentRouter;
    }

    activate(nextInstruction: ComponentInstruction): Promise<any> {
        //***YOUR CUSTOM LOGIC HERE***
        return super.activate(nextInstruction);
    }
}

這是自定義路由器插座的一個非常基本的實現。 您的邏輯必須在activate方法中實現,在每次路由更改時調用。 在此方法中,您可以檢查路徑中的data屬性。

主要問題是,目前, 指令不能發出事件......它們只接受輸入,不能觸發任何輸出......

我找到了解決此問題的方法:使用EventEmitter為組件和指令之間的通信創建服務

@Injectable()
export class PubsubService {
    private _pubSubber: EventEmitter<any> = new EventEmitter();

    routeisChanging(obj:any) {
        this._pubSubber.emit(obj);
    }

    onRouteChanged() {
        return this._pubSubber;
    }
}

AppComponent訂閱了onRouteChanged事件:

subscription:any;
constructor(private _pubsubService:PubsubService) {
    this.subscription = this._pubsubService.onRouteChanged().subscribe(data => {
        /**YOUR CUSTOM LOGIC HERE*/});
}

CustomRouterOutlet在需要時在activate方法中觸發事件:

activate(nextInstruction: ComponentInstruction): Promise<any> {
    //***YOUR CUSTOM LOGIC HERE***
    this._pubsubService.routeisChanging(nextInstruction.routeData.data['hideTopbar']);
    return super.activate(nextInstruction);
}

通過這種方式,您可以使用任何邏輯輕松實現路由器與AppComponent之間的通信。

您必須記住在應用程序的RootComponent中注入通信服務。

不確定它是否是正確的方法,但您可以在@RouteConfig()對象的data參數中添加任何數據。 例如,您可以在這個地方RouteDefinitionLogin的對象與hideTopbar設置。 如果應將其設置為true,則只需將其放在路徑中:

警告,未經測試的代碼:)

@RouteConfig([{
    path: '/login',
    name: 'Login',
    component: LoginComponent,
    data : {hideTopbar : true}
},
//...
])

您可以在AppComponent類中訪問此數據,如:

export class AppComponent {

    private get _hideTopbar() : boolean {
       return this._data.get('hideTopbar');
    };

    constructor(private _data:RouteData) {}

}

並將AppComponent模板更改為:

<my-topbar *ngIf="!_hideTopbar"></my-topbar>

<div class="container-fluid">
    <div class="row">
        <router-outlet></router-outlet>
    </div>
</div>

幾乎在那里,試試這個

模板

<my-topbar *ngIf="shouldShowTopbar()">
</my-topbar>

應用組件

export class AppComponent implements OnInit{

    hideWhen: Array<string> = ['Login', 'Help', 'SomeOtherRoute'];
       // put all the route names where you want it hidden in above array

    constructor(private _router:Router) {}

    shouldShowTopbar() {
     return (hideWhen.indexOf(this._router.currentInstruction.component.routeName) > -1);
    }

}

我有類似的問題。 也許這不是最好的方式。 但我這樣解決了:

我創建了一個新組件。 此組件處理需要導航欄的所有路徑。 其他路由由app.component處理。

以下是一些需要了解的代碼:

app.component

@RouteConfig([
{
    path: '/...',
    name: '...',
    component: MyComponentWhoAddsNavbar,
    useAsDefault: true
},
{   path: '/login',
    name: 'Login',
    component: LoginComponent
}
])


@Component({
selector: 'my-app',
template: '<router-outlet></router-outlet>', 
})

export class AppComponent {}

這里是MyComponentWhoAddsNavbar

@RouteConfig([
    put your routes here who need a navbar
])

@Component({
    selector: '...',
    template: `
        <navbar></navbar>
        <router-outlet></router-outlet> 
    `,

 })

export class MyComponentWhoAddsNavbar{} 

我在工作

"@angular/common": "~2.1.0"

我解決這個問題的方法是創建一個global應用程序范圍的數據對象和一個GlobalService服務。 任何組件都可以subscribe()全局或部分全局對象。 出於您的目的,您應該創建一個布爾屬性isTopBar: true 您可以訂閱<topBar>組件並使用該值進行切換。

isTopBar: boolean;

ngOnInit(){
  this._globalService.getIsTopBar().subscribe(isTopBar => this.isTopBar = isTopBar)
}

<my-topbar *ngIf="isTopBar"></my-topbar>

我發現這種“全球服務”的一大優勢是我可以將很多狀態信息保存到我的后端。 在你的例子中它不太有用,但你有一套內部標簽的成像; 您可以保存用戶上次選擇的選項卡,並在以后重新訪問該頁面時重新加載到該視圖。

這根本不是完成它的正確方法,但它對我有用。 它不是根據路徑本身改變可見性,而是根據路線中顯示的組件改變可見性。

我已經在使用服務來為導航欄提供所有部分,等等,所以我認為它也可以告訴導航欄何時出現。

我基本上在這個服務中創建了一個主題,通過一系列方法來確定它是否可見,以改變這種可見性。

@Injectable()
export class NavigationService {

  mobileNavbarIsVisible = true;
  mobileNavbarIsVisibleChanged = new Subject<boolean>();

  constructor() { }

  getSections() {
    return this.sections;
  }

  getMobileNavbarIsVisible() {
    return this.mobileNavbarIsVisible;
  }

  hideMobileNavbar() {
    this.mobileNavbarIsVisible = false;
    this.mobileNavbarIsVisibleChanged.next(this.mobileNavbarIsVisible);
  }

  showMobileNavbar() {
    this.mobileNavbarIsVisible = true;
    this.mobileNavbarIsVisibleChanged.next(this.mobileNavbarIsVisible);
  }

}

然后,我在影響可見性的組件中調用那些方法 - 在我的情況下,每當我編輯項目列表中的項目時,我希望導航欄消失 - 。 我啟動此組件時調用hide方法,並在銷毀時調用show方法。

@Component({
  selector: 'app-item-edit',
  templateUrl: './item-edit.component.html',
  styleUrls: ['./item-edit.component.css']
})
export class ItemEditComponent implements OnInit, OnDestroy {

  constructor(private navigationService: NavigationService) {}
  ngOnInit() {
    this.navigationService.hideMobileNavbar();
  }
  ngOnDestroy() {
    this.navigationService.showMobileNavbar();
  }
}

然后,我的NavbarComponent正在監聽該主題,並根據該值顯示或不顯示:

@Component({
  selector: 'app-mobile-navbar',
  templateUrl: './mobile-navbar.component.html',
  styleUrls: ['./mobile-navbar.component.css']
})
export class MobileNavbarComponent implements OnInit {
  isVisible = true;
  ngOnInit() {
    this.isVisible = this.navigationService.getMobileNavbarIsVisible();
    this.navigationService.mobileNavbarIsVIsibleChanged.subscribe(
      (visibilityValue) => this.isVisible = visibilityValue
    );
  }
}

正如我所說,它很可能不是正確或最有效的方式,但如果您只想在啟動其他組件時隱藏導航欄,它就可以工作,因為它們只是使用導航服務作為通信方式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM