novita
novita

Reputation: 139

triggering ngOnInit of children components angular

I have a father component and several child components displayed as labels. I'm having trouble to control the behavior of the children ngOnInit as when changing from one label to another, ngOnInit of children won't trigger.

The father is app-management and its html is:

 <mat-tab-group dynamicHeight="true">
      <mat-tab label="Application Loader">
        <app-loader [deviceId]="deviceId"></app-loader>
      </mat-tab>
      <mat-tab label="Application Config">
        <app-config [deviceId]="deviceId"></app-config>
      </mat-tab>
      <mat-tab label="Docker">
        <app-docker [deviceId]="deviceId"></app-docker>
      </mat-tab>
      <mat-tab label="Application Logs">
        <app-logs [deviceId]="deviceId"></app-logs>
      </mat-tab>
      <mat-tab label="Ack Logs">
        <exec-logs [deviceId]="deviceId"></exec-logs>
      </mat-tab>
      <mat-tab label="Docker Logs">
        <docker-logs [deviceId]="deviceId"></docker-logs>
      </mat-tab>
    </mat-tab-group>

When introducing a console.log in ngOnint of app-docker doesn't work. I need to implemement a subscription in app-docker from the event in app-loader as when the application changes that change is displayed in app-docker, but, as ngOninit won't trigger when navigating to that label, I have no idea how to solve this.

The structure in VC it's aa follows:

>app-config
>app-docker
>app-loader
>app-logs
>docker-logs
>exec-logs
app-management.component.html
app-management.component.scss
app-management.component.ts
app-management.service.ts

I have tried this: on my app-docker.ts


import { Component, OnInit, Input, ChangeDetectorRef } from '@angular/core';
import { AppManagementService } from "../app-management.service";
import { SnackMessageService } from "app/main/common/services/snackMessage.service";
import { Subscription } from 'rxjs';


@Component({
  selector: "app-docker",
  templateUrl: "./app-docker.component.html",
  styleUrls: ["./app-docker.component.scss"],
})
export class AppDockerComponent implements OnInit {
  @Input() deviceId: string;
  configErrorMessage: string;
  
  dataContainer: any;
  
  application: any;
  private appChangeSub: Subscription;


  constructor(
    private appManagementService: AppManagementService,
    private snackMessageService: SnackMessageService, private cd: ChangeDetectorRef) {

 
      this.dataContainer = {
        containerInfo: [],
        dockerInfo: [],
        timestamp: ""  
    }

  

    this.application = {
      lastUpdate: new Date(0),
      registryId: "",
      applicationId: ""
  }
  }

  ngOnInit() {
      this.appManagementService.getDevicepplication(this.deviceId).then(response => {
        this.application = response
        if (this.application.applicationId !== "") {
          this.postContainerInfo();
        }
        this.appChangeSub = this.appManagementService.onSelectedApplicationsChanged.subscribe(app => {
          this.application.applicationId = app
        })
      }).catch(()=>  this.configErrorMessage = "Oops, could not get application info")

  }

public postContainerInfo() {
    this.appManagementService.postContainerInfo(this.deviceId).then(() => { this.getDockerContainerInfo() }).catch(() => this.configErrorMessage = "Oops, could not send container info message.")
  }

public getDockerContainerInfo() {
    this.appManagementService.getDockerContainerInfo(this.deviceId).then(response => {
      this.dataContainer = response
    }).catch(() => this.configErrorMessage = "Oops, could not get docker data.");
  }

the app-loader loads a new application, and every time this application changes I need to display these changes when going to app-docker label, without pressing any button. Is that possible?

my app-loader component .ts

import { Component, OnInit, Input, OnDestroy } from "@angular/core";
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
import { RegistryModel } from "app/main/registry/registry.model";
import { ApplicationModel } from "app/main/registry/application.model";
import { AppManagementService } from "../app-management.service";
import { SnackMessageService } from "app/main/common/services/snackMessage.service";

import { MatDialogRef, MatDialog } from "@angular/material";
import { FuseConfirmDialogComponent } from "@fuse/components/confirm-dialog/confirm-dialog.component";


@Component({
  selector: "app-loader",
  templateUrl: "./app-loader.component.html",
  styleUrls: ["./app-loader.component.scss"]
})
export class AppLoaderComponent implements OnInit, OnDestroy {
  @Input() deviceId: string;

 ngOnInit() {}

 public sendRegistryForm(): void {
    this.confirmDialogRef = this.matDialog.open(FuseConfirmDialogComponent, {
      disableClose: false
    });

    this.confirmDialogRef.componentInstance.confirmMessage = "Are you sure you want to send this application to the device?";

    this.confirmDialogRef.afterClosed()
      .subscribe(result => {
        if (result) {
          this.appManagementService.sendApplicationToDevice(this.deviceId, this.registryForm.value.registryId, this.registryForm.value.applicationId).then(() => {
            this.loaderErrorMessage = null;
            this.snackMessageService.sendMessage("Application sent");
          }).catch(() => this.loaderErrorMessage = "Oops, could not send the application to the device.");

        }
        this.confirmDialogRef = null;
      });
  }

}

In the appmanagementservice, I'm trying to implement an emitter with next each time a new application is loaded, but, I'm not sure this is right. The method postContainerInfo in app-docker is sending a message to an mqtt service, updating a ddbb, and then getting the info updated through getContainerInfo().

My app-management.service.ts:

import { Injectable } from "@angular/core";
import { RegistryModel } from "app/main/registry/registry.model";
import { BackEndCommunicationService } from "app/main/common/services/beComm.service";
import { BehaviorSubject, Subject } from "rxjs";

@Injectable({
  providedIn: "root"
})
export class AppManagementService {
  onSelectedApplicationsChanged: Subject<any>;

  constructor(private backEndCommunicationService: BackEndCommunicationService) {
    this.onSelectedApplicationsChanged = new Subject();
   }

 public getDevicepplication(deviceId: string): Promise<any> {
    return new Promise((resolve, reject) => {
      this.backEndCommunicationService.getResource("/devices/" + deviceId).then((response: any) => {
        this.onSelectedApplicationsChanged.next()
        resolve(response.response.application);
      }).catch(error => {
        console.log(error);
        reject("Error getting persistant size")
      })
    })
  }

public sendApplicationToDevice(deviceId: string, registryId: string, applicationId: string): Promise<void> {
    return new Promise((resolve, reject) => {
      const sendObject = {
        data: {
          registryId: registryId,
          applicationId: applicationId
        }
      };
      this.backEndCommunicationService.postResource("/devices/" + deviceId + "/application", sendObject).then(() => {
        resolve();
      }).catch(error => {
        console.log(error);
        reject("Error sending app to device");
      });
    });
  }

Upvotes: 1

Views: 1364

Answers (1)

mbojko
mbojko

Reputation: 14679

The ngOnInit won't run, because the DOM: the tab labels and the content, is built once, not rebuilt on every click.

You can use the selectedTabChange event to react to the tab change. What exactly are you trying to achieve?

Upvotes: 1

Related Questions