I created a component which is called sidebar. That component has let's say 2 inputs, sideBarMode and sideBarSide. In the app.component I add this component like this
<sidebar [sideBarMode]="'sliding'" [sideBarSide]="'right'"></sidebar>
.
When I use the above as one tag, it works as expected. However, when I do something like
<div>
<sidebar [sideBarMode]="'sliding'" [sideBarSide]="'right'"></sidebar>
</div>
<div>
<sidebar [sideBarMode]="'docked'" [sideBarSide]="'left'"></sidebar>
</div>
They are rendered but with the same classes, although if I will console log the values in ngOnInit which are being passed, they show correctly. E.G one div should show sliding as a class, and the other one as docked. Instead, they show as docked both.
This is the HTML template.
<div class="container-fluid">
<div [ngClass]="barSliding ? 'sliding' : 'sidebar-docked'">
<div class="row k-sidebar {{theme}}"
[ngClass]="[sidebarLeft ? 'position-left' : 'position-right', barSliding ? 'sliding-content-bar' : 'sidebar-docked', isDesktopWidth.value ? 'largeView' : 'mobileView']"
[@slideAnimation]= 'animationState'
[@dockMobileSidebar]= 'animationStateMobile'
[ngStyle]="{'width.px': isDesktopWidth.value ? sideBarWidth : '' }"
>
<div class="col-md-12">
<ng-container *ngIf="sidebarTemplate">
<ng-container *ngTemplateOutlet="sidebarTemplate">
</ng-container>
</ng-container>
<ng-container *ngIf="!sidebarTemplate">
<p>This is a paragraph, no template has been passed</p>
</ng-container>
</div>
</div>
</div>
This is how I check the mode, wether it is docked or not in TS file and I call this method from the ngOnInit.
private checkSidebarMode(mode) {
console.log('checkSidebarMode ', mode);
if (mode === 'sliding') {
this.sidebarService.sideBarSliding.next(true);
console.log('checkSidebarMode ', this.sidebarService.sideBarSliding.getValue());
this.sideBarDock.next(false);
} else if (mode === 'docked' && this.sidebarService.innerWidth.getValue() <= 767) {
this.sideBarDock.next(false);
this.sidebarService.sideBarSliding.next(true);
} else if (mode === 'docked' && this.sidebarService.innerWidth.getValue() > 767) {
this.sideBarDock.next(true);
this.sidebarService.sideBarSliding.next(false);
this.sidebarService.animationState.next('docked');
console.log('checkSidebarMode ', this.sidebarService.sideBarSliding.getValue());
}
}
As you can see, if it is sliding, I set the observable to true, and then In the ngOninit I assign that value to barSliding, which is used in the HTML template to determine the class name.
The docked one is correct, however, the sliding one is getting the docked properties...why?
As your
BehaviorSubject
is in thesidebarService
, this one is probablyprovidedIn: 'root'
which makes it a singleton. Thus, yourBehaviorSubject
is the same for the two instances of your component.You have multiple solutions:
BehaviorSubject
directly in your component instead of using a shared BehaviorSubject in a service. I would update it by callingnext()
in angOnChanges
method as soon as themode
input changes.BehaviorSubject
instance to be used by your component. Maybe there is no real benefit over the first solution if it's a simpleBehaviorSubject
with no logic attached.But this make really sense only if the
BehaviorSubject
you return from the service must use other information from the service (other data, static variables like size of the screen, etc).One question you should ask yourself is the following: does this behavior should be shared among components or known by other component? In this case you can delegate it to a global singleton service. Example: every component may need to know at one point if the app's main sliding menu is opened or not. Or, does this behavior is specific to a component's instance? In this case the state should be stored in the component instance itself. Example: I have two collapsible elements, each must keep track of either it is collapsed or not, but no other component needs to know about this state.
There are many strategies you can adopt, and there is no answer that can fit all situations.