Render props method without nesting dom element - javascript

In essence I have the following inside a react functional component:
<div className="content">
<div className="filters">
<MyFilter1 data={data}>
{(filter1Data) => {
return <MyFilter2 data={filter1Data}>
{(finalData) => {
return <div className="final-data">{finalData}</div>
}}
</MyFilter2>
}}
</MyFilter1>
</div>
<div className="filtered" />
I am using multiple filters with the render children paradigm to get the final data. But for (admittedly frustrating) styling reasons, I would like to render the final data in a div outside of the filters location (inside the 'filtered' div in this case). How can I do this? Is my approach wrong? Is the 'filter with render children' the wrong approach?
I have tried:
React portal with createRef(), in essence the problem ends up being that the ref is not available yet when the 'finalData' function is called.
Edit:
The filter components themselves are very complicated but I can give a couple examples. The data I'm filtering is a simple object with 12ish properties. One of the filters is implemented as a series of checkboxes determining which properties of the data I want to display (necessary as a separate component because of the number of fields). One of the properties on the data is a price, and another filter is a price range 'dialer', that specifies the price range to display ( aka exclude data points outside the range).

Related

Vue 3 Realoading component if variable change

I am trying to realod component if selectedLeague has been changed
<label class="label">Select league</label>
<div class="selector">
<v-select
v-model="selectedLeague"
:dropdown-should-open="dropdownShouldOpen"
:options="leagues"
label="displayLeague"
placeholder="Select a league"
/>
</div>
<div v-if="selectedLeague">
<LeagueTopScorers :is="selectedLeague" :selectedLeague="selectedLeague.id.toString()" />
</div>
In LeagueTopScorers component I am fetching API to get top scorers from selected league.
I tried :watch, v-on:, created()
<LeagueTopScorers /> does re-render when selectedLeague changes 1, but it doesn't re-mount.
It only mounts when selectedLeague changes from a falsy value to a truthy one (because that's when the value of the v-if changes).
There are a few problems with your question:
you're asking about a technical aspect (let's call it X), which you think will solve a business requirement (let's call it Y). It's a classical XY problem. Why don't you describe the Y requirement? (e.g: what you want to achieve). What output change do you want to see on what input change?
the code you posted is not enough to create a runnable example. We don't know what v-select is, what <LeagueTopScorers /> is, or how does :is prop look like on <LeagueTopScorers />.
From the snippet you posted, I am guessing the following:
v-select is either vue-select or Vuetify select component
you expect :is to work on <LeagueTopScorers /> as it does on <component />. Hint: it doesn't, unless you coded it yourself, which I doubt
last, but not least, I guess you want some code you placed into an init lifecycle hook of <LeagueTopScorers /> (e.g: onMounted) to run when you replace an object stored in selectedLeague with another object.
If I'm correct, the simplest and cleanest way to achieve this behavior is to create a computed 2:
const leagueId = computed(() => selectedLeague?.id.toString() || '')
... and use it in v-if, :key and :selectedLeague:
<LeagueTopScorers
v-if="leagueId"
:selectedLeague="leagueId"
:key="leagueId" />
(without the <div v-if> wrapper).
The above will create a new instance of <LeagueTopScorers /> every time leagueId changes and will only render one when leagueId is not falsy. I believe that's what you were trying to accomplish, technically 3.
Notes:
1 - to verify, use onUpdated(() => console.log('updated...'))
2 - use selectedLeague.value?.id.toString() if selectedLeague is a ref
3 - at the same time, I am sure the actual business requirement can be met without creating a new instance of <LeagueTopScorers /> every time leagueId changes, but I can't help more without more details and/or context

How to access and use a value from a child component on redux-form to make a checkbox work and enable conditionally rendered extra options

I'm using redux-form. I need to conditionally render extra options on user click of a checkbox in a child component.
I am able to do this on the parent file (in the SOW Type section of the form) using 'formValueSelector' (see sandbox: https://codesandbox.io/s/currying-cloud-isu8c) but on the third option in this section ('Custom Professional Services SOW') on clicking the checkbox I need to further condionally render some options on clicking the new checkbox that is exposed inside ('Customised Professional Services').
The file containing the code for the child component is 'CustomProfExtOptions'. What code do I need in this child component and/or the parent component in order to get this nested checkbox to work/enable conditional rendering on checking the box
I understand I need to access the value of the field in this child component on the form in order to manipulate it's state (mapStateToProps?) and allow the conditional rendering to work. I have done this successfully in the parent (as the sandbox shows) but I don't know how to get his working in the child component.
I have googled extensively on this for three days and tried to tweak other examples I have found to fit this specific problem (the greyed out text at the bottom of 'CustomProfExtOptions.js' where the child component code is held) but I've yet to find anything that works.
What is working so far:
The 'formValueSelector' code (as per the Redux-Form docs which allows access the values in the fields of the form) I am using in the parent container for the form (a file called 'PdfGenFormContainerRedux.js') is as follows:
PdfGenFormContainerRedux = reduxForm({
form: "StatementOfWorkApplication"
})(PdfGenFormContainerRedux);
const selector = formValueSelector("StatementOfWorkApplication");
PdfGenFormContainerRedux = connect((state) => {
const hasProductSowValue = selector(state, "productSOW");
const hasTeradataExtOptionsValue = selector(state, "teradata");
const hasCustomProfExtOptions = selector(state, "customExtOptions"); //selector created
return {
hasProductSowValue,
hasTeradataExtOptionsValue,
hasCustomProfExtOptions
};
})(PdfGenFormContainerRedux);
export default PdfGenFormContainerRedux;
This allows me to conditionally render the second hidden field on the click of the checkbox by using a variable called props.hasCustomProfExtOptions as demonstrated below:
<div className="checkbox-group">
<div>
<label className="checkbox-group">
<Field
name="customExtOptions"
className="form-checkbox"
component="input"
type="checkbox"
/>
Custom Professional Services SOW
{props.hasCustomProfExtOptions && ( //conditional rendering bit here
<div>
<Field
name="custProfServices"
type="input"
component={CustomProfExtOptions}
label="Custom Options Info"
placeholder="Location"
formId={formId}
/* hasProfServ={props.hasProfServ} */
/>
</div>
)}
</label>
</div>
</div>
</div>
This works fine on the parent container but how do I get it working on the checkbox labelled 'Customised Professional Services' in the child component? (the file called 'CustomProfExtOptions')
Just to add, i need any input from this nested section to be included in the final submission of the form.
Any help would be greatly appreciated

How to sort Column when data is cell rendering a component Angular 6

I'm using Ag-grid to try and have some data on screen nice and tidy and well organised, for one of my columns I have it set up so all of the cells have a component rendered in, a span and a div.
The Ag-grid lives within a modal and when that it opened I am using
this.gridColumnApi.getColumn('value').setSort("desc");
to set the sort to descending in order for it to come out how I planned. Now the Component in each cell looks like this.
<div class="d-flex">
<span>{{status}}</span>
<div class="data-block"
[class.example1]="status === 'exampleValue1'"
[class.example2]="status === 'exampleValue2'"
[class.example3]="status === 'exampleValue3'"
[class.example4]="status === 'exampleValue4'">
</div>
I still need to and sort by the text value but unsure how to as now the sort functionality does not work.
I have tried calling the setSort functions on the API but cant work out how to achieve the required outcome. Any way on how people have managed to sort cell rendered components would be awesome.
To achieve expected result , use below option of using setSortModel method instead of setSort
const defaultSortModel = [
{colId: "value", sort: "asc"},
];
this.gridOptions.api.setSortModel(defaultSortModel);

To limit number of items to be displayed in react predictive input

Implementing React from couple of months. I used 'react-predictive-input' for predicting items from the pre-defined list on onchange event.
With "large" data sets (500/1000 items) the AutoComplete component becomes very slow especially when typing the first 3 characters because it will render many items in the dropdown slowing the entire interface, even using a maxHeight for the component.
Do we have any attribute as 'max-items' to show from the list?
Below is the snippet of code :
<Autocomplete
id="items"
placeholder="My Items"
data={this.props.items}
onSelected={this.onItemSelected.bind(this)} />
Function is invoked if item is selected
onItemSelected(value){
console.log(`${value} was selected`);
}
List of items
static defaultProps = {
items:[
'car','Bicycle','Truck','Green Van'............................1000items]
};
Text prediction works fine, speed and display are becoming an issue to handle.
I used Material UI Autocomplete for retrieving the use cases mentioned in the question. Link for reference here.

Angular 2 change template input values on click

Working with a set of column components with id input in my template:
<div class="panel-body" *ngIf="columns">
<div class="col-md-4">
<column [id]=columns[current_left_column].Id></column>
</div>
<div class="col-md-4">
<column [id]=columns[current_middle_column].Id></column>
</div>
<div class="col-md-4">
<column [id]=columns[current_right_column].Id></column>
</div>
</div>
I have buttons that increment and decrement the columns by changing the values of current_left_column, current_middle_column, and current_right_column. When I click those buttons I log the values of the three column id's and they're representative of where they should be however the template doesn't reload.
I did attempt to use ApplicationRef.tick() to trigger change detection, but the fact that it didn't change makes me think it's a binding issue, but I'm thus far unable to find anything that matches my case as 2-way binding seems to necessitate a more traditional input element and it currently is one way bound.
I think you need to change the name of the input. I have seen it several times that it collides with the id property every HTML element has.
I really appreciate the comments and info given, it helped me get a better handle on what I was actually trying to do.
I ended up taking an example from a different answer and using ngModel with an input to show the individual column id's. Then since I could prove my id's were switching but it wasn't updating even with the tick() I realized I was working on one component level too high and had to be initiating the change from the Column level. So I took the ngOnInit method that populates the columns with data and put it in a ngOnChanges() method, cleared the OnInit() because it was doubling up, and it started moving fine.
Then I had to deal with the information from the columns being added on top of the prior column, but that was relatively minor.
ngOnChanges(){
this._columnService.GetSingleColumn(this.id).subscribe(column => { this.columnData = column; });
this._cardService.GetCardsByColumnId(this.id).subscribe(cards => { this._cardColumnService.LoadCards(cards); console.log(this.cards); });
if (this.columnData == undefined) {
this.LoadDummyData();
}
}

Categories

Resources