How to update react component props (and rerender) from "outside React" - javascript

My application is mixed with vanilla JS and React components, and I have a component that I would like to rerender by changing the props from outside the react component. How would I accomplish this? And maybe I need to be using "state" instead?
This component is only shown when a user clicks a dropdown link in a list of items. Because the list can be quite long, I am trying to be efficient with creating only one component and then changing the props (rerendering) depending on which item in the list if clicked.
This is the code the initially creates the component with references to the "root" and "element"
// Render AdjustDateFormulaComponent
let rootContainer = document.getElementById('rc_dateFormulaComponent');
if (rootContainer) {
this.dataFormulaWidgetRoot = createRoot(rootContainer);
this.dataFormulaWidgetElement = createElement(AdjustDateFormulaComponent, {
id: null,
entityType: 'taskTemplateEntry',
onSave: _this._dateFormulaUpdated, // callback method
});
this.dataFormulaWidgetRoot.render(this.dataFormulaWidgetElement);
}
When item is clicked, rerender by changing props (specifically the "id" field) and show/move in the appropriate dropdown div
_this.$widgetDiv.find('.dueDateAdjustDropdown').on('show.bs.dropdown', function () {
// Change props/rerender here with correct id
this.dataFormulaWidgetElement.props = { id: 124 }; // <--- THIS DOESNT WORK OBVIOUSLY
// When dropdown shown, move react component into dropdown div
$(document.getElementById('rc_dateFormulaComponent'))
.detach()
.appendTo($(this).find('.dropdownContent'));
});
Many thanks in advance.

Related

React: On click update a child component from parent component

I'm trying to show a table of data on click on a number in another component called Sidebar. I have a parent component ShowTable and two child components Sidebar and Table. However, because I have componentDidMount in Table it only shows the table for the first click. On the second click the table doesn't change, since it has already been mounted. Does anyone know how I could solve this, so that on every click the table would reload? So, how could I trigger a function in the child from the parent component or what could I use instead of componentDidMount? I tried using componentDidUpdate, so that every time a new serial is sent by props the component would load again, however, it starts to infinately loop.
Function handleSelect in ShowTable:
handleSelect=(value)=>{
this.setState( {serial: value, showComponent: true} )
console.log(this.state.serial)
}
In render ShowTable:
{this.state.showComponent ?
<Table s={this.state.serial}/>:
null
}
In Sidebar:
{this.props.se.map((number) => (
<li>
<a onClick={()=>this.props.handleSelect(number.ta)}>{number.ta}</a>
</li>
))};
In Table:
componentDidMount() {
const database = db.ref().child("Devices/" + this.props.s);
...
Thanks in advance!

Angular change child component template with parent component action

I'm trying to create a child component (it's a form), which appears within a parent component in a modal.
The form (child component) must change according to the type chosen in the parent through several buttons (each button is a different type).
When you click on the button, the child component must modify the form according to the type chosen in the parent. The form controls change properly, but the template is not modified. The code is the following:
Parent method that opens the modal and calls the child component
show(value: string){
this.type = value;
this.entityFormComponent.type = this.type;
this.entityFormComponent.ngOnInit();
// Set submitAttemp to false for the new form
this.entityFormComponent.submitAttemp = false;
this.contentModal.show();
}
Method ngOnInit of the child component
ngOnInit(): void {
if(this.creating){
this.entity = new Entity();
} else {
this.entityService.get(this.nameToEdit, this.type)
}
// Initialize the form and add the corresponding attributes according to the type
this.entityForm = new FormGroup({});
this.entityHelper.getEntityFormAttributes(this.entityForm, this.type, this.entity);
}
So far it seems that everything is correct and the form group that is generated is adequate every time you click on the parent button, but the inputs of the form do not appear. They are generated through an auxiliary method, which returns true or false through the type and attribute of the input that is passed:
<div class="col-md-6" *ngIf="entityHelper.getEntityInputsAttributes('shadow', type)">
The type in the view is "undefined", but in the component appears correctly. Why doesn't the view update the type correctly? What do I have to do to update it?
For parent child component interactions, it is advised to use the Input directive.
If you have different types of forms you could use an enum. And bind each enum entry to each of the buttons by adding an action to the button that sets a property with its correspondent type. For example:
onClick(type: FormTypes) {
this.formType = type;
}
You parent template would look something like
<child-component [typeOfForm]=formType </child-component>
Your child component would need to execute changes when a new formType is provided therefore you would need to do something like
#Input()
set typeOfForm(typeOfForm: FormType) {
//make the necessary changes on form type change.
}
Also to avoid manually executing the ngOnInit function would can surround your child component tag with a div and have it showing or not with a boolean property on the typescript code like so:
<div *nfIf="showForm">
<child-component [typeOfForm]=formType </child-component>
</div>
doing this your show function would only set the showForm property to true.
Hope this helps, for more detailed information on component interaction I suggest you check out this documentation Angular Component interaction

Semantic UI React, Dropdown Selection

Please take a look at my code for Dropdown,
I'm using the semantic ui react dropdown on an EditProfile component. I have pasted a sample code here, https://codesandbox.io/s/m4288nx4z8, but I could not get it to work because I'm not very familiar with functional components in React, I've always used Class component. But you can check the full code for the whole component below in the github gist.
https://gist.github.com/mayordwells/b0cbb7b63af85269091f1f98296fd9bb
Please, I need help on inserting values from multiple select options of a Dropdown into the Database and also a way to display that back upon viewing the profile edit page again.
I'm using semantic-ui-react in react + rails app.
Also when I insert a value using a normal drop down without multiple select, the value gets persisted into the database.
<Dropdown
placeholder='Select Country'
fluid
search
selection
options={countryOptions}
name='country'
defaultValue={this.state.extraInfo.country}
onChange={(e) => this.handleExtraInfoChange('country', e)}
/>
This code handles change for the dropdown elements.
handleExtraInfoChange = (name, event) => {
let value;
if (event.target.value !== undefined) {
value = event.target.value;
} else {
value = event.target.textContent;
}
let newExtraInfo = Object.assign(this.state.extraInfo, { [name]: value })
this.setState({ extraInfo: newExtraInfo});
}
But when I visit the page again, I get a white blank in the input box. Here's a screen pic for that. When I comment out the defaultValue or value property(i have tried with defaultValue and value), the white blank disappears, but the value picked by a user is also not seen.
Please advice what is a possible solution to this misbehavior? And what is the best way to insert multiple values into the Database?
Thanks in advance for your time.
A functional component does not have state, it's used for composition; you want to store state, so you either have to create a Component class or you need an external state container like redux.

Manipulating parent's array prop - Reactjs

This question may sound a little complicated. But i am stuck here, so i am throwing it here.
I am rendering a child component multiple times in parent with different properties and an array.
Parent contains an array of headings, i am passing it to child components and mapping select options with that array. If an heading is selected from any of the child components, that heading should display as disabled in other child components.
Child:
{
this.props.xarray.map((heading, index) => {
if (heading.headingis.toLowerCase().indexOf(this.state.field) != -1) {
this.setcheckstate(); //ignore this function
this.props.actionis(index, 'disabled'); //Using this function (passed from parent) to disable selected option
return <option value={heading.headingis} key={index} selected disabled={heading.disabled}>{heading.headingis}</option>
}else{
return <option value={heading.headingis} key={index} disabled={heading.disabled}>{heading.headingis}</option>
}
})
}
Parent's actionis function:
handlerHeading(index, disabled) {
xarray[index]['disabled'] = disabled;
}
It's working somehow BUT problem is
If first component is rendered, it will disable that value
Then 2nd component is rendered, it will disable that value
along with previous one.
and so on...
But in first component, only one value is disabled, in 2nd component 2 values are disabled and in 3rd component 3 values are disabled. And so on...
But i want if one value is disabled in component 6, it should get disabled in all previous components.
Have a look at following images for example.
Component #1 Rendered:
Component #4 Rendered:
I have resolved this, by changing xarray to state of parent.
This:
state = {xarray: xarray}
And:
handlerHeading(index, disabled) {
xarray[index]['disabled'] = disabled;
this.setState({ xarray: xarray });
}
For some reason you cannot change Props as you desire. See This Question

React.JS, pass data between components

very new to react. you can say I have not yet started to think like React.
here is the problem:
<div>
<DropDown> </DropDown>
<Panel> </Panel>
</div>
In the dropdown, I select a value. Store it in state, as something as , currentLocation.
Then I go to Panel, hit a button, and I want to open a modal. When i open a modal, I need to pass the currentLocation to that model.
I can pass in arbitrary value to modal, but I cannot figure out a way to get the currently selected item from DropDown.
How do I get the value of the currently selected item to the Panel?
Am I even making sense?
When you call the setState in the dropdown that will force an update of the page.
Then if you call this.state in your component you should have the value you need there.
You should go over the basic tutorials to grasp the react basics.
But it goes like this:
getInitialState: function() {
return {
myVar: ''
//set your variables here
//getInitialState will get called before the component gets mounted
};
},
myCustomFunction: function(newVariable) {
this.setState({
myVar: newVariable
});
},
render: function() {
return (
<div>
<input
onChange={this.myCustomFunction}
/>
<MyCustomComponent myProp={this.state.myVar}/>
//everytime the state changes MyCustomComponent will have that new value as a prop
</div>
);
}
There is a lot of ambiguity in your question but I'll try for the simplest case.
You have a Panel component and a Dropdown component.
You want to the Panel to have access to a value that was set when the Dropdown was used.
Solution: When the Dropdown is actuated, it creates an Action that Stores the selected value.
When the modal button in the Panel is actuated, it creates an Action that requires the DropDownStore. Then it decides what to do based on that value.
The pattern I am loosely describing is known Facebook's Flux architecture which is basically just a more specific application architecture for React applications similar to pub/sub or an event bus.

Categories