输入属性更改时,ngOnChanges不会触发

时间:2016-01-02 02:14:25

标签: angular

在改变angular2中的组件属性时,可以以编程方式触发角度变化检测吗?

@Component({
   selector: 'my-component', 
})
class MyComponent implements OnChanges {
   @Input() message: string;

   ngOnChanges(changeRecord) {
      for (var change in changeRecord) {
         console.log('changed: ' + change);
      }
   }

   doSomething() {
     // I want ngOnChanges to be called some time after I set the 
     // message. Currently it is only called if the host element
     // changes the value of [message] on the element.
     this.message = 'some important stuff';
   }
}

4 个答案:

答案 0 :(得分:4)

尝试手动调用更改检测或花费大量时间来解决此问题是一种过度的方法,为什么不创建一个函数来处理所需的突变并在 apply plugin: 'com.android.application' repositories { mavenCentral() } configurations { compile.exclude module: 'support-v4' } dependencies { compile 'com.google.android.gms:play-services-gcm:9.6.1' compile 'com.google.android.gms:play-services-maps:9.6.1' compile 'com.google.android.gms:play-services-vision:9.6.1' compile 'com.android.support:support-core-ui:24.2.1' compile 'com.android.support:support-compat:24.2.1' compile 'com.android.support:support-core-utils:24.2.1' compile 'net.hockeyapp.android:HockeySDK:4.0.1' compile 'com.googlecode.mp4parser:isoparser:1.0.6' } android { compileSdkVersion 24 buildToolsVersion '24.0.2' useLibrary 'org.apache.http.legacy' defaultConfig.applicationId = "org.telegram.messenger" sourceSets.main.jniLibs.srcDirs = ['./jni/'] externalNativeBuild { ndkBuild { path "/jni/Android.mk" } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } signingConfigs { debug { storeFile file("config/release.keystore") storePassword RELEASE_STORE_PASSWORD keyAlias RELEASE_KEY_ALIAS keyPassword RELEASE_KEY_PASSWORD } release { storeFile file("config/release.keystore") storePassword RELEASE_STORE_PASSWORD keyAlias RELEASE_KEY_ALIAS keyPassword RELEASE_KEY_PASSWORD } } buildTypes { debug { debuggable true jniDebuggable true signingConfig signingConfigs.debug applicationIdSuffix ".beta" } release { debuggable false jniDebuggable false signingConfig signingConfigs.release minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } foss { debuggable false jniDebuggable false signingConfig signingConfigs.release } } defaultConfig.versionCode = 851 sourceSets.debug { manifest.srcFile 'config/debug/AndroidManifest.xml' } sourceSets.release { manifest.srcFile 'config/release/AndroidManifest.xml' } sourceSets.foss { manifest.srcFile 'config/foss/AndroidManifest.xml' } productFlavors { x86 { ndk { abiFilter "x86" } versionCode = 2 } armv7 { ndk { abiFilter "armeabi-v7a" } versionCode = 1 } fat { versionCode = 3 } } applicationVariants.all { variant -> def abiVersion = variant.productFlavors.get(0).versionCode variant.mergedFlavor.versionCode = defaultConfig.versionCode * 10 + abiVersion; } defaultConfig { minSdkVersion 14 targetSdkVersion 24 versionName "3.13.1" externalNativeBuild { ndkBuild { arguments "NDK_APPLICATION_MK:=jni/Application.mk", "APP_PLATFORM:=android-14" abiFilters "armeabi-v7a", "x86" } } } } apply plugin: 'com.google.gms.google-services' ngOnChanges中调用它?类似的东西:

doSomething

因此@Component({ selector: 'my-component', }) class MyComponent implements OnChanges { @Input() message: string; viewMessage: string; ngOnChanges(changes: { [propertyName: string]: SimpleChange }) { for (let propName in changes) { if (propName === 'message') { this.updateView(this.message); } } } doSomething() { this.viewMessage = 'some important stuff'; } updateView(message: string) { this.viewMessage = message; } } 将是您正在使用和控制模板的属性。

答案 1 :(得分:2)

我遇到了同样的问题,这是一个简单但不太优雅的解决方法。传入另一个属性以强制触发ngOnChanges方法

<div poll-stat-chart [barData]="barData" [changeTrigger]="changeTrigger"></div>

在父组件类中,只要您想在子组件上手动触发ngOnChanges方法,只需修改&#34; changeTrigger&#34;属性

ParentComponent Class(poll-stat-chart是子组件)

     @Component({
        directives: [PollStatChartCmp],
        template: `
            <div poll-stat-chart [barData]="barData" [changeTrigger]="changeTrigger">
            </div>
            <button (click)="triggerChild()"></button>
        `
      }
    export class ParentComponent {
        changeTrigger = 1;
        barData = [{key:1, value:'1'}, {key:2, value'2'}];
        triggerChild() {
            this.barData[0].value = 'changedValue';

            //This will force fire ngOnChanges method of PollStatChartComponent
            this.changeTrigger ++ ;           
        }

    }

然后在子组件类中添加属性[changeTrigger]

    @Component({
        selector: '[poll-stat-chart]',
        inputs: ['barData', 'changeTrigger'],
        template: `
            <h4>This should be a BAR CHAR</h4>
        `
    })
    export class PollStatChartCmp {
        barData;
        changeTrigger;
        constructor(private elementRef: ElementRef) {
            this.render();

        }

        ngOnChanges(changes) {
            console.log('ngOnChanges fired');
            this.render();
        }

        render() { console.log('render fired');}

}

答案 2 :(得分:1)

似乎没有办法修改this上的输入绑定并在更改检测期间检测到它。但是,通过将整个组件包装在另一个组件中,可以修复我正在编写的单元测试

@ng.Component({
    selector: 'my-host-component',
    template: '<my-component [message]="message" (change)="change.emit($event)"></my-component>'
    directives: [MyComponent]
})
class MyHostComponent {
   message: string;
   change = new EventEmitter<any>();
}

然后我在MyHostComponent而不是MyComponent上运行了测试。

我已经提交issue to angular请求将方法添加到ComponentFixture,以便这样的测试更容易编写。

答案 3 :(得分:0)

不起作用的原因可以在源代码中找到。

https://github.com/angular/angular/blob/885f1af509eb7d9ee049349a2fe5565282fbfefb/packages/core/src/view/provider.ts

调用ngOnChanges的位置以及构建SimpleChanges结构的位置都与组件/指令代码紧密相关。

运行的不仅是“更改跟踪程序”,它可以查看设置的每个属性,因此ngOnChanges仅适用于父组件设置的绑定。

这是ngDoCheck出现的地方,可能还有KeyValueDiffers。

另请参阅:

https://netbasal.com/angular-the-ngstyle-directive-under-the-hood-2ed720fb9b61 https://juristr.com/blog/2016/04/angular2-change-detection/