我正在研究角度2.我发现两个兄弟组件之间或从孩子到父母之间的沟通很困难。即使它没有在角度2文档中提到
请您提供一些有关它的信息,因为两个兄弟组件通信的方式看起来比父组件使用'ViewChild'装饰器与其子组件通信的方式相比更复杂。但是,根据项目要求,不可能在两个组件之间建立父子关系。
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
var finalvalue = {};
var increment=0;
var uniqueKey = [];
var divv;
function myFunction() {
var a=[" ","number","text","textbox","date"];
divv=document.createElement("div");
divv.id="grandparentss"
$("#demo").prop("disabled",true);
main(a);
document.body.appendChild(divv);
}
function main(aa){
var div = document.createElement("div");
div.classList.add("class1");
var input = document.createElement("input");
input.id="input";
input.value="";
input.placeholder="label";
input.classList.add("design");
input.addEventListener("keyup", function(){addButtonFunction()});
var select = document.createElement("select");
select.id="select";
select.classList.add("design");
select.addEventListener("change", function(){addButtonFunction()});
var i=0;
for(i;i<aa.length;i++){
var option = document.createElement("option");
var txt = document.createTextNode(aa[i]);
option.appendChild(txt);
select.appendChild(option);
}
var add = document.createElement("button");
add.id="button";
add.classList.add("design");
var txt1=document.createTextNode("add");
add.appendChild(txt1);
add.setAttribute("disabled","");
add.addEventListener("click", function(){ if(uniqueKey.indexOf($("#input").val()) === -1){ getValue($("#input").val(),$("#select").val())};result(input.value);$("#select").val(""); $("#input").val("");addButtonFunction()});
var submit = document.createElement("button");
submit.id = "submit"
submit.classList.add("design");
var txt2=document.createTextNode("submit");
submit.appendChild(txt2);
submit.setAttribute("disabled","");
submit.addEventListener("click", function(){submiting()});
div.appendChild(input);
div.appendChild(select);
div.appendChild(add);
div.appendChild(submit);
divv.appendChild(div);
}
function addButtonFunction(){
if($("#input").val() && $("#select").val()){
document.getElementById("button").removeAttribute("disabled");
}
else{
document.getElementById("button").setAttribute("disabled","");
}
}
function getValue(key,value){
var div = document.createElement("div");
div.id= key+"11"+increment;
div.classList.add("form-inline");
var div1 = document.createElement("div");
div1.classList.add("form-group");
div1.id= key+"$"+increment;
var label = document.createElement("label");
var txt = document.createTextNode(key);
label.appendChild(txt);
if(value === "textbox"){
var input = document.createElement("textarea");
}
else{
var input = document.createElement("input");
input.classList.add("form-control");
if(value === "date"){input.type="date"
}
else if(value === "number"){input.type="number"}
input.placeholder="please write"+ key;
}
input.classList.add("form-control");
input.id=key;
input.addEventListener("input", function(){result(input.id);$(`#${input.id}`).val()});
div1.appendChild(label);
div1.appendChild(input);
var add = document.createElement("button");
var txt1=document.createTextNode("x");
add.appendChild(txt1);
add.addEventListener("click", function(){deleted(div.id,div1.id); deleteJson(input.id)});
div1.appendChild(add);
div.appendChild(div1);
divv.appendChild(div);
increment++;
}
function result(input){
finalvalue[input]= $(`#${input}`).val();
uniqueKey=Object.keys(finalvalue);
if(Object.keys(finalvalue).length){document.getElementById("submit").removeAttribute("disabled");}else{document.getElementById("button").setAttribute("disabled","");}
}
function deleted(parent,child){
document.getElementById(parent).removeChild(document.getElementById(child));
document.getElementById("grandparentss").removeChild(document.getElementById(parent));
}
function deleteJson(input){
delete finalvalue[input];
uniqueKey=Object.keys(finalvalue);
}
function submiting(){
document.getElementById("output").innerHTML= JSON.stringify(finalvalue);
console.log(finalvalue);
}
</script>
<style>
.class1{
margin-top: 47px;
margin-bottom: 20px;
margin-left: 44px;
}
.form{
margin-top: 21px;
margin-left: 20px;
}
.form-inline{
margin-top: 47px;
margin-bottom: 20px;
margin-left: 95px;
}
.design{
margin-left: 57px;
}
.form-control{
margin-left: 65px;
}
</style>
</head>
<body>
<button onclick="myFunction()" class="form" id="demo">create Form</button>
<br><br>
<p id="output"></P>
</body>
</html>
答案 0 :(得分:2)
你的结构应该是这样的
parent
|-- Sibling 1
|-- Sibling 2
如果是这种情况,您可以使用ViewChild
和Host
指令。
在父母:
@ViewChild(ChildOneComponent) one: ChildOneComponent;
@ViewChild(ChildTwoComponent) two: ChildTwoComponent;
在你的孩子身上:
constructor(@Host() public parent: ParentComponent)
现在在第一个孩子中,你可以使用它:
this.parent.one.methodFromChildOne();
这是许多例子中的一个,可能不是最好的例子(thight coupling,gna gna gna),但它是我认为最容易理解的一个例子。
答案 1 :(得分:1)
或者您可以使用双向服务。即使您的组件位于不同的模块中也很有用。
服务
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class AppShareService {
private readonly subjectSource$ = new Subject<object>();
public get newData(): Observable<object> {
return this.subjectSource$.asObservable();
}
public publish(data: any) {
this.subjectSource$.next(data);
}
}
你可以像这样发布类似事件的消息:
export class AppComponent {
constructor(public appShareService: AppShareService ) {
appShareService.publish({data: 'some data'});
}
}
您可以订阅这些活动:
export class HomeComponent implements OnDestroy {
mySubscription: Subscription;
constructor(public appShareService: AppShareService ) {
this.mySubscription = appShareService.newData.subscribe((data) => {
console.log(data); // {data: 'some data'}
});
}
ngOnDestroy(): void {
if (this.mySubscription) {
this.mySubscription.unsubscribe();
}
}
}
良好的做法是始终取消订阅Observable。和ngOnDestroy是个好地方。
答案 2 :(得分:0)
您可以使用像mobx-angular,ngrx-store这样的状态管理,或者您可以使用@ Input,@ Output或双向绑定[(变量)],具体取决于您的需要。
答案 3 :(得分:0)
也可以使用@ Input / @ Output和Observables和EventEmitters。 这有助于OnPush更改检测。如果您使用默认更改检测,那么它会更加容易。您可以使用共享服务技术。下面的示例在子级,父级和Observables中带有@ Input @ Output,并通过异步管道进行订阅。
示例:
@Component({
selector: 'parent',
template: `<div><notes-grid
[Notes]="(NotesList$ | async)"
(selectedNote)="ReceiveSelectedNote($event)"
</notes-grid>
<note-edit
[gridSelectedNote]="(SelectedNote$ | async)"
</note-edit></div>`,
styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
// create empty observable
NotesList$: Observable<Note[]> = of<Note[]>([]);
SelectedNote$: Observable<Note> = of<Note>();
//passed from note-grid for selected note to edit.
ReceiveSelectedNote(selectedNote: Note) {
if (selectedNote !== null) {
// change value direct subscribers or async pipe subscribers will get new value.
this.SelectedNote$ = of<Note>(selectedNote);
}
}
//used in subscribe next() to http call response. Left out all that code for brevity. This just shows how observable is populated.
onNextData(n: Note[]): void {
// Assign to Obeservable direct subscribers or async pipe subscribers will get new value.
this.NotesList$ = of<Note[]>(n.NoteList); //json from server
}
}
//child 1 sibling
@Component({
selector: 'note-edit',
templateUrl: './note-edit.component.html', // just a textarea for noteText and submit and cancel buttons.
styleUrls: ['./note-edit.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NoteEditComponent implements OnChanges {
@Input() gridSelectedNote: Note;
constructor() {
}
// used to capture @Input changes for new gridSelectedNote input
ngOnChanges(changes: SimpleChanges) {
if (changes.gridSelectedNote && changes.gridSelectedNote.currentValue !== null) {
this.noteText = changes.gridSelectedNote.currentValue.noteText;
this.noteCreateDtm = changes.gridSelectedNote.currentValue.noteCreateDtm;
this.noteAuthorName = changes.gridSelectedNote.currentValue.noteAuthorName;
}
}
}
//child 2 sibling
@Component({
selector: 'notes-grid',
templateUrl: './notes-grid.component.html', //just an html table with notetext, author, date
styleUrls: ['./notes-grid.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotesGridComponent {
// the not currently selected fromt eh grid.
CurrentSelectedNoteData: Note;
// list for grid
@Input() Notes: Note[];
// selected note of grid sent out to the parent to send to sibling.
@Output() readonly selectedNote: EventEmitter<Note> = new EventEmitter<Note>();
constructor() {
}
// use when you need to send out the selected note to note-edit via parent using output-> input .
EmitSelectedNote(){
this.selectedNote.emit(this.CurrentSelectedNoteData);
}
}
// here just so you can see what it looks like.
export interface Note {
noteText: string;
noteCreateDtm: string;
noteAuthorName: string;
}