72

我试图创建新组件,ResultComponent但是它的ngOnInit()方法被调用了两次,我不知道为什么会这样。在代码中,ResultComponent继承@Input自父组件mcq-component

这是代码:

父组件(MCQComponent)

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

@Component({
    selector: 'mcq-component',
    template: `
        <div *ngIf = 'isQuestionView'>
            .....
        </div>
        <result-comp *ngIf = '!isQuestionView' [answers] = 'ansArray'><result-comp>
    `,
    styles: [
        `
            ....
        `
    ],
    providers: [AppService],
    directives: [SelectableDirective, ResultComponent]
})
export class MCQComponent implements OnInit{
      private ansArray:Array<any> = [];
    ....
    constructor(private appService: AppService){}
    ....
}

子组件 (result-comp)

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

@Component({
    selector:'result-comp',
    template: `
        <h2>Result page:</h2>

    `
})
export class ResultComponent implements OnInit{
    @Input('answers') ans:Array<any>;

    ngOnInit(){
        console.log('Ans array: '+this.ans);
    }
}

运行时,console.log出现两次,第一次显示正确的数组,但第二次给出undefined。我一直无法弄清楚:为什么会ngOnInit被叫ResultComponent两次?

4

22 回答 22

47

为什么它被调用两次

现在,如果在检测组件的内容/视图子项的更改期间发生错误,ngOnInit 将被调用两次(见 DynamicChangeDetector)。这可能导致隐藏原始错误的后续错误。

此信息来自此github 问题


因此,您的错误似乎可能源于您的代码中与该组件相关的其他地方。

于 2016-08-05T11:13:19.250 回答
22

由于组件 html 错误,这发生在我身上。我忘记关闭主机组件中的选择器标签。所以我有这个<search><search>,而不是<search></search>- 注意语法错误。

与@dylan 答案相关,请检查您的组件 html 结构及其父级的结构。

于 2016-10-15T05:38:55.243 回答
19

如果您 platformBrowserDynamic().bootstrapModule(AppModule);在 app.module.ts 中使用过,请评论并尝试。我有同样的问题。我认为这有帮助

于 2018-01-03T06:00:31.653 回答
18

那么我的问题是我引导子组件的方式。在我的@NgModule装饰器的元数据对象中,我在引导属性中传递了“<strong>子组件”以及“<strong>父组件”。在引导属性中传递子组件正在重置我的子组件属性并使OnInit()被触发两次。

    @NgModule({
        imports: [ BrowserModule,FormsModule ], // to use two-way data binding ‘FormsModule’
        declarations: [ parentComponent,Child1,Child2], //all components
        //bootstrap: [parentComponent,Child1,Child2] // will lead to errors in binding Inputs in Child components
        bootstrap: [parentComponent] //use parent components only
    })
于 2016-12-15T16:18:08.783 回答
13

这可能是因为您将 设置AppComponent为基本路线

RouterModule.forRoot([
    { path: '', component: AppComponent }  // remove it
])

注意:AppComponent在默认情况下被调用angular所以不需要调用它

于 2018-04-25T09:14:41.813 回答
12

ngOnInit()在所有指令都被实例化后,钩子只发生一次。如果您有订阅ngOnInit()并且它没有取消订阅,那么如果订阅的数据发生更改,它将再次运行。

在下面的 Stackblitz 示例中,我在里面订阅ngOnInit()并控制台结果。它控制台两次,因为它加载一次并且数据更改并再次加载。

堆栈闪电战

于 2019-02-20T16:24:54.777 回答
11

把这个放在这里以防有人在这里结束。如果你的浏览器默认按钮类型是“提交”,NgOnInit 也可以被调用两次,比如如果你有以下,NextComponent 的 NgOnInit 将在 Chrome 中被调用两次:

<button class="btn btn-primary" (click)="navigateToNextComponent()">

要修复它,请设置类型:

<button class="btn btn-primary" type="button" (click)="navigateToNextComponent()">
于 2017-01-27T03:01:48.087 回答
3

就我而言,构建生成的每个文件 main-es5.js 和 main-es2015.js 的副本,删除所有 *-es5.js 副本并且它有效。

如果这也是您的情况,请不要删除重复项,只需添加这些属性

<script src="elements-es5.js" nomodule defer>
<script src="elements-es2015.js" type="module">
于 2020-12-25T08:13:56.100 回答
3

这发生在我身上是因为我<router-outlet>*ngFor. 它为循环中的每次迭代加载。

在这种情况下,解决方案是为每个出口设置一个唯一的名称,或者确保 DOM 中一次只有一个(可能带有一个*ngIf)。

于 2018-08-28T17:24:20.467 回答
3

只要有任何模板错误,就会发生这种情况。

在我的情况下,我使用了错误的模板引用并更正了我的问题..

于 2017-03-08T05:25:28.677 回答
2

如果您有多个这样的路由器插座,则可能会发生这种情况:

<ng-container *ngIf="condition">
  <div class="something">
    <router-outlet></router-outlet>
  </div>
</ng-container>
<ng-container *ngIf="!condition">
  <div class="something-else">
    <router-outlet></router-outlet>
  </div>
</ng-container>

请注意,如果您这样做,它也可能最终调用构造函数两次。构造函数被调用两次的事实证明该组件被创建了两次,这正是当组件位于*ngIf其条件从真到假再到真时发生的情况

一个有用的调试方法是创建一个名为 rnd 的类变量,如下所示:

rnd = Math.random()

并在构造函数和ngOnInit中console.log。如果值发生变化,那么您在第二次调用时就知道它是组件的一个新实例,并且它不是同一个实例被调用两次。虽然这不能解决您的问题,但它可能表明存在问题。

于 2021-04-30T08:53:18.323 回答
1

我自己也有类似的问题,我正在调用一个组件,然后通过路由器插座引用相同的组件。

<layout>
  <router-outlet></router-outlet>
</layout>

并且出线路径也指向了Layout。

于 2018-11-05T18:25:13.370 回答
1

When I stumbled over this issue in 2021, I had just recently migrated from an ancient ng4 to a more recent ng10. The app however was integrated in a monolithic Java backend via an index.jsp, which I did not properly migrate.
If you are in a similar position check your <script> tags. The *-es2015.js sources should have a type="module" while *-es5.js should have nomodule defer set, i.e.:

<script src=".../main-es5.js" nomodule defer></script>
<script src=".../main-es2015.js" type="module"></script>
于 2021-06-14T11:17:02.583 回答
1

就我而言,这是在 Component 同时实现OnChangesOnInit时发生的。尝试删除这些类之一。也可以使用ngAfterViewInit方法,在视图初始化后触发,保证调用一次。

于 2018-01-23T13:09:42.163 回答
1

对我来说,这是因为我在 Route 中注册了两次相同的组件:

{
        path: 'meal-services',
        children: [
          {
            path: '',
            component: InitTwiceComponent,
            canActivate: [AppVendorOpsGuard],
            data: { roleWhitelist: [UserRoles.Manage] }
          },
          {
            path: ':itemID',
            component: InitTwiceComponent,
            canActivate: [AppVendorOpsGuard],
            data: { roleWhitelist: [UserRoles.Manage] }
          }]
      },
}
于 2019-03-05T19:47:59.200 回答
0

这可能表明您错误地启动了该组件两次。这可能有几个原因:

  1. 您已导入AppRoutingModule超过 1 个模块。在您的应用程序中搜索它,并确保您仅将其包含在AppModule.

  2. 您已导入AppModule另一个模块。这也将AppRoutingModule按照第 1 点复制您的内容。

  3. 您的标记中有多个<router-outlet>。这可能会让人感到困惑,因为如果您有多个嵌套路由,您实际上将需要多个<router-outlet>. 但是,您需要检查每个具有子路由的路由是否只有 1 <router-outlet>。有时更容易复制父级中的每个嵌套组件,以查看实际输出将是什么。然后你可以看看你是否<router-outlet>错误地得到了额外的东西。

  4. 您的包装器组件在 AppRoutingModule 和子组件内指定。通常我会有一个包装器组件来处理标准布局的东西,如页眉、页脚、菜单等。然后,当我的AppRoutingModule. 有时也可以在另一个组件中使用这个包装器组件,从而复制它,因为它已经在AppRoutingModule. 这将导致额外的<router-outlet>.

于 2021-02-16T12:22:31.087 回答
0

这发生在我的子组件中。子组件用于显示何时使用 *ngIf 满足某个条件。我的解决方案是用 ngClass 替换 ngIf

在 HTML 中:

<component [ngClass]="isLoading?'hide':'show'>"

在 CSS 中:

.show{ display: block; }

.hide{ display: none; }
于 2020-05-19T07:51:39.630 回答
0

就我而言,我没有取消订阅我在 ngOnInit 中的所有订阅。我刚刚取消了ngOnDestroy中的所有订阅,这解决了我的问题。

于 2019-06-24T01:59:38.193 回答
0

这发生在我身上,因为我在锚标记中有 arribute href="#"。不要在锚标签中使用。如果您按照如下所示的角度代码使用 routerLink 并尽量避免在 appComponent.ts 中使用 ngInit(0 方法,这将得到解决

<a  class="nav-link" [routerLink]="['/login']"> Sign In. </a>
于 2021-07-09T16:03:56.893 回答
0

我的解决方案是ngIf在组件中使用以防止未定义的输入,在您的情况下是:

<result-comp *ngIf="answers" [answers]="answers"></result-comp>
于 2022-02-14T16:26:03.760 回答
0

就我而言,这是一个 html 错误导致 app.component.html 中出现这种情况,我有类似的东西

<icpm-la-test><icpm-la-test>

代替

<icpm-la-test></icpm-la-test>

有两个开始标签而不是结束标签。并且我在控制台上没有错误,并且功能工作正常,除了由于 ngOnInit 被调用两次,我在订阅中发生了多个 api 调用。

于 2020-06-05T09:37:39.840 回答
0

我把XComponent放在

引导程序:[AppComponent,XComponent ]

app.module.ts中。

删除XComponent ngOnInit 后仅触发一次。

于 2021-04-15T10:46:25.723 回答