I'm trying to make a popup menu in Angular. I've got the parent (misvecinos) and child components (vecino-menu). I've designed it so whenever I click in a div (with info about an object Vecino), all data is assigned to vecinoMenu
(which is a base Vecino when the component is initialized). Once that vecinoMenu
has new data from the Vecino clicked, it is sent to the child component via @Input, where there is a form where I want to get the vecinoMenu
data and make one of the inputs already checked (eg. if the Vecino clicked had id=4, when it's sent to vecino-menu, the radio input with value =4 should be checked).
This is the code that implements what I've described:
Misvecinos.component.ts:
vecinoMenu : Vecino = {
nombre: "",
vecino_id: 0,
usuario_id: 0
};
@ViewChild(VecinoMenuComponent) menu : VecinoMenuComponent;
abreMenu(event, vecino : Vecino){
let coord = this.obtenPosicion(event);
if(vecino == null){
this.vecinoMenu = {
nombre: "",
vecino_id: 0,
usuario_id: 0
}
this.menu.abreMenu(event, coord);
}else{
if(this.vecinoMenu != null && this.vecinoMenu.vecino_id == vecino.vecino_id && this.menu.visibility == "visible"){
this.menu.cierraMenu();
}else{
//this.vecinoMenu = vecino;
// setTimeout(() => {
// this.menu.abreMenu(event, coord);
// }, 3000);
this.iniciaDatos(vecino).then(() => {
console.log("dsps de asignar vecino");
console.log(this.vecinoMenu);
this.menu.abreMenu(event, coord);
});
}
}
}
iniciaDatos(vecino : Vecino) : Promise<Vecino> {
let promise = new Promise<Vecino>((resolve, reject) => {
this.vecinoMenu = vecino;
if(this.vecinoMenu == vecino){
resolve(this.vecinoMenu);
}else{
reject();
}
});
return promise;
}
( Ignore obtenPosicion() and cierraMenu() )
Here there are a couple things to grasp:
- If the vecino sent when calling the function is null that means that I'm going to create one, but in order to avoid nullpointers, I set vecinoMenu to a new one (in case that the user already modified vecinoMenu by clicking in another Vecino before trying to create one). After the vecino is set, I open the menu (I'm guessing this part should have the same problem but I'm currently trying to debug it using the next section)
- Inside the first else, there is a few lines just to close the menu when clicked twice in the same Vecino, and if that's not the case, I set vecinoMenu with the value from Vecino and open the menu afterwards. If I do it like:
this.vecinoMenu = vecino;this.menu.abreMenu(event, coord);
when the menu is opened (next file), the value that the child component gets from the parent is the base one. Then I tried using setTimeout()
to check if the problem was a matter of time and indeed it is. If I do it like the commented part, it works, but setTimeout()
is a horrible solution, so I tried with promises. I made a function called iniciaDatos()
which basically does this.vecinoMenu = vecino
as a promise (or at least that's the intention, I'm still learning the whole Promise thing) in order to use .then()
afterwards, but this way I'm getting the same result as if I did nothing and the value that the child component gets it's the base one.
Vecino-menu.component.ts:
@Input("vecinoMenu") vecino : Vecino;
constructor(private _builder : FormBuilder) {
// if(this.vecino.vecino_id == 0){
this.vecinoForm = this._builder.group({
id: [1, Validators.required]
});
// }else{
// this.vecinoForm = this._builder.group({
// id: [2, Validators.required]
// });
// }
}
abreMenu(e : MouseEvent, coord : Array<number>){
this.visibility = "visible";
console.log(this.vecino);
this.x = coord[0]+"%";
this.y = coord[1]+"%";
e.stopPropagation();
}
Two points here:
- The section commented in the constructor is a test for selecting the default check input, if I uncomment that, I will get the following error:
ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'vecino_id' of undefined
, but I'm guessing that is just because it's getting the wrong value from the input
- Check the console.log in abreMenu where gets the value of vecino (vecinoMenu) after the menu is open)
I placed some console.logs and so far, when the vecinoMenu is setted in the parent (either with iniciaDatos() or manually like the comment) it has the correct value, but when the menu opens and checks the value sent through the @Input, it has the base value (unless I use setTimeout in which case works).
Since the problem apparently it's caused by the abreMenu()
function executing before the new vecinoMenu is setted, is there any way where I can execute the function after vecinoMenu has setted correctly?
question from:
https://stackoverflow.com/questions/65871619/var-assignment-before-executing-function-angular 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…