adding fields to a redux form inside the component - redux-form

So I have a React component (called Contract) which is being fed to the reduxForm function. It's been given an array of field names (the fields property shown below) which will be part of the form.
export default reduxForm({
form: 'Contract',
fields
}, mapStateToProps)(Contract);
But while this component is being created, there is data (additional field names) being loaded from a server which will need to be appended to this list. That data may not load in time. Is it possible to dynamically update the list of fields and make them part of the form after this component has been created? Can it be updated inside the Contract component or is it that once this component has been created the list of fields is set in stone?

I'm assuming you're using version 5 or earlier since you've got a fields config. You can make your fields dynamic by passing a fields prop to your form component instead of configuring them in reduxForm. (See docs)
I used a stateful component in this example to fetch the fields but you could also of course use a redux-connected component.
class ContractContainer extends Component {
state = { fields: [] };
componentDidMount() {
fetchData().then(fields => {
this.setState({ fields });
}
}
render() {
<Contract fields={[...staticFields, ...this.state.fields]} />
}
}

Related

Subscribing to valueChanges for multiple fields is causing performance issue in reactive form angular 2

I have more than 50 fields those are input text and dropdowns in the reactive form. The fields are dependent to each other's value changes in order to trigger validation and to display related field after the selection.
I subscribed to the value changes in ngOnInit() as below:
ngOnInit() {
this.setPageValidation();
}
setPageValidation() {
this.NameSubscription = this.FormGroup.get('personnel').get('name').valueChanges.subscribe(data
=> {
this.enableOrders();
});
this.StateSubscription = this.FormGroup.get('personnel').get('state').valueChanges.subscribe(data
=>
{
this.enableAccount();
});
// more value changes subscription like 40 fields ............................
}
While loading the form, it is taking longer time to load due to subscribing for the value changes when the form loads.
I tried implementing it to move the code to ngOnChanges() but it is not triggering the enable and display of other fields depending on it's initial value that are filled from the table if there are values for those fields. It is just populating the first field and the rest does not display depending upon on its value.
I would like to thank you in advance. I really appreciate your help if there is any best approach to it to resolve without performance issue.
You can do with a single subscription.
this.personnelSubscription =
this.Formgroup.get('personnel').valueChanges.subscribe(data => {
if (data) {
//Console log the data here. It will print the formGroup of personnel
// then select the control and add your validations
// like this data.controls.state
}
})

GraphQL retrieve data for specific blocks - Gatsby + Wordpress

I have a React + Gatsby JS project that retrieves data from a Wordpress site through their headless API. I'm a total newbie to Gatsby.
Every page on my site is made up of blocks, which are in turn made up of fields. I'm using ACF to build these.
I am currently able to retrieve every page and a list of the blocks within that page by using the following GraphQL query:
query ($id: String!) {
currentPage: wordpressPage(id: {eq: $id}) {
title
acf {
page_blocks {
block_type {
acf_fc_layout
}
}
}
}
}
This returns the following data for page with id f4c4f4a7-ba0d-55b1-8877-16f543c22b80
{
"data": {
"wordpressPage": {
"id": "f4c4f4a7-ba0d-55b1-8877-16f543c22b80",
"acf": {
"page_blocks": [
{
"block_type": [
{
"acf_fc_layout": "page_title_and_text"
},
{
"acf_fc_layout": "two_column_media_and_text"
}
]
}
]
}
}
}
}
The blocks are next to afc_fc_layout. Both page_title_and_text and two_column_media_and_text are page blocks in that page.
Now, I would think that the next step would be to make a React component for each of those blocks, passing in the custom field data for each, to that component. If a page doesn't have a block, then there wouldn't be a need for me to retrieve the fields for that block, right?
Initially I thought I would run another query from my React component, requesting the fields for that particular block. But I realized I can't really add variables (page Id) to a static query within my components, per Gatsby docs, so I wouldn't be able to query that specific page for its fields. Please correct me if I'm wrong.
I believe I have to retrieve those fields I need from my main query that I've shown you here, but it seems absolutely bonkers to have to query for every possible custom field on the site, when not all pages are going to have the same blocks.
Ideally there would be some sort of syntax like
...
acf {
page_blocks {
block_type {
acf_fc_layout
if (acf_fc_layout eq page_title_and_text) {
title
text
}
if (acf_fc_layout eq two_column_media_and_text) {
media
text
}
}
}
}
...
And then I would pass those fields to their corresponding React component.
What is the proper way to go about this?
Note: I am currently at the point where I'm able to retrieve the fields from the API to render blocks. I am more wondering if there is any way my graphQL query can filter out the data for me, or if there is a way to customize the WP endpoint to show me field data filtered by the blocks that are actually on the page.
Ex: the site queries the data in blocks 4,3,2,10,12,15.... even though the page only has block 2.
I'm worried that devs that want to add blocks in the future will have to rewrite the query each time, hurting the site's scalability and potential performance.
You say you are a beginner with Gatsby but what you are trying to do touches many advanced topics inside Gatsby. My answer is most likely incomplete and you will need to figure many things out for yourself.
Prepare yourself for lots of documentation reading and lots of debugging to get things to work with Gatsby.
You want to programmatically create pages depending on the result of your GraphQL query. That means you need to create a page wide page template component.
In your templates folder of your Gatsby project, you create one template that programmatically picks the right components for each of your routes. To get your ACF data you use GraphQL page queries.
What is the proper way to go about this?
One alternative is this: You create React components that retrieve their data via props. You don't need to give each of those components their own GraphQL query since you already query in your page templates.
acf: acf_fc_layout eq page_title_and_text -> React component PageTitleAndText.jsx
const PageTitleAndText = ({ title, text}) => {
return (
<div>
<h1>{title}</h1>
<p>{text}</p>
</div>
);
};
// NO GraphQL query
export default PageTitleAndText;
Instead, you pass props inside your page template to your component:
acfPageTemplate.jsx
const acfPageTemplate = (props) => {
return (
<div>
{/* pass props as data from the GraphQL query result here */}
<PageTitleAndText title={props.data.currentPage.acf.page_blocks.block_type.acf_fc_layout.title }
text ={props.data.currentPage.acf.page_blocks.block_type.acf_fc_layout.text} />
</div>
);
};
export const query = graphql`
query ($id: String!) {
currentPage: wordpressPage(id: {eq: $id}) {
title
acf {
page_blocks {
block_type {
acf_fc_layout
}
}
}
}
}
`;
export default acfPageTemplate;
Define a page template for each of your acf layouts. Pick the right components for each layout and pass props as data from the GraphQL query result.
You need to pass variables to your page query. The only way to do this is to use page context as described in this question:
gatsby-node.js
createPage({
path: `/my-acf-page-title-and-text-page/`,
component: path.resolve(`./src/templates/PageTitleAndText.jsx`),
// The context is passed as props to the component as well
// as into the component's GraphQL query.
context: {
id: acfFieldId, // pass the acf field id
},
})
// define a createPage action for each of your acf layouts
But I realized I can't really add variables (page Id) to a static query within my components, per Gatsby docs, so I wouldn't be able to query that specific page for its fields. Please correct me if I'm wrong.
Correct. That's why you need to go the way with a page query, page template, and page context variable in gatsby-node.js
If a page doesn't have a block, then there wouldn't be a need for me to retrieve the fields for that block, right?
Yes. That's why you create a different page template for each of your acf layouts. You can create one big tempalte for all layouts but then you need to programmatically decide what components to add. This is out of scope of this question. You should ask a new question if you want to do this.
My advise is to get this to work with one specific layout before you go down this next rabbit hole, if you decide to do this at all.

How can I clear all validators when a user clicks on a boolean, then reapply all validators when a user selects another boolean value

My application is in angular 7 and is essentially one giant form spread across several components.
In one section, when a user clicks on a boolean input and selects 'Yes', it should disable all validators in a sibling component. If the user selects 'No' on the same boolean input, it should reapply all validators to that sibling component (this includes custom validators).
Currently, we are able to clear all validators on one selection, however, when the user selects the other boolean value, the validators are not reapplied.
How can we modify these methods so that this can be achieved?
Here is a snippet of the TS file that should clear or apply the validators to each form group:
getSkipLogic() {
this.skipLogicService.getSkipLogic().subscribe(data => {
(data || []).forEach(item => {
if(item.toQuestion === 'check46') {
this.item46 = item.values
}
if(item.toQuestion === 'check47') {
this.item47 = item.values
}
});
});
}
// clears validators for all controls in a form group
clearValidation(group: FormGroup){
Object.keys(group.controls).forEach((key: string) => {
const abstractControl = group.get(key);
abstractControl.clearValidators();
})
}
// clear validation for parent financial form groups if user selects 'yes'
for any questions 46-58 in the student dependency section
validationCheck() {
if((this.item46 ===true) || (this.item47 === true)) {
this.clearValidation(this.financialSectionOne);
this.clearValidation(this.financialSectionTwo);
this.clearValidation(this.financialSectionThree);
this.clearValidation(this.financialSectionFour);
this.clearValidation(this.financialSectionFive);
this.clearValidation(this.financialSectionSix);
}
this.financialSectionOne.updateValueAndValidity();
this.financialSectionTwo.updateValueAndValidity();
this.financialSectionThree.updateValueAndValidity();
this.financialSectionFour.updateValueAndValidity();
this.financialSectionFive.updateValueAndValidity();
this.financialSectionSix.updateValueAndValidity();
}
What we want to happen is, when the user selects 'Yes' on the boolean input field, it should clear all validators for the form group on the sibling component. If they select 'No', it should reapply all validators to the sibling component.
For reapplying the validators you can make use of setValidators method in form control. As you have clearValidators function, you can have another functoin called setValidation() function where you can set respective validators on your form Control keys. For example,
//sets validation for form control
setValidation(){
this.finanacialSectionOne.controls['<any Value in this control>'].setValidators([Validators.minLength(1), Validators.maxLength(30)]);
this.financialSetionTwo.control['<any value in this control>'].setValidators(Validators.required);
.
.
do the same for all the controls.
}
You can refer this link for more clarification - https://angular.io/api/forms/AbstractControl

Spring boot + JPA(Hibernate) Edit partial entity fields

all.
I have following simple form in which I want to edit the entity. The problem is that I have some fields which I don't want to be edited. For example (Image file path).
As it is now, I have the service method -
public void addOrModifyLayout(Layout layout){
if(layout.getId() == null){
layoutRepository.save(layout);
}
else {
Layout modifiedLayout = new Layout();
modifiedLayout.setId(layout.getId());
modifiedLayout.setName(layout.getName());
modifiedLayout.setStatus(layout.getStatus());
modifiedLayout.setExhibitor(layout.getExhibitor());
layoutRepository.save(modifiedLayout);
}
}
As you can see, every field that I want to be able to be edited, I should explicitly put it in the service. Can I use some mapper or trick to update only some fields that are in the view (form) ? How you handle this kind of issues?
You can either
store all the entity fields in hidden inputs (e.g. imageFilePath hidden input). So you can store on UI all the entity fields and get them back to assign to the entity.
OR
Avoid new entity creation but retrieve existing one and fill only necessary fields.
Layout modifiedLayout = layoutRepository.getById(layout.getId());
modifiedLayout.setName(layout.getName());
modifiedLayout.setStatus(layout.getStatus());
modifiedLayout.setExhibitor(layout.getExhibitor());
layoutRepository.save(modifiedLayout);

Extjs: What is the correct way to use Associate Data of a model's field reference?

The Ext.data.Model class represents the backend models. And just like in the server code, some of its fields can be of another declared model type via the reference property. I've found out that using a model's getAssociatedData() function returns an object with all those referenced fields. However they only contain the reference object's data object they are not full fledged initialized Ext.data.Models, which forces a primitive object access and there is no way to use the model's configured proxies etc for loading/saving. Is this the correct/only way of using this functionality? We've also been looking for a way to add columns from referenced fields on a grid but it doesn't seem to work... I'm starting to doubt the usefulness of declaring referenced fields.
Example code:
Ext.define('MyApp.ModelA', {
extend: 'Ext.data.Model',
fields: [{
name: 'modelb',
reference: 'MyApp.ModelB'
}]
});
Ext.define('MyApp.ModelB', {
extend: 'Ext.data.Model',
fields: [{
name: 'modelId',
type: 'int'
}]
});
//...
var modelA = new MyApp.ModelA().load();
var modelB = modelA.getAssociatedData().modelb; //This is the only way to access it.
var modelBId = modelB.get('modelId') //This returns undefined because the function .get doesn't exist.
var modelBId = modelB.id; //This works because it is a simple object property access.
//...
As Chad Peruggia said, it seems that ExtJS creates special getters for reference fields that match the field name. Using getAssociatedData() returns only the primitive form of those objects (only their data values) but using the special getter (in my case getModelb()) it returns a full fledged model initialized with the given data.

Resources