Home > Blockchain >  How to pass data from angluar component to angular layout component
How to pass data from angluar component to angular layout component

Time:04-14

I have a page where the contract has some basic information display in app-contract and I have a menu with different taps each tab contains some information about the contract shipping the components needed etc. I just click on a tab and it load contract details example the shipping information of the contract. However my issue is that when I do a search in the search tab the <app-contract></app-contract> fields are not updating for example the contract number remains the same. I am not sure what to use emitter viewchild etc to get the a <app-contract></app-contract> component to be up to date.

I have this page Contract page

Here is a visual representation of angular component structure

my structure

here is the relevant code for the contract search. Has you can see I have added a change: EventEmitter<Contract> = new EventEmitter<Contract>(); in the search component <app-contract-search></app-contract-search> I am not sure what to do after words with it.

@Component({
  selector: 'app-contract-search',
  templateUrl: './contract-search.component.html',
  styleUrls: ['./contract-search.component.css']
})
export class ContractSearchComponent implements OnInit {
  public contractNumber: string;
  public contract: Contract;
  public searchValue: string;


  @Output()
  change: EventEmitter<Contract> = new EventEmitter<Contract>();

  constructor(private route: ActivatedRoute, private router: Router, private toastr: ToastrService, private contractService: ContractService) {}

  ngOnInit(): void {
    // First get the contract id from the current route.
    const url = window.location.href;
    var parts = url.split('/', 6);

    this.contractNumber = parts[4];
    this.searchValue = this.contractNumber;

    console.log("Contract Id form url : "   this.contractNumber);

    this.GetContract(this.contractNumber);
  }


  GetContract(id: string) {
    this.contractService.getContractByContractNumber(Number(id)).subscribe(result => {
      this.contract = result;
      this.change.emit(this.contract);
    }, error => {
      console.log(error)
    });
  }

  search() {

    this.contractService.checkIfContractExists(this.searchValue).subscribe(contract => {
      if (contract) {
        console.log("contract "   this.searchValue   " found");
        this.GetContract(contract.contractNumber.toString());
        this.toastr.success("Success","The contract is being loaded!");
        this.router.navigate(['/contract', contract.contractNumber, 'search']);
      }
      else {
        console.log("contract "   this.searchValue   " NOT found");
        this.toastr.error("Error", "The contract number was not found!");
      }
    }, error => {
      console.log(error)
    });

  }
}

And then here in the <app-contract></app-contract> component is where I want to get the update contract information here. Is there a way I can listen to the event emitter here?

@Component({
  selector: 'app-contract',
  templateUrl: './contract-layout.component.html',
  styleUrls: ['./contract-layout.component.css']
})
export class ContractComponent implements OnInit {

  public contract: Contract;
  public contractId: number;

  constructor(private router: ActivatedRoute, private http: HttpClient,
              private contractService: ContractService ) { }


  ngOnInit(): void {
   
    // First get the product id from the current route.
    const routeParams = this.router.snapshot.paramMap;
    this.contractId = Number(routeParams.get('contractId'));

    console.log("Contract Id form url : "   this.contractId);

    this.GetContractByNumber(this.contractId);

  }

  GetContractByNumber(number: number) {
    this.contractService.getContractByContractNumber(number).subscribe(result => {
      this.contract = result;
    }, error => {
      console.log(error)
    });
  }
}

And here is the layout of my contract

<p *ngIf="!contract"><em>{{'HtmlElement.Loading' | translate}}</em></p>

<div *ngIf="contract">

  <h2>Contract details {{contract.contractNumber}}</h2>
  <form action="" id="GeneralForm" method="post">
     //Here is the form Form Contract details
    <div >
      <div >
        <br>
        <input id="btnSalvar"  type="submit" value="Update">
      </div>
    </div>
  </form>

  <div >
    <p >
      <app-contract-menu></app-contract-menu>
    </p>
    <div >
      <router-outlet></router-outlet>
    </div>
  </div>

</div>

CodePudding user response:

You can alter you app component ts to the following

@Component({
 selector: 'app-contract',
 templateUrl: './contract-layout.component.html',
 styleUrls: ['./contract-layout.component.css']
 })
 export class ContractComponent implements OnInit {

 public contract: Contract;
 public contractId: number;

 constructor(private router: ActivatedRoute, private http: HttpClient,
          private contractService: ContractService, private ChangeDetectorRef 
          changeDetector) { }


 ngOnInit(): void {

 // First get the product id from the current route.
  const routeParams = this.router.snapshot.paramMap;
  this.contractId = Number(routeParams.get('contractId'));

  console.log("Contract Id form url : "   this.contractId);

  this.GetContractByNumber(this.contractId);

}

GetContractByNumber(number: number) {
  this.contractService.getContractByContractNumber(number).subscribe(result => {
  this.contract = result;
  this.changeDetector.detectChanges();// this will force rerender your component 
}, error => {
  console.log(error)
});
}}

CodePudding user response:

I think you should do something like this:

in app-contract component

<app-contract-search (change)="GetContractByNumber($event.number)"><app-contract-search>

CodePudding user response:

Your component has been created once and since it is not getting any new inputs, nothing is forcing it to be rerendered

1- Move your App Contract component onInit event code to OnChanges event instead

2- Inject the contract as an input in your component, so when ever contract changes the onChanges event will be called

3- You are emitting the contract from search using event emitter therefore you can grab it in html and pass it to the app contract component as input

3- Your Html should look like that

<app-contract-search (change)= "contract=$event"></app-contract-search>
<app-contract [contract]="contract"></app-contract>

4- Your new App Component ts code

public [input] contract: Contract;

5- you don't need to do getContract method or any further subscriptions because you will be duplicating the logic

CodePudding user response:

I can propose another option. The idea is to use an Observable Subject in your ContractService.

So in your ContractService declare something like:

private _newContractSearched = new Subject<Contract>();
newContractSearched = this._newContractSearched.asObservable();

public triggerNewContractSearched(contract: Contract){
    this._newContractSearched.next(contract);
}

Then in ContractSearchComponent, every time you search:

this.contractService.triggerNewContractSearched(contract);

And finaly in ContractComponent just subscribe to that observable:

this.contractService.newContractSearched.subscribe(contract: Contract => {
    // Here you have the contract object
});

Maybe this is not the best solution, but should work.

  • Related