Change children class with parent onClick in React? - javascript

I have multiple parent components and within each parent component are nested children components. I'd like to have the class in the nested childrens' component change when a link in that parent component is clicked (a show/hide toggle type thing). I'm guessing this can be done by setting and changing state in the parent component on the click, but am not sure. Is this the correct way to handle this?
Is it usually best practice to hold state in the root component (I should note that the parent component explained above is not the root).
Any and all help is greatly appreciated. Thanks!

Generally, the higher up in your component hierarchy you can push state, the better. Then as the state changes in your parent/root component, new props will trickle down to child components. This makes your child components a lot simpler because they don't have to manage as much of their own state, if any.
In your case, you're exactly right. Handle the click event in your parent which will change your state, then render your child component with the correct className based on that state.
var Child = React.createClass({
render: function () {
return <div {...this.props}></div>;
}
});
var Parent = React.createClass({
handleLinkClick: function (e) {
this.setState({toggle: !this.state.toggle});
},
render: function () {
return <Child className={this.state.toggle ? 'yes' : 'no'} />;
}
});

Related

this.$destroy vs v-if vue js with pages

i have a menu with many items. on item click I create a new Vue element (with Vuex store). The question is:
on close witch is outside the vue instance do I have to call this.$destroy or v-if="false" the root element.
<template>
<div v-if="closeVar">
....
</div>
</template>
<script>
export default {
...,
data() {
return {
closeVar: true
};
},
methods: {
onWindowsClose() {
this.$destroy() OR this.closeVar = false; ????
}
},
created() {
window[id + 'onWindowsClose'] = this.onWindowsClose;
}
}
</script>
From the $destroy docs:
In normal use cases you shouldn’t have to call this method yourself. Prefer controlling the lifecycle of child components in a data-driven fashion using v-if and v-for.
So the answer from the docs is that it's preferred to use v-if. Furthermore, you should place that v-if on the component's tag in the parent, not within the component on the root element:
Parent
<child v-if="closeVar"></child>
Otherwise, you'd only be removing the child's content rather than the entire component.
The difference there is, for example, the child's created hook would not be called again if you repopulated that particular instance with content (which would be possible because the component wouldn't have been destroyed.)

angular 2 variable returns null in child component method when called from parent component

I have parent and child component communication, I want to fire up a method in child component that should open up a modal and pass the data. When I call a function from parent using ViewChild, the variable in the child method component returns null, however should have data inside variable. When I fire same function within the child component, the data is available, but its not a case when called from parent component. What is missing and why I don't see data in child component, from fire up from the parent component?
parent.html
<button (click)="openModal()">New</button>
<child><child>
parent.ts
import { FilterComponent } from './../filter/filter.component';
#ViewChild(FilterComponent) filterComponent: FilterComponent;
openModal(){
this.filterComponent.openModal(); // when fired from here, the function in the child component fires, but the variable inside it returns null
}
child.html
<button (click)="openModal()">New</button>
<modal><modal>
child.ts
openModal(){
modalVisible = true;
console.log(this.filter) returns null; when fired from parent component
console.log(this.filter) returns "filter data"; when fired within the component
}
From what I can tell you are currently selecting ALL FilterComponents inside your parentComponent. In order to use this you need to be more specific. You can change your ViewChild to select only one FilterComponent if that fits your use case.
Example:
parent.html
<button (click)="openModal()">New</button>
<!-- notice the #child attribute -->
<child #child><child>
Then in parent.component.ts
import { FilterComponent } from './../filter/filter.component';
#ViewChild("child") filterComponent: FilterComponent;
openModal(){
this.filterComponent.openModal(); // now that you're only selecting one element this function call should have access to this values.
}
You can also reference the relevant stack blitz i made here: https://stackblitz.com/edit/angular-lqmc8x
Good luck!
I think you need an EventEmitter.
parent.html
<child (messageEvent)="openModal($event)"></child>
child.ts
import { Component, Output, EventEmitter } from #angular/core;
export class...
#Output() messageEvent = new EventEmitter<string>();
openModal(val) { this.messageEvent.emit(val); }
child.html
<button (click)="openModal(val)">Click</button>
or something like that.
I think you should rethink your architecture here.
If the method is triggered from the parent component only, then put into the parent component
If the the method is triggered from both parent AND child component, then put into a service

Access the parent's data on child events in Vue js

I have two components, one inside the other one. I have a click event on the parent component that should change the data value of the child component.
<template>
<div>
.....
.....
<my-component
:options="options">
</my-component>
</div>
.....
.....
</template>
<script>
...
...
data(){
}
methods:{
clickEvent(array_from_child){
this.array = array_from_child; //array is in my-component
}
}
components:{
....
}
</script>
I want to trigger the clickEvent method on child's element change. how to do that?
It seems like you're asking two different questions.
First, accessing a child's data from its parent:
If possible, you should pass the array to the child component using the child's props. Then simply change the array in the parent and any changes will be reflected in the child. If the array really needs to be in the child, then you can define a method to retrieve it.
<template>
<child-component ref="child">
</child-component>
</template>
methods: {
onClick() {
const myArray = this.$refs.child.getMyArray();
}
}
And then, in the child
methods: {
getMyArray() {
return this.myArray;
}
}
Second, triggering a change in the parent from the child
In this case, Flame's answer is most idiomatic. Emit a custom event in the child and listen for that event in the parent.
When you are going from a child to a parent, you should use events:
{
methods: {
clickEvent()
{
this.$emit('click', mydata);
}
}
So in your parent element, you can then attach your own callback to the emitted event like so:
<template>
<my-child-component #click="theParentMethod" />
</template>
You could also use some reactivity by passing an object reference from the parent to the child, so if you change the object in the child, the parent can detect the changes. However this comes with some reactivity gotcha's, see https://v2.vuejs.org/v2/guide/reactivity.html .

Animate (Expand,collapse) child component along With parent component [Angular5]

I want to achieve this(Ref. attached image) in Angular 5
There Two components User-layout and role
User-Layout Component has been used at the start of Role component.
I am able to Expand and collapse the Parent component with animations but unable to to do the same simultaneously for the child component.
Any way to trigger animation on child component from the parent component.
For communication between child component and parent component you can use #Input, #Output and EventEmitter.
If you want to pass data from parent to child you can simply do it using #Input as below:
First you need to import Input into your child component using
import { Component, Input } from '#angular/core';
Then you need to declare an #Input variable in your child component
export class ChildComponent {
#Input() parentVariable: string;
}
Then while using the child component in you parent you need to specify the varible as an attribute as below
<child-component [parentVariable]="parentData"></child-component>
You should have a parentData declare in your parent component whose changes will reflect in the child component #Input variable parentVariable.
Thats all you need to do to and you need to animatation code which will trigger on the change of parentVariable variable.
Hope this helps!!!!
Take a look at animateChild() method.
Excerpt from the blog post posted by the #angular/animations author, Matias Niemelä, about animateChild()
Now what about the situation when there is an element in the application that has an animation ready-to-go, but a parent animation runs instead? Is there a way that the parent animation can dictate when the child animation runs, how long it runs for or if it doesn't run at all?
[...]
If these animations trigger at the same time then the parent animation will always win and the child animation will be skipped. However, using animateChild we can have the parent animation query into the child and tell it when it's allowed to animate:
Sub Animations With animateChild
component.html
<!-- do these two guys animate at the same time? -->
<div [#parent]="parentVal">
<div [#child]="childVal">
...
</div>
</div>
component.animations
trigger('parent', [
style({ transform: 'translate(-100px)' }),
animate('500ms',
style({ transform: 'translate(0px)' })),
query('# child', animateChild())
]),
trigger('child', [
style({ opacity:0 }),
animate('0.5s', style({ opacity:1 }))
])

how to interact with unspecified number of react child components

I've got a component which can contain any number of child components, and I want these child components, which contain input fields, to set those input fields to "disabled" when the state in the parent is changed. I've been attempting to use React.cloneElement with React.Children.map to modify the properties of the child elements, but it doesn't seem to be affecting anything.
Here's a simplified version:
# parent component
# assume that there's a #setState call in here somewhere
DisableableItem = React.createClass
getInitialState: ->
disabled: false
render: ->
<div>
{
React.Children.map #props.children, (child) =>
React.cloneElement child, isDisabled: #state.disabled
}
</div>
# child component
ParameterizedOption = React.createClass
getInitialState: ->
disabled: #props.isDisabled
render: ->
<div className="parameterized-option">
<label>{#props.text}</label>
<div className="input-group input-group-sm">
<input type={#props.inputType or "text"} className="form-control"
placeholder={#props.initialInput or "00.00"}
disabled={#state.disabled}></input>
</div>
</div>
And rendering it like:
React.render <DisableableItem>
<ParameterizedOption text="hey" isDisabled=false />
<ParameterizedOption text="hey" isDisabled=false />
</DisableableItem>, document.body
So I'm console.logging the output, and the state in the parent is getting modified when I want it to, but the children's props are not getting modified as I thought the React.cloneElement call would modify them (they're always false as they were at start). I've taken a look at these questions, but I don't think they really apply, since DisableableItem doesn't know what its children are until they're given to it in the call to React.render, so it can't put disabled={#state.disabled} as one of the children's properties.
How would I reach in and modify these children's state? Am I misunderstanding what cloneElement is supposed to do?
You're copying the props to the state, which is some bad mojo. (https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html)
Just bind props.disabled directly to the element instead of copying it over to state.
Your current code:
getInitialState: ->
disabled: #props.isDisabled
This will only work if you ensure you update state.disabled in componentWillReceiveProps to reflect the new props.disabled passed in.
If you're deadset on doing it your weird way: https://jsfiddle.net/1t8ew85x/

Categories

Resources