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.
Here is a visual representation of angular component 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.