在另一个组件中调用方法,数据将反映在UI

时间:2018-10-18 07:52:24

标签: angular

我有一个侧边栏组件:

import { Component, OnInit,HostBinding, Input} from '@angular/core';

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

  @Input() navItems: Array<any>;
  @HostBinding('class.sidebar-nav') true;
  @HostBinding('attr.role') role;

  constructor() {}

  ngOnInit() {
    this.navItems.push(
      {
        name: 'Vessels',
        url: '/vessels',
        icon: 'icon-speedometer',

      }
    );
  }

  isDivider(navItem) {
      return !!navItem.divider
  }

  isTitle(navItem) {
      return !!navItem.title
  }

  isHasChild(navItem) {
      return navItem.hasOwnProperty('children') && navItem.children.length > 0;
  }

  loadNew(){
    alert('sadasdasdasd');
    console.log('dd');

    this.navItems = []; 

    this.navItems.push(
      {
        name: 'Dashboard 2',
        url: '/dashboard',
        icon: 'icon-speedometer',

      }
    );
  }    
}

还有html:

<ul class="nav">
  <button (click)="loadNew()">test</button>
  <ng-template ngFor let-navitem [ngForOf]="navItems">
      <li *ngIf="!isHasChild(navitem)"
          [ngClass]="{'nav-title': isTitle(navitem), 'nav-item': !(isTitle(navitem) || isDivider(navitem)), 'nav-divider': isDivider(navitem)}"
      >
          <span *ngIf="isTitle(navitem)">{{navitem.name}}</span>
          <span *ngIf="isDivider(navitem)"></span>
          <a class="nav-link" *ngIf="!(isTitle(navitem) || isDivider(navitem))" routerLink="{{navitem.url}}"
             routerLinkActive="active">
              <i class="nav-icon" [ngClass]="navitem.icon"></i> {{navitem.name}}
          </a>
      </li>
      <li *ngIf="isHasChild(navitem)" appNavDropdown routerLinkActive="open" class="nav-item nav-dropdown open">
          <a appNavDropdownToggle class="nav-link nav-dropdown-toggle" role="button"><i class="nav-icon" [ngClass]="navitem.icon"></i> {{navitem.name}}</a>
          <ul class="nav-dropdown-items">
              <li class="nav-item" *ngFor="let cnavitem of navitem.children">
                  <a class="nav-link" *ngIf="!(isTitle(cnavitem) || isDivider(cnavitem))" routerLink="{{cnavitem.url}}"
                     routerLinkActive="active">
                      <i class="nav-icon" [ngClass]="cnavitem.icon"></i> {{cnavitem.name}}
                  </a>
              </li>
          </ul>
      </li>
  </ng-template>
</ul>

如果我单击组件中的按钮,它将自动删除所有项目。

但是,如果我从其他组件调用函数loadMenu,则会调用该方法,但是UI剂量会更新吗?就像navItems一样,它有自己的实例。您将如何从另一个组件控制navItems并更新UI?

import { Component, OnInit } from '@angular/core';
import { SidebarNavCustomComponentComponent} from '../sidebar-nav-custom-component/sidebar-nav-custom-component.component';

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

  constructor(private sidebar: SidebarNavCustomComponentComponent) { }

  ngOnInit() {
  }

  loadMenu(){
    alert('lol');
    this.sidebar.loadNew();
  }

}

2 个答案:

答案 0 :(得分:1)

您的目标

很明显,您希望在不同组件之间进行通信。

问题?

实施中存在几个问题

  1. 注入组件参考。在除非您要操作DOM之前,否则这不是一个很好的实践。
  2. 问题是数组对变量navItems的新引用。除了分配新值,您还可以清空现有数组并将新项目推入其中。

解决方案

根据您的要求,您应该创建服务,该服务将充当不同组件之间的桥梁。该服务类将通知所有组件任何更改。

示例

  

data.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class DataService {

  private messageSource = new BehaviorSubject();

  getData(){
     return this.messageSource.asObservable();
  }

  reloadData() {
    let data = [{
    name: 'Dashboard 2',
    url: '/dashboard',
    icon: 'icon-speedometer',

  }];
    this.messageSource.next(data); //notify all that data is loaded.
  }

}
  

app-sidebar-nav-custom-component.ts

export class SidebarNavCustomComponentComponent implements OnInit {

  @Input() navItems: Array<any>;
  @HostBinding('class.sidebar-nav') true;
  @HostBinding('attr.role') role;

  constructor(private dataService : DataService) {
       this.dataService.getData().subscribe(data=>{
          this.navItems = data;  //update the data whenever data is updated in service.
       });
   }
}
  

app-vessels.ts

Finally you can update the data

import { Component, OnInit } from '@angular/core';
import { SidebarNavCustomComponentComponent} from '../sidebar-nav-custom-component/sidebar-nav-custom-component.component';

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

  constructor(private sidebar: SidebarNavCustomComponentComponent, private dataService : DataService) { }

  ngOnInit() {
  }

  loadMenu(){
    this.dataService.realoadData(); //reload new data. 
  }

}
  

最后的笔记:

  1. 不要忘记将DataService放在模块的providers数组中。
  2. 上面编写的
  3. 代码直接键入stackoverflow,因此可能存在一些与拼写错误或语法错误有关的小问题。因此,请纠正自己。

答案 1 :(得分:0)

每当应用程序由于用户事件或从网络请求接收到的数据而发生更改时,Angular都会对所有组件(从上到下)执行更改检测。变更检测非常有效,但是随着应用程序变得越来越复杂以及组件数量的增加,变更检测将不得不执行越来越多的工作。但是,有一种方法可以解决此问题,并将特定组件的更改检测策略设置为OnPush。这样做将指示Angular仅在将新引用传递给组件和它们的子树时(而不是简单地对数据进行突变时)对它们进行更改检测。

看看Change Detection Strategy in Angular