【问题标题】:active tab issue in angular 2 - tabs角度 2 中的活动选项卡问题 - 选项卡
【发布时间】:2017-10-11 11:15:23
【问题描述】:

需要帮助来解决 Angular 2 应用程序中的活动选项卡问题。

Plunker link

我正在从 json 加载选项卡和相应信息。

我有复杂的json格式,但这里我做了简化版。

问题:初始阶段未设置活动标签。

预期:第一个标签'Tab 1'需要有active类。

请注意:点击标签时,活动类已经添加。 所以需要修复第一个元素的活动标签。所以我们应该干预其他功能。

感谢任何帮助。

Json

[
      {
        "id": "1",
        "name": "Tabs 1",
        "content": [
          {
            "header": "Basic Information",
            "contents": [
              {
                "label": "Report 1"
              }
            ]
          }
        ]
      },
      {
        "id": "2",
        "name": "Tabs 2",
        "content": [
          {
            "header": " Information",
            "contents": [
              {
                "label": "Report 2"
              }
            ]
          }
        ]
      },
      {
        "id": "3",
        "name": "Tabs 3",
        "content": [
          {
            "header": " report",
            "contents": [
              {
                "label": "Report 3"
              }
            ]
          }
        ]
      },
      {
        "id": "4",
        "name": "Tabs 4",
        "content": [
          {
            "header": " content Report",
            "contents": [
              {
                "label": "Report 4"
              }
            ]
          }
        ]
      }
    ]

app-service.ts

import { Injectable }     from '@angular/core';
import { Http, Response }     from '@angular/http';
import { Observable }     from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()

export class DashboardService {
  private _url: string = "./app/report.json";

  constructor(private _http: Http) {}

  getRecords() {
    return this._http.get(this._url)
      .map((response: Response) => response.json())

  }

  _errorHandler(error: Response) {
    console.error(error);
    return Observable.throw(error || "Server Error");
  }

}

app.component.ts

import {Component,ContentChildren,QueryList, OnInit, 
Injectable, Inject} from '@angular/core';
    import {TAB_COMPONENTS} from './tabset';
    import {Tab} from './tab';
    import { DashboardService } from './app-service';

    @Component({
      selector: 'my-app',
      template: `
            <h2>App Component</h2>
         <tabset>
          <tab *ngFor="let tab of records" [title]="tab.name"> 
            <div *ngFor="let header of tab.content">
            {{header.header}}
            <div *ngFor="let label of header.contents">{{label.label}}</div>
            </div>
          </tab>
        </tabset>
        `
    })
    @Injectable()
    export class AppComponent implements OnInit {
      records = [];
      errorMsg: string;

      constructor(@Inject(DashboardService) private _dashboardService: DashboardService) {
        //this.getRecords();
      }

      // getting json values from report.json
      // To build the form
      ngOnInit() {
        this._dashboardService.getRecords()
          .subscribe(
            resGetRecords => {
              debugger;

              this.records = resGetRecords

            },
            resRecordsError => this.errorMsg = resRecordsError
          );
      }
    }

tab.ts

import { Component, Input } from "@angular/core";

@Component({
  selector: 'tab',
  template: `
    <ng-content *ngIf="active"></ng-content>
  `
})
export class Tab {

  @Input() title = '';
  @Input() active = false;
  @Input() disabled = false;

}

tabset.ts

import {
  Component,
  Input,
  Output,
  ContentChildren,
  HostListener,
  EventEmitter
} from '@angular/core';

import { Tab } from './tab';

@Component({
  selector: 'tabset',
  template: `
    <section class="tab-set">
      <ul
        class="nav"
        [class.nav-pills]="vertical"
        [class.nav-tabs]="!vertical">
        <li
          *ngFor="let tab of tabs"
          [class.active]="tab.active">
          <a
            (click)="tabClicked(tab)"
            class="btn"
            [class.disabled]="tab.disabled">
            <span>{{tab.title}}</span>
          </a>
        </li>
      </ul>
      <div class="tab-content">
        <ng-content></ng-content>
      </div>
    </section>
  `
})
export class Tabset {

  @Input() vertical;
  @Output() onSelect = new EventEmitter();
  @ContentChildren(Tab) tabs;

  ngAfterContentInit() {
    const tabs = this.tabs.toArray();
    const actives = this.tabs.filter(t => {
      return t.active
    });

    if (actives.length > 1) {
      console.error(`Multiple active tabs set 'active'`);
    } else if (!actives.length && tabs.length) {
      tabs[0].active = true;
    }
  }

  tabClicked(tab) {
    const tabs = this.tabs.toArray();

    tabs.forEach(tab => tab.active = false);
    tab.active = true;

    this.onSelect.emit(tab);
  }

}

export const TAB_COMPONENTS = [
  Tabset,
  Tab
];

【问题讨论】:

  • 您使用的是哪个版本的 Angular?
  • 嗨,我正在使用 angular 2

标签: javascript json angular tabs


【解决方案1】:

编辑:答案最终与我认为的您的问题不相似。对不起。

-- 如果您使用 angular 4 --

你可以看到类似的issue that I have reported。

有一个技巧可以让它工作:

[routerLinkActive]="['']" [ngClass]="rla.isActive?'active':''" #rla="routerLinkActive"

【讨论】:

  • 谢谢。正如你提到的它对角度 2 没有帮助
【解决方案2】:

如果您不从 json 加载数据,它会起作用,我的意思是您需要等待之前的异步行为。

第一次使用空数组records = [];(在app.component.ts中)初始化选项卡

在 tabset 组件中,在你的 ngAfterContentInit 中,你只检查第一个 tabs 数据,这一次是一个空数组,并用第一个 tab 初始化 tabset,这一次是 未定义。所以没有选项卡被设置为活动,这就是为什么没有选择的选项卡。

只有在加载JSON数据,订阅http后,标签数据才会更新为正确的内容((与json中的4个项目)),并且没有任何操作来检查和设置默认选择的标签.

因此,您的解决方案是在设置所选标签之前订阅标签中的更改:

ngAfterContentInit() {
    this.tabs.changes.subscribe((changes)=> {
      const tabs = this.tabs.toArray();
      const actives = this.tabs.filter(t => {
        return t.active
      });

      if (actives.length > 1) {
        console.error(`Multiple active tabs set 'active'`);
      } else  {
        this.tabClicked(tabs[0]);
      }
    });       
}

补充:

如果您遇到如下错误:

Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.

您需要添加setTimeout() 中描述的the angular doc here

ngAfterViewInit() 生命周期钩子是一个重要的问题。这 计时器组件直到 Angular 显示 父视图。所以它最初显示 0 秒。然后 Angular 调用 ngAfterViewInit 生命周期钩子,此时为时已晚 更新父视图的倒计时秒数显示。角的 单向数据流规则防止更新父视图的 同一个周期。该应用程序必须等待一圈才能显示 秒。

使用 setTimeout() 等待一个滴答,然后修改 seconds() 方法 以便它从计时器组件中获取未来值。

那么现在:

tabClicked(tab) {
    const tabs = this.tabs.toArray();
    tabs.forEach(tab => tab.active = false);
    setTimeout( () => tab.active = true);
    this.onSelect.emit(tab);
}

工作人员:https://plnkr.co/edit/AZpieA3kow3xGT8UCIaj?p=preview

【讨论】:

  • 很好的解释。感谢您为此工作。它现在可以工作了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-22
  • 1970-01-01
相关资源
最近更新 更多