Angular show/hide on parent component based on child component - javascript

I have a parent component with the following template:
<app-sidebar></app-sidebar>
<router-outlet></router-outlet>
<app-footer></app-footer>
How can I show or hide the app-sidebar or app-footer component based on the component routing through the router outlet? I have a boolean showSidebar I'd like to use, with it's value set to true or false on each child component.
<app-sidebar *ngIf=showSidebar></app-sidebar>

In the app routes add a data property.
{ path: 'no-sidebar', component: NoSidebarComponent, canActivate: [AuthGuard], data: { showSidebar: false } },
and subscribe to the router events in the parent component like this
this.router.events.subscribe(event => {
if (event instanceof RoutesRecognized) {
const routeData = event.state.root.firstChild.data;
if (routeData) {
this.showSidebar = routeData.showSidebar === false ? false : true
}
}
}

Instead of direct component to component communication, you could use a service to share the show/hide flag and inject the service in the enclosing component as well as the the ones routed to.
For example child components' onInit, set a flag in the shared service instance. The parent component containing the router outlet, would read that flag and use it along with an *ngIf to show or hide parts of the template.

You can use subject variable, whenever you want to hide or show that time emits value of variable and subscribe to that variable in sidebar and footbar

Related

How can i get boolean data from another component in vue js?

I have two Components.
In the second component, "date-detail-filter" I always keep track for boolean value, and want to access this data in my parent component.
do you know how to use $emit?
In your date-detail-filter component
you can add this to your method. this.$emit('your-event-name', 'your payload')
and in your main component.
<date-detail-filter #your-event-name="functionName()"/>
functionName(payload) {
your logic here to hide the caret
}
$emit is used to pass data from child component to parent component via event.

How can I access a property of a step component from the parent page of a Vue stepper?

Not very experienced with Vue, and am struggling to fix an issue with an existing component made by a previous developer.
On the parent page, the stepper component is declared like this, with these as the names of the sub-components that make up the individual steps:
#Component({
name: 'switch-stepper',
components: {
Stepper,
StepIndicator,
FirstStep,
SecondStep,
ThirdStep
}
})
There's a property in ThirdStep that needs to be changed, either in the parent page or in FirstStep. The property in question is public, and declared like this:
#Prop({ default: true })
public myBooleanProperty: boolean;
However, inside the parent page, if I try this:
ThirdStep.myBooleanProperty
It is not recognised by the intellisense and is undefined. I've tried also creating a public method on ThirdStep that I can call to use ForceUpdate but public methods likewise seem to be inaccessible.
I've also tried setting the public property via a function in the parent page when the step is created:
<third-step :page="page"
:step="steps[4]"
:myBooleanProperty="setMyBooleanProperty()"
v-show="currentStep === steps[4]">
</third-step>
But as far as I can tell this is only called once when the step is created and never accessed again.
What can I do to set the property of this child step via other components in the stepper?
There's a property in ThirdStep that needs to be changed, either in the parent page or in FirstStep. The property in question is public,
and declared like this:
If a property needs to be changed, it should be changed in the component which returns the property in the data property. By this, I mean, the component that has
data() {
return {
myBooleanProperty: false // or true. This is the local data that will be initialised and passed as props to the ThirdStep component
}
}
If this is in the parent page, change ThirdStep.myBooleanProperty to this.myBooleanProperty = *enter value*. The change of the value of myBooleanProperty can be done in a method, watcher, computed property etc. The reason ThirdStep.myBooleanProperty is not working in the parent component, is that each vue component is a Vue instance and ThirdStep cannot have access to an instance property in the parent component.
ParentComponent.vue
#Component({
name: 'switch-stepper',
components: {
Stepper,
StepIndicator,
FirstStep,
SecondStep,
ThirdStep
}
})
<third-step>
...
:myBooleanProperty="myBooleanProperty" // my boolean property is passed as props from the parent component, I assume
....>
</third-step>
When myBooleanProperty is changed where it is initialised (parent component, I assume), this will cause the value of the myBooleanProperty props, passed into the ThirdStep component, to change and there will be a re-render of the parts of the ThirdStep component that use myBooleanProperty props.

How to store value in common file and get the same value in other component in angular 6

I am working on a project Where I have a dropdown in one component (Header component) and I am assigning a default value to it in an API call on first component load. Example: value = 1
Problem is when I change the dropdown value Example: value = 2 and try to navigate to another component, the header component loads each and every time I navigate to any other component as it is commonly used in structure and the value again changes back to the default assigned Example: value = 1
I have tried to achieve this by creating service file and using subscribe in it.
And call it. But each time I navigate to another component the Header component loads and the value again changes.
Is there any way that I can achieve this.
I think your main component could have wrong structure.
If your main component contains HeaderComponent and router, it should look something like this:
<app-header></app-header>
<section>
<router-outlet></router-outlet>
</section>
<app-footer></app-footer>
Then navigation in your application via Router should not cause re-render of HeaderComponent.
If your HeaderComponent gets data in ngOnInit then it should be instantiated only once:
#Component({
selector: 'app-header',
template: 'header.component.html'
})
export class HeaderComponent implements OnInit {
myData: [];
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.getData()
.subscribe(result => this.myData = result);
}
}

Angular parent component "scoping" child component

Suppose I have components Parent and Child. Child can be used either as a standalone component, or within a Parent component. However, I want Child to have different behavior based upon where it lives.
Suppose Child has an optional #Input [isHappy], which is either true or false. However, whenever a Child component is hosted by a Parent component, suppose isHappy must always be true.
AFAICT there are two ways of doing this:
1) User must just know to always specify [isHappy]="true" whenever a Child is hosted by a Parent.
<parent>
<child [isHappy]="true"></child>
</parent>
2) Parent manually sets this.child.isHappy = true within its ngOnInit lifecycle hook.
Which approach is preferred? In my opinion, approach #2 makes more sense, users don't have to know to set [isHappy]="true" when a Child is hosted by a Parent. On the other hand, I'm aware that it's frowned upon in Angular for components to programmatically change one another, especially if all components are OnPush (please correct me if I'm wrong here).
I want Child to have different behavior based upon where it lives.
How about letting Child component know where it lives with ElementRef:
export class ChildComponent {
hasParent: boolean;
constructor (
private elRef: ElementRef
) {}
ngOnInit() {
const el = this.elRef.nativeElement.parentElement as HTMLElement
this.hasParent = el.localName === 'app-parent'
}
}
stackblitz: https://stackblitz.com/edit/angular-kagdsu
In my opinion 2nd way would work, but that could add couple of things into your solution
Tight coupling between two component
What if parent component don't have child component?
To solve it by better way, I'd suggest you to use Host decorator, that will ask for Parent component dependency from Child component. If that exists the make isHappy property to be true
#Component({...})
export class Child {
#Input() isHappy: boolean = false;
constructor(#Optional() #Host() private parent: Parent) {}
ngOnInit() {
// Do only if parent exists
if (this.parent) {
this.parent.isHappy = true
}
}
}
I understand even the way suggested above has tight coupling between the Parent component. We should think of removing that dependency from the inner child component.
Yes, we can do that by little hackish way, where we would be checking current component's immediate parent component name like below. For achieving the same you had to add ViewContainerRef dependency to get hold of parent/host component.
constructor(private viewContainer: ViewContainerRef) {}
ngOnInit() {
if(this.viewContainer[ '_data' ].componentView.parent.component.constructor.name === 'Parent') {
this.parent.isHappy = true
}
}

emit event with arguments from child to parent with ember 3.6

I would like emit one event from child to parent but with some argument.
Child component javascript
import Component from '#ember/component';
export default Component.extend({
tagName: 'li',
actions: {
favoriteWasClicked() {
const organization = this.get('organization');
// organization.id value equal to 'facebook' here in my app
// we're gonna send its id to parent component "orgs" like an argument of clicked method
this.clicked(organization);
}
}
});
Parent component .hbs template
{{child-component
clicked=(action "favoriteClicked" value="organization.id")
}}
Parent component javascript controller file
import Controller from '#ember/controller';
export default Controller.extend({
actions: {
favoriteClicked(orgId) {
console.log(orgId);
}
}
});
I'm getting undefined in console.log(orgId); Why? What am i missing
Thank you!
You simply need to change organization.id to just id. What I mean is; you need to do the following:
{{child-component
clicked=(action "favoriteClicked" value="id")
}}
You send the event from the child component with an organization; which simply contains an id; but not organization.id; so it must be just id for the value property in the action passing within parent's template.
I prepared an ember twiddle for you to illustrate the solution I proposed in action. Hope that helps.

Categories

Resources