Angular组件拿不到@Input输入属性问题探究解决方法

目录
  • 区别一
  • 区别二
  • 区别三
  • 总结

我需要给一个Component设置一个输入属性 @Input,好了,直接上代码,没有什么难度。

原代码是这样的:

@Component({
    selector: 'my-menu',
    templateUrl: './main-menu.widget.html'
})
export class MyMenuWidget {
  data: any[];
  ...
    constructor(...) {
       this._changesSubscription = this._service.changes.pipe(
            map((data: any[]) => {
                    ...
                    return data;
            })
        ).subscribe((data: any[]) => {
            this.data = data;
        });
    }
  ...
}

添加一个输入属性:

@Component({
    selector: 'my-menu',
    templateUrl: './main-menu.widget.html'
})
export class MyMenuWidget {
  @Input() isMainMenu: boolean = false;
  data: any[];
  ...
    constructor(...) {
        this._changesSubscription = this._service.changes.pipe(
                map((data: any[]) => {
                        ...
                        return data;
                })
        ).subscribe((data: any[]) => {
            if (this.isMainMenu) {
               this.data = data.filter((d: any) => d.ID === 233);
            }
            else {
              this.data = data;
            }
        });
    }
  ...
}

使用起来:

<my-menu [isMainMenu]="mainMenu"></my-menu>

然后发现MyMenuWidget里的输入属性isMainMenu始终拿不到值,难道哪里拼写有问题吗?检查了一下,发现完全没有问题,但就是拿不到值。

定睛一看,啊啊啊???,对一个Observable的订阅居然写在了构造函数里!!!尽管这样写在一些场景下是可以正常工作的,不影响代码功能,但是这种写法很不规范,就像上面例子中的代码一样,引起了问题。所以,平时开发过程中, 不建议去这么写,那正确的写法是什么呢?

上代码。

@Component({
    selector: 'my-menu',
    templateUrl: './main-menu.widget.html'
})
export class MyMenuWidget {
  @Input() isMainMenu: boolean = false;
  data: any[];
  ...
  constructor(...) {
     ...
  }
    ngOnInit() {
        this._changesSubscription = this._service.changes.pipe(
            map((data: any[]) => {
                ...
                return data;
            })
        ).subscribe((data: any[]) => {
            if (this.isMainMenu) {
                    this.data = data.filter((d: any) => d.ID === 233);
            }
            else {
                this.data = data;
            }
        });
    }
  ...
}

那么问题来了,为什么同样的代码放ngOnInit里就可以正常工作呢?有人会说,我们就是应该放ngOnInit里就行了,放构造函数里就是不行。那为啥不行呢,需要去弄明白。

问题就是,Angular构造函数和ngOnInit函数的区别是什么呢?

区别一

语言上的区别:

先从语言的角度上看一下他们的区别。ngOnInit只是组件类上的一个方法,结构上和类上的其他方法没有什么不同,只是有一个特定的名字。

export class MyMenuWidget implements OnInit {
   ngOnInit() {}
}

实现不实现他都是可以的,我还可以这么写,完全没有问题。无需显示的标记要实现这个接口。

export class MyMenuWidget {
   ngOnInit() {}
}

这是ES6的写法,上面的代码用ES5怎么写呢?

构造函数和他完全不一样,他会在创建类实例的时候会被调用。

export class MyMenuWidget {
   constructor(){}
   ngOnInit() {}
}

区别二

组件初始化过程的区别:

从组件初始化角度来看两者的区别,还是很大的。Angular的启动过程有两个主要阶段:

1. 构造组件树;

2. 执行变更检测;

当Angular构造组件树时候,需要创建组件实例,首先就会调用构造函数new 一个实例出来,也就是调用组件类的构造函数。然后调用,包括ngOnInit的所有生命周期钩子都作为变更检测阶段的一部分被调用。

当Angular开始变更检测时,组件树已经构建好,并且已经调用树中所有组件的构造函数。此外,此时每个组件的模板节点都添加到DOM中。 在这里,你可以使用初始化组件所需的所有数据——DI provider,DOM等。@Input通信机制作为变更检测阶段的一部分进行处理的,所以@Input在构造函数中不可用。

export class MyMenuWidget {
   constructor(private _elementRef: ElementRef){
     ...
   }
   ngOnInit() {}
}

区别三

功能上的区别:

对于Angular构造函数,主要用来初始化,和注入依赖关系。通常的做法是,尽可能少放逻辑到构造函数中,有时候,尽管你放了很多逻辑但不影响功能。

对于ngOnInit,Angular在创建组件的DOM,使用构造函数注入所有必须的依赖,完成初始化后调用ngOnInit,这是执行组件初始化逻辑的好地方。

简单的说 ,constructor构造函数本身是和Angular无关的,ngOnInit这些钩子函数是Angular里定义的。

总结

现在是不是清楚为什么@Input在构造函数里拿不到值的了吧。以后也清楚哪些逻辑放构造函数里,哪些放ngOnInit里了吧。

到此这篇关于Angular组件拿不到@Input输入属性问题探究解决方法的文章就介绍到这了,更多相关Angular @Input输入属性内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 如何通过简单的代码描述Angular父组件、子组件传值

    目录 引言 零.知识铺垫 CSS选择器 一.什么是父子组件 二.父组件调用子组件的方法 三.父组件向子组件传值 子组件使用@input装饰器接收数据 父组件使用方括号[]发送数据 升级:子组件通过set方法监听传入数据变化 另一种升级:子组件通过ngOnChanges()生命周期钩子监听传入数据变化 四.子组件向父组件传值 子组件向父组件弹射事件 父组件监听子组件弹射的事件 五.总结 六.后记 总结 引言 对于稍微接触过Angular组件的同学来说,组件间交互应该没有什么问题. 本文想追求的是用

  • 简单谈谈Angular中的独立组件的使用

    目录 前言 如何创建一个独立组件 在独立组件中导入已有的模块 使用独立组件启动Angular应用 为独立组件配置路由 配置依赖注入 源代码 前言 Angular 14一项令人兴奋的特性就是Angular的独立组件终于来了. 在Angular 14中, 开发者可以尝试使用独立组件开发各种组件,但是值得注意的是Angular独立组件的API仍然没有稳定下,将来可能存在一些破坏性更新,所以不推荐在生产环境中使用. 如何创建一个独立组件 对于已有的组件,我们可以在@Component()中添加stand

  • 详解Angular组件之中间人模式

    一.中间人模式 该组件树中除了组件1以外,每个组件都有一个父组件可以扮演中间人的角色.顶级的中间人是组件1,它可以使组件2,组件3,组件6之间互相通讯.依次类推,组件2是组件4和组件5的中间人.组件3是组件7和组件8的中间人. 中间人负责从一个组件接收数据并将其传递给另一个组件. 二.例子 股票报价组件为例,假设交易员在监看着报价组件的价格,当股票价格达到某一个值的时候,交易员会点一个购买按钮,来购买股票.问题:报价组件并不知道应该如何下单来买股票,它只是用来监控股票价格的.所以报价组件在这时应

  • Angular懒加载动态创建显示该模块下声明的组件

    目录 环境: Angular 13.x.x 新建一个angular项目 懒加载工具栏组件 toolbar.module.ts toolbar.component.ts toolbar.component.html app.component.ts 环境: Angular 13.x.x angular中支持可以通过路由来懒加载某些页面模块已达到减少首屏尺寸, 提高首屏加载速度的目的. 但是这种通过路由的方式有时候是无法满足需求的. 比如, 点击一个按钮后显示一行工具栏, 这个工具栏组件我不希望它默

  • 详解Angular组件之投影

    概述 运行时动态改变组件模版的内容.没路由那么复杂,只是一段html,没有业务逻辑. ngContent指令将父组件模版上的任意片段投影到子组件上. 一.简单例子 1.子组件中使用<ng-content>指令来标记投影点 <div class="wrapper"> <h2>我是子组件</h2> <div>这个div定义在子组件中</div> <ng-content></ng-content>

  • 详解Angular父子组件通讯

    概述 Angular组件间通讯 组件树,1号是根组件AppComponent. 组件之间松耦合,组件之间知道的越少越好. 组件4里面点击按钮,触发组件5的初始化逻辑. 传统做法:在按钮4的点击事件里调用组件5的方法.紧密耦合. Angular:在组件4根本不知道组件5存在的情况下实现. 使用松耦合的方式在组件之间传递数据开发出高重用性的组件. 使用输入输出属性在父子关系的组件之间传递数据. 一.输入输出属性概述 组件设计成黑盒模型,用输入属性声明从外部世界接收什么东西.不需要知道这些东西从哪里来

  • 详解Angular组件数据不能实时更新到视图上的问题

    目录 问题起源 OnPush策略 当前组件或子组件之一触发了事件 总结 问题起源 MainComponent: @Component({ selector: 'main', template: ` <MenuComponent [isReport]="isReport"> </MenuComponent> `, changeDetection:ChangeDetectionStrategy.OnPush }) export class MainComponent

  • Angular组件拿不到@Input输入属性问题探究解决方法

    目录 区别一 区别二 区别三 总结 我需要给一个Component设置一个输入属性 @Input,好了,直接上代码,没有什么难度. 原代码是这样的: @Component({ selector: 'my-menu', templateUrl: './main-menu.widget.html' }) export class MyMenuWidget { data: any[]; ... constructor(...) { this._changesSubscription = this._s

  • IOS开发中键盘输入屏幕上移的解决方法

    在IOS开法中经常会遇到键盘遮挡屏幕的事情(比如输入账号密码验证码等等),就使得原本都不大的屏幕直接占了一半甚至更多的位置,这倒无所谓,关键是挡住了下面的按钮.这样的话按钮的事件也就触发不了,最好的解决办法就是当输入这些信息的时候让整个屏幕上移一个键盘的位置,或者上移到指定的位置. 首先一般输入的话都用的是UITextField,所以要监听用户什么时候开始输入和什么时候结束输入,直接设置代理代理就行了,要遵受 UITextFieldDelegate协议. //遵循协议 @interface Vi

  • Mac OS X 下 IntelliJ IDEA、jEdit 等 Java 程序中文标点输入无效的完美解决方法

    Mac OS X 下基于 Java 的程序(如 IntelliJ IDEA.jEdit 等)会出现中文标点输入无效的问题,在中文输入法状态,可以输入中文字,但输入中文标点最后上去的是英文标点.查阅了相关资料,原来这是 Java 自己的 bug.从 Java 8u51 版本开始就出现了这个 bug,一直到现在最新的 Java 8u72 仍然如此,但是老版本 Java 8u45 是没有这个问题的.所以,可以采取变通的方法,在 Mac OS X 上同时装一个老版本的 JDK 8u45,不会影响已经安装

  • Android使用TextView,设置onClick属性无效的解决方法

    Android在布局文件中为View提供了onClick属性,使用方法如下: <TextView android:id="@+id/user" android:layout_width="@dimen/px_171" android:layout_height="fill_parent" android:onClick="iconClickListener" android:clickable="true&qu

  • vue组件中节流函数的失效的原因和解决方法

    今天使用节流函数的时候遇见了一个问题,搞了半天才找到原因,所以在这里做个总结. 节流函数 浏览器的一些事件,如:resize,scroll,mousemove等.这些事件触发频率太过频繁,绑定在这些事件上的回调函数会不停的被调用,加重浏览器的负担,导致用户体验非常糟糕.所以先贤们发明了节流函数,简单版本如下: function throttle (f, wait = 200) { let last = 0 return function (...args) { let now = Date.no

  • IE中document.createElement的iframe无法设置属性name的解决方法

    iframe 的name可以是link或者form的target,将link或form打开到这个iframe上. 之前在IE遇到过设置不了iframe的name属性 JavaScript代码 var iframe = document.createElement('iframe'); iframe.name = 'ifr'; //iframe.setAttribute('name', 'ifr'); //这样也不行 上面两种方式都无法设置.后来找到原来也可以这样创建 JavaScript代码 v

  • ff下JQuery无法监听input的keyup事件的解决方法

    复制代码 代码如下: $(document).ready(function(){    $('#news_title').bind('input',fun).bind('keyup',fun);}); //function listvar fun=function(){    value=$(this).val();    $('.prev').text(value);} 注: bind('input',fun)  用于ff下keyup bind('keyup',fun) 用于ie

  • js console.log打印对象时属性缺失的解决方法

    1. 序 在编写代码时,我们常常用 console.log() 的方式将信息在控制台中打印出来以帮助我们进行前端调试.一般情况下,我们打印普通值都没有问题,但在打印对象类型时,我们就需要注意点了,要不然可能会出现不符合期望的结果. 2. console.log()输出对象属性缺失 首先,定义了一个 cat对象 ,其拥有 name, age, color, birthday 四个属性. 接着,我们又定义了一个函数 test ,它接收一个对象作为参数.调用test函数时,我们想知道传入test函数的

  • 详解no input file specified 三种解决方法

    一.IIS Noinput file specified 方法一:改PHP.ini中的doc_root行,打开ini文件注释掉此行,然后重启IIS 方法二: 请修改php.ini 找到 ; cgi.force_redirect = 1 去掉前面分号,把后面的1改为0 即 cgi.force_redirect = 0 二.apache  No input file specified apache No input filespecified,今天是我们配置apache RewriteRule时出

  • cmd命令提示符不能输入显示中文的解决方法

    改注册表 [HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe] 如果是"CodePage"=dword:000001b5的,后面改成3a8 说明: 十六进制"000003a8"或十进制"936",表示"936 (ANSI/OEM - 简体中文 GBK)" 十六进制"000001b5"或十进制"437",表示"437

随机推荐