Angular 6 - Using Observable to trigger event between siblings











up vote
0
down vote

favorite












So I have a collection of divs in app-component filled with my app-cube components, and I have an array filled with GridProp objects in the parent component which's indexes represents each cell in the collection, meaning I create the content of each "cell" based on the content of array[i].



At array[i] I have an object with an Observable in it among other things like the content for cells. When I update something in cell i I want to update the siblings of cell [i-1] and [i+1].



I am trying to do this by having each app-cube subscribe to the observable in the matching object in the array. This way I should be able to simply send a value to the observer in the array at any index and have it trigger the subscribed components subscription handler, right?



The objects in the array are of this class



export class GridProp implements OnInit {
private terrain = new Terrain();
coord: Array<number>;
cont: {};

observer: Observer<string>;
observable: Observable<string> = new Observable((observer: Observer<string>) => {
this.observer = observer;
});
}


Then in the cube-component.ts



@Component({
selector: 'app-cube',
templateUrl: './cube.component.html',
styleUrls: ['./cube.component.css']
})
export class CubeComponent implements OnInit {
@Input() point; // Represents the relevant GridProp object

ngOnInit() {
this.point.observable.subscribe(this.handleCubeUpdate);
}

handleCubeUpdate() {
console.log('handling!');
this.updateWalls();
}

updateWalls() {
// Do stuff to the "walls" values used in this cube.component.html
}
toggleWalls() {
for (const direction in this.point.cont.terrain.walls) {
if (this.getSide(direction) && this.getSide(direction).cont.terrain.isBlock) {
this.point.cont.terrain.walls[direction] = false;
this.getSide(direction).observer.next(true);
} else {
this.point.cont.terrain.walls[direction] = true;
}
}
this.updateWalls();
}
}


In the parent component I distrubte the app-cube



<div class="grid-point-z" *ngFor="let z of y">
<div
class="grid-point"
attr.data-point="{{ z.coord }}"
[ngStyle]="{
'z-index': z.coord[2]
}">
<app-cube
[point]="z"
[coord]="z"
[level]="level"
(click)="clickPoint(z)"
(change)="onCubeChange($event)">
{{z}}
</app-cube>
</div>
</div>


It crashes with the error



ERROR TypeError: this.updateWalls is not a function
at SafeSubscriber.push../src/app/assets/cube/cube.component.ts.CubeComponent.handleCubeUpdate [as _next] (cube.component.ts:71)


So I guess it doesn't recognize this.handleCubeUpdate in the subscription in CubeComponent. Is there a work-around for this?










share|improve this question




















  • 1




    is that a function updateWalls? it seems to me that handleCubeUpdate is being called but look like handleCubeUpdate was calling updateWall. Also, IMO, I'd use Subject in your GridProp component. ``` private subject = new Subject<string>(); observable: Observable<string> = subject.asObservable(); ```
    – dK-
    Nov 15 at 12:38












  • Wops, thank you. I edited in the updateWalls function call. It is inside the handleCubeUpdate function. I changed the code as you described but the issue is the same. handleCubeUpdate is able to console.log "handling!", but the this.updateWalls(); is "is not a function" in the crash log
    – NachoDawg
    Nov 15 at 12:47










  • Where the updateWalls is declared ? And as @dK say, it is better to use Subject or BehaviorSubject.
    – User.Anonymous
    Nov 15 at 12:47










  • And observable.subscribe declare the object which you subscribe observable.subscribe(p => console.log(p); }. And without next, your observable is useless.
    – User.Anonymous
    Nov 15 at 12:51










  • The updateWalls is declared in cube.component.ts. It handles valued used in the HTML file. The .next() is also called later in the cube.component.ts, i'll add it to the post for clarity
    – NachoDawg
    Nov 15 at 12:52















up vote
0
down vote

favorite












So I have a collection of divs in app-component filled with my app-cube components, and I have an array filled with GridProp objects in the parent component which's indexes represents each cell in the collection, meaning I create the content of each "cell" based on the content of array[i].



At array[i] I have an object with an Observable in it among other things like the content for cells. When I update something in cell i I want to update the siblings of cell [i-1] and [i+1].



I am trying to do this by having each app-cube subscribe to the observable in the matching object in the array. This way I should be able to simply send a value to the observer in the array at any index and have it trigger the subscribed components subscription handler, right?



The objects in the array are of this class



export class GridProp implements OnInit {
private terrain = new Terrain();
coord: Array<number>;
cont: {};

observer: Observer<string>;
observable: Observable<string> = new Observable((observer: Observer<string>) => {
this.observer = observer;
});
}


Then in the cube-component.ts



@Component({
selector: 'app-cube',
templateUrl: './cube.component.html',
styleUrls: ['./cube.component.css']
})
export class CubeComponent implements OnInit {
@Input() point; // Represents the relevant GridProp object

ngOnInit() {
this.point.observable.subscribe(this.handleCubeUpdate);
}

handleCubeUpdate() {
console.log('handling!');
this.updateWalls();
}

updateWalls() {
// Do stuff to the "walls" values used in this cube.component.html
}
toggleWalls() {
for (const direction in this.point.cont.terrain.walls) {
if (this.getSide(direction) && this.getSide(direction).cont.terrain.isBlock) {
this.point.cont.terrain.walls[direction] = false;
this.getSide(direction).observer.next(true);
} else {
this.point.cont.terrain.walls[direction] = true;
}
}
this.updateWalls();
}
}


In the parent component I distrubte the app-cube



<div class="grid-point-z" *ngFor="let z of y">
<div
class="grid-point"
attr.data-point="{{ z.coord }}"
[ngStyle]="{
'z-index': z.coord[2]
}">
<app-cube
[point]="z"
[coord]="z"
[level]="level"
(click)="clickPoint(z)"
(change)="onCubeChange($event)">
{{z}}
</app-cube>
</div>
</div>


It crashes with the error



ERROR TypeError: this.updateWalls is not a function
at SafeSubscriber.push../src/app/assets/cube/cube.component.ts.CubeComponent.handleCubeUpdate [as _next] (cube.component.ts:71)


So I guess it doesn't recognize this.handleCubeUpdate in the subscription in CubeComponent. Is there a work-around for this?










share|improve this question




















  • 1




    is that a function updateWalls? it seems to me that handleCubeUpdate is being called but look like handleCubeUpdate was calling updateWall. Also, IMO, I'd use Subject in your GridProp component. ``` private subject = new Subject<string>(); observable: Observable<string> = subject.asObservable(); ```
    – dK-
    Nov 15 at 12:38












  • Wops, thank you. I edited in the updateWalls function call. It is inside the handleCubeUpdate function. I changed the code as you described but the issue is the same. handleCubeUpdate is able to console.log "handling!", but the this.updateWalls(); is "is not a function" in the crash log
    – NachoDawg
    Nov 15 at 12:47










  • Where the updateWalls is declared ? And as @dK say, it is better to use Subject or BehaviorSubject.
    – User.Anonymous
    Nov 15 at 12:47










  • And observable.subscribe declare the object which you subscribe observable.subscribe(p => console.log(p); }. And without next, your observable is useless.
    – User.Anonymous
    Nov 15 at 12:51










  • The updateWalls is declared in cube.component.ts. It handles valued used in the HTML file. The .next() is also called later in the cube.component.ts, i'll add it to the post for clarity
    – NachoDawg
    Nov 15 at 12:52













up vote
0
down vote

favorite









up vote
0
down vote

favorite











So I have a collection of divs in app-component filled with my app-cube components, and I have an array filled with GridProp objects in the parent component which's indexes represents each cell in the collection, meaning I create the content of each "cell" based on the content of array[i].



At array[i] I have an object with an Observable in it among other things like the content for cells. When I update something in cell i I want to update the siblings of cell [i-1] and [i+1].



I am trying to do this by having each app-cube subscribe to the observable in the matching object in the array. This way I should be able to simply send a value to the observer in the array at any index and have it trigger the subscribed components subscription handler, right?



The objects in the array are of this class



export class GridProp implements OnInit {
private terrain = new Terrain();
coord: Array<number>;
cont: {};

observer: Observer<string>;
observable: Observable<string> = new Observable((observer: Observer<string>) => {
this.observer = observer;
});
}


Then in the cube-component.ts



@Component({
selector: 'app-cube',
templateUrl: './cube.component.html',
styleUrls: ['./cube.component.css']
})
export class CubeComponent implements OnInit {
@Input() point; // Represents the relevant GridProp object

ngOnInit() {
this.point.observable.subscribe(this.handleCubeUpdate);
}

handleCubeUpdate() {
console.log('handling!');
this.updateWalls();
}

updateWalls() {
// Do stuff to the "walls" values used in this cube.component.html
}
toggleWalls() {
for (const direction in this.point.cont.terrain.walls) {
if (this.getSide(direction) && this.getSide(direction).cont.terrain.isBlock) {
this.point.cont.terrain.walls[direction] = false;
this.getSide(direction).observer.next(true);
} else {
this.point.cont.terrain.walls[direction] = true;
}
}
this.updateWalls();
}
}


In the parent component I distrubte the app-cube



<div class="grid-point-z" *ngFor="let z of y">
<div
class="grid-point"
attr.data-point="{{ z.coord }}"
[ngStyle]="{
'z-index': z.coord[2]
}">
<app-cube
[point]="z"
[coord]="z"
[level]="level"
(click)="clickPoint(z)"
(change)="onCubeChange($event)">
{{z}}
</app-cube>
</div>
</div>


It crashes with the error



ERROR TypeError: this.updateWalls is not a function
at SafeSubscriber.push../src/app/assets/cube/cube.component.ts.CubeComponent.handleCubeUpdate [as _next] (cube.component.ts:71)


So I guess it doesn't recognize this.handleCubeUpdate in the subscription in CubeComponent. Is there a work-around for this?










share|improve this question















So I have a collection of divs in app-component filled with my app-cube components, and I have an array filled with GridProp objects in the parent component which's indexes represents each cell in the collection, meaning I create the content of each "cell" based on the content of array[i].



At array[i] I have an object with an Observable in it among other things like the content for cells. When I update something in cell i I want to update the siblings of cell [i-1] and [i+1].



I am trying to do this by having each app-cube subscribe to the observable in the matching object in the array. This way I should be able to simply send a value to the observer in the array at any index and have it trigger the subscribed components subscription handler, right?



The objects in the array are of this class



export class GridProp implements OnInit {
private terrain = new Terrain();
coord: Array<number>;
cont: {};

observer: Observer<string>;
observable: Observable<string> = new Observable((observer: Observer<string>) => {
this.observer = observer;
});
}


Then in the cube-component.ts



@Component({
selector: 'app-cube',
templateUrl: './cube.component.html',
styleUrls: ['./cube.component.css']
})
export class CubeComponent implements OnInit {
@Input() point; // Represents the relevant GridProp object

ngOnInit() {
this.point.observable.subscribe(this.handleCubeUpdate);
}

handleCubeUpdate() {
console.log('handling!');
this.updateWalls();
}

updateWalls() {
// Do stuff to the "walls" values used in this cube.component.html
}
toggleWalls() {
for (const direction in this.point.cont.terrain.walls) {
if (this.getSide(direction) && this.getSide(direction).cont.terrain.isBlock) {
this.point.cont.terrain.walls[direction] = false;
this.getSide(direction).observer.next(true);
} else {
this.point.cont.terrain.walls[direction] = true;
}
}
this.updateWalls();
}
}


In the parent component I distrubte the app-cube



<div class="grid-point-z" *ngFor="let z of y">
<div
class="grid-point"
attr.data-point="{{ z.coord }}"
[ngStyle]="{
'z-index': z.coord[2]
}">
<app-cube
[point]="z"
[coord]="z"
[level]="level"
(click)="clickPoint(z)"
(change)="onCubeChange($event)">
{{z}}
</app-cube>
</div>
</div>


It crashes with the error



ERROR TypeError: this.updateWalls is not a function
at SafeSubscriber.push../src/app/assets/cube/cube.component.ts.CubeComponent.handleCubeUpdate [as _next] (cube.component.ts:71)


So I guess it doesn't recognize this.handleCubeUpdate in the subscription in CubeComponent. Is there a work-around for this?







angular rxjs






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 at 12:54









Pac0

7,35922544




7,35922544










asked Nov 15 at 11:57









NachoDawg

1,306717




1,306717








  • 1




    is that a function updateWalls? it seems to me that handleCubeUpdate is being called but look like handleCubeUpdate was calling updateWall. Also, IMO, I'd use Subject in your GridProp component. ``` private subject = new Subject<string>(); observable: Observable<string> = subject.asObservable(); ```
    – dK-
    Nov 15 at 12:38












  • Wops, thank you. I edited in the updateWalls function call. It is inside the handleCubeUpdate function. I changed the code as you described but the issue is the same. handleCubeUpdate is able to console.log "handling!", but the this.updateWalls(); is "is not a function" in the crash log
    – NachoDawg
    Nov 15 at 12:47










  • Where the updateWalls is declared ? And as @dK say, it is better to use Subject or BehaviorSubject.
    – User.Anonymous
    Nov 15 at 12:47










  • And observable.subscribe declare the object which you subscribe observable.subscribe(p => console.log(p); }. And without next, your observable is useless.
    – User.Anonymous
    Nov 15 at 12:51










  • The updateWalls is declared in cube.component.ts. It handles valued used in the HTML file. The .next() is also called later in the cube.component.ts, i'll add it to the post for clarity
    – NachoDawg
    Nov 15 at 12:52














  • 1




    is that a function updateWalls? it seems to me that handleCubeUpdate is being called but look like handleCubeUpdate was calling updateWall. Also, IMO, I'd use Subject in your GridProp component. ``` private subject = new Subject<string>(); observable: Observable<string> = subject.asObservable(); ```
    – dK-
    Nov 15 at 12:38












  • Wops, thank you. I edited in the updateWalls function call. It is inside the handleCubeUpdate function. I changed the code as you described but the issue is the same. handleCubeUpdate is able to console.log "handling!", but the this.updateWalls(); is "is not a function" in the crash log
    – NachoDawg
    Nov 15 at 12:47










  • Where the updateWalls is declared ? And as @dK say, it is better to use Subject or BehaviorSubject.
    – User.Anonymous
    Nov 15 at 12:47










  • And observable.subscribe declare the object which you subscribe observable.subscribe(p => console.log(p); }. And without next, your observable is useless.
    – User.Anonymous
    Nov 15 at 12:51










  • The updateWalls is declared in cube.component.ts. It handles valued used in the HTML file. The .next() is also called later in the cube.component.ts, i'll add it to the post for clarity
    – NachoDawg
    Nov 15 at 12:52








1




1




is that a function updateWalls? it seems to me that handleCubeUpdate is being called but look like handleCubeUpdate was calling updateWall. Also, IMO, I'd use Subject in your GridProp component. ``` private subject = new Subject<string>(); observable: Observable<string> = subject.asObservable(); ```
– dK-
Nov 15 at 12:38






is that a function updateWalls? it seems to me that handleCubeUpdate is being called but look like handleCubeUpdate was calling updateWall. Also, IMO, I'd use Subject in your GridProp component. ``` private subject = new Subject<string>(); observable: Observable<string> = subject.asObservable(); ```
– dK-
Nov 15 at 12:38














Wops, thank you. I edited in the updateWalls function call. It is inside the handleCubeUpdate function. I changed the code as you described but the issue is the same. handleCubeUpdate is able to console.log "handling!", but the this.updateWalls(); is "is not a function" in the crash log
– NachoDawg
Nov 15 at 12:47




Wops, thank you. I edited in the updateWalls function call. It is inside the handleCubeUpdate function. I changed the code as you described but the issue is the same. handleCubeUpdate is able to console.log "handling!", but the this.updateWalls(); is "is not a function" in the crash log
– NachoDawg
Nov 15 at 12:47












Where the updateWalls is declared ? And as @dK say, it is better to use Subject or BehaviorSubject.
– User.Anonymous
Nov 15 at 12:47




Where the updateWalls is declared ? And as @dK say, it is better to use Subject or BehaviorSubject.
– User.Anonymous
Nov 15 at 12:47












And observable.subscribe declare the object which you subscribe observable.subscribe(p => console.log(p); }. And without next, your observable is useless.
– User.Anonymous
Nov 15 at 12:51




And observable.subscribe declare the object which you subscribe observable.subscribe(p => console.log(p); }. And without next, your observable is useless.
– User.Anonymous
Nov 15 at 12:51












The updateWalls is declared in cube.component.ts. It handles valued used in the HTML file. The .next() is also called later in the cube.component.ts, i'll add it to the post for clarity
– NachoDawg
Nov 15 at 12:52




The updateWalls is declared in cube.component.ts. It handles valued used in the HTML file. The .next() is also called later in the cube.component.ts, i'll add it to the post for clarity
– NachoDawg
Nov 15 at 12:52












3 Answers
3






active

oldest

votes

















up vote
1
down vote



accepted










From my point of view here we have kind of design problem.



In Angular, components can interact with each other using their @Input() and @Output() properties(Input - to be aware about changes from parent component and update view, Output - to notify others about changes inside).



So better to add to your CubeComponent output event somethingChanged and emit this event when, as you said, you update something.



export class CubeComponent implements OnInit {
@Input() point; // Represents the relevant GridProp object
@Output() somethingChanged = new EventEmitter<GridProp>();

ngOnInit() {
}

notifyOthersComponentAboutUpdate() {
let id = this.point; // You can emit point or some id, to identify it later in parent component
this.somethingChanged.emit(id);
}
}


In you parent component(app-component) which contains array of app-cube components create a method updateSiblings(idOfComponentWhichWasUpdated) and call it from app-cube component



<div class="grid-point-z" *ngFor="let z of y">
<div
class="grid-point"
attr.data-point="{{ z.coord }}"
[ngStyle]="{
'z-index': z.coord[2]
}">
<app-cube
[point]="z"
[coord]="z"
[level]="level"
(somethingChanged)="updateSiblings($event)">
{{z}}
</app-cube>
</div>
</div>


And in that updateSiblings method your have access to your y array(*ngFor="let z of y") which contains all data for app-cube components(y: GridProp).

You have id of component which was updated, so you can find it in array y and you can find his siblings and update their data as well. Angular will automatically detect changes in that y array and your siblings will be updated on UI level.






share|improve this answer























  • I ended up using your solution. I kept an observable in the GridProp where i manage the rendering of the "walls", and used the parent component to trigger the observable of any sibling of a clicked point including 'this' point, leaving each context intact. Thanks!
    – NachoDawg
    Nov 15 at 14:53










  • Nice to hear that. Happy to help @NachoDawg
    – Yury Polubinsky
    Nov 15 at 15:10




















up vote
2
down vote













Now it make more sense to me that I could try to answer it here.
Hopefully I could articulate this properly :).



So, when you pass in a function reference in your subscribe, this in handleCubeUpdate has a different context.
You can change your function implementation to arrow function.



handleCubeUpdate = () => {
this.updateWalls();
}


additionally, if your updateWalls is calling another function, then you should change that updateWalls function arrow function.






share|improve this answer





















  • Accepted answer. This allows me to reach the siblings by triggering their corresponding observables like i wanted to, thanks.
    – NachoDawg
    Nov 15 at 13:13










  • Actually it doesn't entirely work like i thought. While I manage to trigger the observable of a sibling, 'this' refers to the original point. I changed all the functions touched by handleCubeUpdate to arrow functions, but they always seem to refer to the point that triggered the sibling to update the walls
    – NachoDawg
    Nov 15 at 14:04


















up vote
0
down vote













Have you considered using a REDUX architecture in Angular?



Here's a good tutorial on how it works and the benefits. I have used the exact same tutorial to learn about it and implement.



You could then keep that array in your store and dispatch actions to change thing. Each action could contain the logic to update itself + the two items surrounding it.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53319005%2fangular-6-using-observable-to-trigger-event-between-siblings%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted










    From my point of view here we have kind of design problem.



    In Angular, components can interact with each other using their @Input() and @Output() properties(Input - to be aware about changes from parent component and update view, Output - to notify others about changes inside).



    So better to add to your CubeComponent output event somethingChanged and emit this event when, as you said, you update something.



    export class CubeComponent implements OnInit {
    @Input() point; // Represents the relevant GridProp object
    @Output() somethingChanged = new EventEmitter<GridProp>();

    ngOnInit() {
    }

    notifyOthersComponentAboutUpdate() {
    let id = this.point; // You can emit point or some id, to identify it later in parent component
    this.somethingChanged.emit(id);
    }
    }


    In you parent component(app-component) which contains array of app-cube components create a method updateSiblings(idOfComponentWhichWasUpdated) and call it from app-cube component



    <div class="grid-point-z" *ngFor="let z of y">
    <div
    class="grid-point"
    attr.data-point="{{ z.coord }}"
    [ngStyle]="{
    'z-index': z.coord[2]
    }">
    <app-cube
    [point]="z"
    [coord]="z"
    [level]="level"
    (somethingChanged)="updateSiblings($event)">
    {{z}}
    </app-cube>
    </div>
    </div>


    And in that updateSiblings method your have access to your y array(*ngFor="let z of y") which contains all data for app-cube components(y: GridProp).

    You have id of component which was updated, so you can find it in array y and you can find his siblings and update their data as well. Angular will automatically detect changes in that y array and your siblings will be updated on UI level.






    share|improve this answer























    • I ended up using your solution. I kept an observable in the GridProp where i manage the rendering of the "walls", and used the parent component to trigger the observable of any sibling of a clicked point including 'this' point, leaving each context intact. Thanks!
      – NachoDawg
      Nov 15 at 14:53










    • Nice to hear that. Happy to help @NachoDawg
      – Yury Polubinsky
      Nov 15 at 15:10

















    up vote
    1
    down vote



    accepted










    From my point of view here we have kind of design problem.



    In Angular, components can interact with each other using their @Input() and @Output() properties(Input - to be aware about changes from parent component and update view, Output - to notify others about changes inside).



    So better to add to your CubeComponent output event somethingChanged and emit this event when, as you said, you update something.



    export class CubeComponent implements OnInit {
    @Input() point; // Represents the relevant GridProp object
    @Output() somethingChanged = new EventEmitter<GridProp>();

    ngOnInit() {
    }

    notifyOthersComponentAboutUpdate() {
    let id = this.point; // You can emit point or some id, to identify it later in parent component
    this.somethingChanged.emit(id);
    }
    }


    In you parent component(app-component) which contains array of app-cube components create a method updateSiblings(idOfComponentWhichWasUpdated) and call it from app-cube component



    <div class="grid-point-z" *ngFor="let z of y">
    <div
    class="grid-point"
    attr.data-point="{{ z.coord }}"
    [ngStyle]="{
    'z-index': z.coord[2]
    }">
    <app-cube
    [point]="z"
    [coord]="z"
    [level]="level"
    (somethingChanged)="updateSiblings($event)">
    {{z}}
    </app-cube>
    </div>
    </div>


    And in that updateSiblings method your have access to your y array(*ngFor="let z of y") which contains all data for app-cube components(y: GridProp).

    You have id of component which was updated, so you can find it in array y and you can find his siblings and update their data as well. Angular will automatically detect changes in that y array and your siblings will be updated on UI level.






    share|improve this answer























    • I ended up using your solution. I kept an observable in the GridProp where i manage the rendering of the "walls", and used the parent component to trigger the observable of any sibling of a clicked point including 'this' point, leaving each context intact. Thanks!
      – NachoDawg
      Nov 15 at 14:53










    • Nice to hear that. Happy to help @NachoDawg
      – Yury Polubinsky
      Nov 15 at 15:10















    up vote
    1
    down vote



    accepted







    up vote
    1
    down vote



    accepted






    From my point of view here we have kind of design problem.



    In Angular, components can interact with each other using their @Input() and @Output() properties(Input - to be aware about changes from parent component and update view, Output - to notify others about changes inside).



    So better to add to your CubeComponent output event somethingChanged and emit this event when, as you said, you update something.



    export class CubeComponent implements OnInit {
    @Input() point; // Represents the relevant GridProp object
    @Output() somethingChanged = new EventEmitter<GridProp>();

    ngOnInit() {
    }

    notifyOthersComponentAboutUpdate() {
    let id = this.point; // You can emit point or some id, to identify it later in parent component
    this.somethingChanged.emit(id);
    }
    }


    In you parent component(app-component) which contains array of app-cube components create a method updateSiblings(idOfComponentWhichWasUpdated) and call it from app-cube component



    <div class="grid-point-z" *ngFor="let z of y">
    <div
    class="grid-point"
    attr.data-point="{{ z.coord }}"
    [ngStyle]="{
    'z-index': z.coord[2]
    }">
    <app-cube
    [point]="z"
    [coord]="z"
    [level]="level"
    (somethingChanged)="updateSiblings($event)">
    {{z}}
    </app-cube>
    </div>
    </div>


    And in that updateSiblings method your have access to your y array(*ngFor="let z of y") which contains all data for app-cube components(y: GridProp).

    You have id of component which was updated, so you can find it in array y and you can find his siblings and update their data as well. Angular will automatically detect changes in that y array and your siblings will be updated on UI level.






    share|improve this answer














    From my point of view here we have kind of design problem.



    In Angular, components can interact with each other using their @Input() and @Output() properties(Input - to be aware about changes from parent component and update view, Output - to notify others about changes inside).



    So better to add to your CubeComponent output event somethingChanged and emit this event when, as you said, you update something.



    export class CubeComponent implements OnInit {
    @Input() point; // Represents the relevant GridProp object
    @Output() somethingChanged = new EventEmitter<GridProp>();

    ngOnInit() {
    }

    notifyOthersComponentAboutUpdate() {
    let id = this.point; // You can emit point or some id, to identify it later in parent component
    this.somethingChanged.emit(id);
    }
    }


    In you parent component(app-component) which contains array of app-cube components create a method updateSiblings(idOfComponentWhichWasUpdated) and call it from app-cube component



    <div class="grid-point-z" *ngFor="let z of y">
    <div
    class="grid-point"
    attr.data-point="{{ z.coord }}"
    [ngStyle]="{
    'z-index': z.coord[2]
    }">
    <app-cube
    [point]="z"
    [coord]="z"
    [level]="level"
    (somethingChanged)="updateSiblings($event)">
    {{z}}
    </app-cube>
    </div>
    </div>


    And in that updateSiblings method your have access to your y array(*ngFor="let z of y") which contains all data for app-cube components(y: GridProp).

    You have id of component which was updated, so you can find it in array y and you can find his siblings and update their data as well. Angular will automatically detect changes in that y array and your siblings will be updated on UI level.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 15 at 15:13

























    answered Nov 15 at 13:31









    Yury Polubinsky

    908




    908












    • I ended up using your solution. I kept an observable in the GridProp where i manage the rendering of the "walls", and used the parent component to trigger the observable of any sibling of a clicked point including 'this' point, leaving each context intact. Thanks!
      – NachoDawg
      Nov 15 at 14:53










    • Nice to hear that. Happy to help @NachoDawg
      – Yury Polubinsky
      Nov 15 at 15:10




















    • I ended up using your solution. I kept an observable in the GridProp where i manage the rendering of the "walls", and used the parent component to trigger the observable of any sibling of a clicked point including 'this' point, leaving each context intact. Thanks!
      – NachoDawg
      Nov 15 at 14:53










    • Nice to hear that. Happy to help @NachoDawg
      – Yury Polubinsky
      Nov 15 at 15:10


















    I ended up using your solution. I kept an observable in the GridProp where i manage the rendering of the "walls", and used the parent component to trigger the observable of any sibling of a clicked point including 'this' point, leaving each context intact. Thanks!
    – NachoDawg
    Nov 15 at 14:53




    I ended up using your solution. I kept an observable in the GridProp where i manage the rendering of the "walls", and used the parent component to trigger the observable of any sibling of a clicked point including 'this' point, leaving each context intact. Thanks!
    – NachoDawg
    Nov 15 at 14:53












    Nice to hear that. Happy to help @NachoDawg
    – Yury Polubinsky
    Nov 15 at 15:10






    Nice to hear that. Happy to help @NachoDawg
    – Yury Polubinsky
    Nov 15 at 15:10














    up vote
    2
    down vote













    Now it make more sense to me that I could try to answer it here.
    Hopefully I could articulate this properly :).



    So, when you pass in a function reference in your subscribe, this in handleCubeUpdate has a different context.
    You can change your function implementation to arrow function.



    handleCubeUpdate = () => {
    this.updateWalls();
    }


    additionally, if your updateWalls is calling another function, then you should change that updateWalls function arrow function.






    share|improve this answer





















    • Accepted answer. This allows me to reach the siblings by triggering their corresponding observables like i wanted to, thanks.
      – NachoDawg
      Nov 15 at 13:13










    • Actually it doesn't entirely work like i thought. While I manage to trigger the observable of a sibling, 'this' refers to the original point. I changed all the functions touched by handleCubeUpdate to arrow functions, but they always seem to refer to the point that triggered the sibling to update the walls
      – NachoDawg
      Nov 15 at 14:04















    up vote
    2
    down vote













    Now it make more sense to me that I could try to answer it here.
    Hopefully I could articulate this properly :).



    So, when you pass in a function reference in your subscribe, this in handleCubeUpdate has a different context.
    You can change your function implementation to arrow function.



    handleCubeUpdate = () => {
    this.updateWalls();
    }


    additionally, if your updateWalls is calling another function, then you should change that updateWalls function arrow function.






    share|improve this answer





















    • Accepted answer. This allows me to reach the siblings by triggering their corresponding observables like i wanted to, thanks.
      – NachoDawg
      Nov 15 at 13:13










    • Actually it doesn't entirely work like i thought. While I manage to trigger the observable of a sibling, 'this' refers to the original point. I changed all the functions touched by handleCubeUpdate to arrow functions, but they always seem to refer to the point that triggered the sibling to update the walls
      – NachoDawg
      Nov 15 at 14:04













    up vote
    2
    down vote










    up vote
    2
    down vote









    Now it make more sense to me that I could try to answer it here.
    Hopefully I could articulate this properly :).



    So, when you pass in a function reference in your subscribe, this in handleCubeUpdate has a different context.
    You can change your function implementation to arrow function.



    handleCubeUpdate = () => {
    this.updateWalls();
    }


    additionally, if your updateWalls is calling another function, then you should change that updateWalls function arrow function.






    share|improve this answer












    Now it make more sense to me that I could try to answer it here.
    Hopefully I could articulate this properly :).



    So, when you pass in a function reference in your subscribe, this in handleCubeUpdate has a different context.
    You can change your function implementation to arrow function.



    handleCubeUpdate = () => {
    this.updateWalls();
    }


    additionally, if your updateWalls is calling another function, then you should change that updateWalls function arrow function.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 15 at 13:07









    dK-

    22828




    22828












    • Accepted answer. This allows me to reach the siblings by triggering their corresponding observables like i wanted to, thanks.
      – NachoDawg
      Nov 15 at 13:13










    • Actually it doesn't entirely work like i thought. While I manage to trigger the observable of a sibling, 'this' refers to the original point. I changed all the functions touched by handleCubeUpdate to arrow functions, but they always seem to refer to the point that triggered the sibling to update the walls
      – NachoDawg
      Nov 15 at 14:04


















    • Accepted answer. This allows me to reach the siblings by triggering their corresponding observables like i wanted to, thanks.
      – NachoDawg
      Nov 15 at 13:13










    • Actually it doesn't entirely work like i thought. While I manage to trigger the observable of a sibling, 'this' refers to the original point. I changed all the functions touched by handleCubeUpdate to arrow functions, but they always seem to refer to the point that triggered the sibling to update the walls
      – NachoDawg
      Nov 15 at 14:04
















    Accepted answer. This allows me to reach the siblings by triggering their corresponding observables like i wanted to, thanks.
    – NachoDawg
    Nov 15 at 13:13




    Accepted answer. This allows me to reach the siblings by triggering their corresponding observables like i wanted to, thanks.
    – NachoDawg
    Nov 15 at 13:13












    Actually it doesn't entirely work like i thought. While I manage to trigger the observable of a sibling, 'this' refers to the original point. I changed all the functions touched by handleCubeUpdate to arrow functions, but they always seem to refer to the point that triggered the sibling to update the walls
    – NachoDawg
    Nov 15 at 14:04




    Actually it doesn't entirely work like i thought. While I manage to trigger the observable of a sibling, 'this' refers to the original point. I changed all the functions touched by handleCubeUpdate to arrow functions, but they always seem to refer to the point that triggered the sibling to update the walls
    – NachoDawg
    Nov 15 at 14:04










    up vote
    0
    down vote













    Have you considered using a REDUX architecture in Angular?



    Here's a good tutorial on how it works and the benefits. I have used the exact same tutorial to learn about it and implement.



    You could then keep that array in your store and dispatch actions to change thing. Each action could contain the logic to update itself + the two items surrounding it.






    share|improve this answer

























      up vote
      0
      down vote













      Have you considered using a REDUX architecture in Angular?



      Here's a good tutorial on how it works and the benefits. I have used the exact same tutorial to learn about it and implement.



      You could then keep that array in your store and dispatch actions to change thing. Each action could contain the logic to update itself + the two items surrounding it.






      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        Have you considered using a REDUX architecture in Angular?



        Here's a good tutorial on how it works and the benefits. I have used the exact same tutorial to learn about it and implement.



        You could then keep that array in your store and dispatch actions to change thing. Each action could contain the logic to update itself + the two items surrounding it.






        share|improve this answer












        Have you considered using a REDUX architecture in Angular?



        Here's a good tutorial on how it works and the benefits. I have used the exact same tutorial to learn about it and implement.



        You could then keep that array in your store and dispatch actions to change thing. Each action could contain the logic to update itself + the two items surrounding it.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 15 at 13:11









        SebastianG

        748115




        748115






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53319005%2fangular-6-using-observable-to-trigger-event-between-siblings%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

            ComboBox Display Member on multiple fields

            Is it possible to collect Nectar points via Trainline?