Angular - 链接到 ViewChild 的函数执行两次
Angular - Function linked to ViewChild executing twice
我有三个组件,Nav、App、Form。在 Nav 组件中,我有一个函数可以更改 CSS 的位置,我可以从 Nav 和 App 组件(从 Form 组件获取触发器)调用此函数。我的问题是,当我从 NAV 组件调用函数时,它会触发两次。
我尝试删除 @ViewChild 并解决了问题,但无法按我想要的方式工作。我环顾四周,发现我应该使用 stopPropagation,但所有示例都有 event.StopPropgation,我不明白如何将其应用于我的函数。
Html 用于导航
<div class="navButton add" (click)="addFormToggle()">
<div class="bar vertical"></div>
<div class="bar horizontal"></div>
</div>
用于导航的 TS
When the button is clicked, it's function fires the CSS change function and another function to render the form Component.
import { Component, OnInit, Renderer2, ElementRef, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'menu-navigation',
templateUrl: './menu-navigation.component.html',
styleUrls: ['./menu-navigation.component.scss']
})
export class MenuNavigationComponent implements OnInit {
constructor(private renderer: Renderer2, private el: ElementRef, private ref: ChangeDetectorRef) { }
ngOnInit() { }
@Output() addFormToggleEvent = new EventEmitter<Event>();
addToggle;
addFormIconToggle() {
this.addToggle = !this.addToggle;
let vert = document.getElementsByClassName("vertical");
let horz = document.getElementsByClassName("horizontal");
if (this.addToggle) {
this.renderer.addClass(vert[0], "verticalToggle");
this.renderer.addClass(horz[0], "horizontalToggle");
}
else if (!this.addToggle) {
this.renderer.removeClass(vert[0], "verticalToggle");
this.renderer.removeClass(horz[0], "horizontalToggle");
}
}
addFormToggle() {
this.addFormToggleEvent.emit();
this.addFormIconToggle();
}
}
App.Component HTML
<div class="mainContainer">
<div class="header">
<menu-navigation (addFormToggleEvent)="childAddFormToggle()">
</menu-navigation>
</div>
<div class="newProjectForm" *ngIf="toggleForm">
<project-form (closeFormEvent)="childAddFormToggle()"></project-form>
</div>
</div>
App.component TS
import { MenuNavigationComponent } from './menu-navigation/menu-navigation.component';
import { Component, Input, ViewChild } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'journal';
toggleForm;
public toggleProjectForm: Event;
@Input() event: Event;
@ViewChild(MenuNavigationComponent, { static: false }) child: MenuNavigationComponent;
constructor() { }
childAddFormToggle() {
this.toggleForm = !this.toggleForm;
this.child.addFormIconToggle();
}
}
它很可能触发两次,因为您调用了两次:一次是在您的 childAddFormToggle()
方法中,一次是在 addFormToggle()
.
中调度事件时
但是从您的代码中我什至看不到这样做的必要性。你可以像这样重写它:
Html 用于导航
<div class="navButton add" (click)="toggleFormToggle()">
<!-- Add the class in HTML conditionally, angular will take care of applying the -->
<!-- class for you when 'addToggle' is set to true and removing it when set to false -->
<div class="bar vertical" [class.verticalToggle]="addToggle"></div>
<div class="bar horizontal" [class.horizontalToggle]="addToggle"></div>
</div>
导航 TS
import { Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
@Component({
selector: 'menu-navigation',
templateUrl: './menu-navigation.component.html',
styleUrls: ['./menu-navigation.component.scss']
})
export class MenuNavigationComponent implements OnInit {
// With this convention (@Input addToggle, @Output addToggleChange ) you can use two-way binding when using this component [(addToggle)]="someVariable"
@Input() addToggle:boolean = false;
@Output() addToggleChange = new EventEmitter<boolean>();
constructor() { }
ngOnInit() { }
// Only set the value in the internal state and bubble up the event, angular handles the class setting for us in the template
toggleFormToggle() {
this.addToggle = !this.addToggle;
this.addToggleChange.emit(this.addToggle);
}
}
app.component html
<div class="mainContainer">
<div class="header">
<!-- Just two-way bind the variable toggleForm so it will effective mirror the addToggle variable in menu-navigation -->
<menu-navigation [(addToggle)]="toggleForm">
</menu-navigation>
</div>
<div class="newProjectForm" *ngIf="toggleForm">
<!-- Change the variable, the two-way binding above will reflect it back into the menu-navigation component -->
<project-form (closeFormEvent)="toggleForm = !toggleForm"></project-form>
</div>
</div>
app.component ts
import { Component, Input, ViewChild } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'journal';
toggleForm:boolean = false;
@Input() event: Event;
constructor() { }
// You don't actually need a method doing anything for you
}
这里是工作 Stackblitz 展示我的方法。
我有三个组件,Nav、App、Form。在 Nav 组件中,我有一个函数可以更改 CSS 的位置,我可以从 Nav 和 App 组件(从 Form 组件获取触发器)调用此函数。我的问题是,当我从 NAV 组件调用函数时,它会触发两次。
我尝试删除 @ViewChild 并解决了问题,但无法按我想要的方式工作。我环顾四周,发现我应该使用 stopPropagation,但所有示例都有 event.StopPropgation,我不明白如何将其应用于我的函数。
Html 用于导航
<div class="navButton add" (click)="addFormToggle()">
<div class="bar vertical"></div>
<div class="bar horizontal"></div>
</div>
用于导航的 TS
When the button is clicked, it's function fires the CSS change function and another function to render the form Component.
import { Component, OnInit, Renderer2, ElementRef, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'menu-navigation',
templateUrl: './menu-navigation.component.html',
styleUrls: ['./menu-navigation.component.scss']
})
export class MenuNavigationComponent implements OnInit {
constructor(private renderer: Renderer2, private el: ElementRef, private ref: ChangeDetectorRef) { }
ngOnInit() { }
@Output() addFormToggleEvent = new EventEmitter<Event>();
addToggle;
addFormIconToggle() {
this.addToggle = !this.addToggle;
let vert = document.getElementsByClassName("vertical");
let horz = document.getElementsByClassName("horizontal");
if (this.addToggle) {
this.renderer.addClass(vert[0], "verticalToggle");
this.renderer.addClass(horz[0], "horizontalToggle");
}
else if (!this.addToggle) {
this.renderer.removeClass(vert[0], "verticalToggle");
this.renderer.removeClass(horz[0], "horizontalToggle");
}
}
addFormToggle() {
this.addFormToggleEvent.emit();
this.addFormIconToggle();
}
}
App.Component HTML
<div class="mainContainer">
<div class="header">
<menu-navigation (addFormToggleEvent)="childAddFormToggle()">
</menu-navigation>
</div>
<div class="newProjectForm" *ngIf="toggleForm">
<project-form (closeFormEvent)="childAddFormToggle()"></project-form>
</div>
</div>
App.component TS
import { MenuNavigationComponent } from './menu-navigation/menu-navigation.component';
import { Component, Input, ViewChild } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'journal';
toggleForm;
public toggleProjectForm: Event;
@Input() event: Event;
@ViewChild(MenuNavigationComponent, { static: false }) child: MenuNavigationComponent;
constructor() { }
childAddFormToggle() {
this.toggleForm = !this.toggleForm;
this.child.addFormIconToggle();
}
}
它很可能触发两次,因为您调用了两次:一次是在您的 childAddFormToggle()
方法中,一次是在 addFormToggle()
.
但是从您的代码中我什至看不到这样做的必要性。你可以像这样重写它:
Html 用于导航
<div class="navButton add" (click)="toggleFormToggle()">
<!-- Add the class in HTML conditionally, angular will take care of applying the -->
<!-- class for you when 'addToggle' is set to true and removing it when set to false -->
<div class="bar vertical" [class.verticalToggle]="addToggle"></div>
<div class="bar horizontal" [class.horizontalToggle]="addToggle"></div>
</div>
导航 TS
import { Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
@Component({
selector: 'menu-navigation',
templateUrl: './menu-navigation.component.html',
styleUrls: ['./menu-navigation.component.scss']
})
export class MenuNavigationComponent implements OnInit {
// With this convention (@Input addToggle, @Output addToggleChange ) you can use two-way binding when using this component [(addToggle)]="someVariable"
@Input() addToggle:boolean = false;
@Output() addToggleChange = new EventEmitter<boolean>();
constructor() { }
ngOnInit() { }
// Only set the value in the internal state and bubble up the event, angular handles the class setting for us in the template
toggleFormToggle() {
this.addToggle = !this.addToggle;
this.addToggleChange.emit(this.addToggle);
}
}
app.component html
<div class="mainContainer">
<div class="header">
<!-- Just two-way bind the variable toggleForm so it will effective mirror the addToggle variable in menu-navigation -->
<menu-navigation [(addToggle)]="toggleForm">
</menu-navigation>
</div>
<div class="newProjectForm" *ngIf="toggleForm">
<!-- Change the variable, the two-way binding above will reflect it back into the menu-navigation component -->
<project-form (closeFormEvent)="toggleForm = !toggleForm"></project-form>
</div>
</div>
app.component ts
import { Component, Input, ViewChild } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'journal';
toggleForm:boolean = false;
@Input() event: Event;
constructor() { }
// You don't actually need a method doing anything for you
}
这里是工作 Stackblitz 展示我的方法。