Angular组件不会对属性更改做出反应

时间:2019-08-19 08:31:42

标签: angular typescript angular-services

我有一个header-comp,一个服务和一个content-comp。在header-comp中,我在服务中切换了一个bool-var,以显示或隐藏移动菜单(响应式)。

我想从content-comp收听此布尔更改,并且它仅在我在服务构造函数中触发时才起作用:

  export class AppService {

  public mblMenuVisible: boolean = false;
  public mobileLayout: boolean;

  constructor() {
    this.determineLayout();

    setTimeout(()=>{
      this.mblMenuVisible = true;
    }, 3000);
  }

  toggleMblMenu() {
    if (this.mblMenuVisible) {
      this.mblMenuVisible = false;
    } else {
      this.mblMenuVisible = true;
    }
  }

如果我通过toggleMblMenu()手动切换它,则我的content-comp将不会对此更改做出反应。 content-comp中的ngClass应该对此更改做出反应:

<div [ngClass]="(service.mblMenuVisible===true)?'mbl-content-wrapper':'content-wrapper'">

编辑:

我尝试过:

  • changeDetection:ChangeDetectionStrategy.Default

  • markForCheck()

  • 通过主题仅在标题中起作用。

  • 依赖关系也是最新的

标题:

import {ChangeDetectorRef, Component, HostListener, OnInit} from '@angular/core';
import {AppService} from "../shared/appService";

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css'],
  providers: [AppService]
})
export class HeaderComponent implements OnInit {

  private mobileMenuVisible: boolean;

  constructor(private service: AppService,
              private cd: ChangeDetectorRef) {
  }

  ngOnInit() {
    this.service.layoutAction.subscribe(
      (visible: boolean) => {
        this.mobileMenuVisible = visible;
      });
  }

  @HostListener('window:resize', ['$event']) resize(e) {
    this.service.determineLayout();
    this.cd.detectChanges();
    if (!this.service.mobileLayout) {
      this.service.mblMenuVisible = false;
    }
  }
}

服务:

import {Injectable} from "@angular/core";
import {Subject} from "rxjs";

@Injectable()
export class AppService {

  public layoutAction = new Subject<boolean>();
  public mblMenuVisible: boolean = false;
  public mobileLayout: boolean;

  constructor() {
    this.determineLayout();
  }
  //LAYOUT
  determineLayout() {
    if (window.innerWidth > 800) {
      this.mobileLayout = false
    } else {
      this.mobileLayout = true;
    }
  }

  toggleMblMenu (){
    this.mblMenuVisible = !this.mblMenuVisible;
    this.layoutAction.next(this.mblMenuVisible);
  }
}

内容:

import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core';
import {AppService} from "../shared/appService";

@Component({
  selector: 'app-content',
  templateUrl: './content.component.html',
  styleUrls: ['./content.component.css'],
  providers: [ AppService ],
  changeDetection: ChangeDetectionStrategy.Default
})
export class ContentComponent implements OnInit {

  private mobileMenuVisible: boolean;

  constructor(private service: AppService,
              private cd: ChangeDetectorRef) {
  }

  ngOnInit() {
      this.service.layoutAction.subscribe(
        (visible: boolean) => {
          alert(visible);
          this.mobileMenuVisible = visible;
          this.cd.markForCheck();
        });
  }
}

3 个答案:

答案 0 :(得分:0)

在HTML文件中,您应该绑定到service.mblMenuVisible而不是toggleMblMenu,因为在mblMenuVisible方法中,您正在更改service.mblMenuVisible而不是{{1}}的状态

答案 1 :(得分:0)

TLDR:使用Angular FlexLayout Responsive Features是解决此移动问题的很好工具。

新回复, 现在来看一下您最近编辑中添加的这段代码,

@Injectable()
export class AppService {
  ...
  determineLayout() {
    if (window.innerWidth > 800) {
      this.mobileLayout = false
    } else {
      this.mobileLayout = true;
    }
  }
  ...
}

@Component()
export class AppComponent{
  constructor(private service:AppService){}
  ...
  @HostListener('window:resize', ['$event']) 
  resize(e) {
    this.service.determineLayout();
    //this.cd.detectChanges();
    if (!this.service.mobileLayout) {
      this.service.mblMenuVisible = false;
    }
  }
  ...
}

可以通过Angular FlexLayout Responsive Features

满足这一需求。

setting up后使用Angular flex进行角度投影, 可以像这样的示例编写响应指令,

<div fxShow.lt-md fxHide fxFlex >
  <!-- MobileMenu Contents -->
</div>
<div fxShow fxHide.lt-md fxFlex >
  <!-- DesktopMenu Contents -->
</div>

Angular FlexLayout响应指令是针对您在此处所做的事情而编写的,无需手动侦听窗口调整大小事件并触发布尔值更改即可使您的组件响应媒体查询断点。

此外,还有一种使用vanilla mediaqueries

的纯CSS方法

答案 2 :(得分:0)

只需将您的服务作为所有组件的全局服务,只需将此AppService添加到AppModule提供程序列表并从组件装饰器中删除providers: [ AppService ],,因为这样您就可以创建两个不同的对象一个并在sigle上更改te值将不会反映另一个,但是当您将服务添加到appModule时,将仅创建一次,现在您在所有组件中都将具有相同的引用

@Injectable({
    providedIn:'root'
})
AppService  {
 ...
}
  

Singleton services单例服务是为其提供服务的服务   应用程序中只有一次实例。

demo ??

在演示拖曳组件(a,b)中更改属性mblMenuVisible的值,并且所需的组件已注入此服务并对值的更改做出反应,以显示或隐藏名为menu的示例组件,值的主要原因是更改,因为注入的AppService是同一对象