dns_nx
dns_nx

Reputation: 3943

Fill state property after ajax request

I've got an issue with React.js. I want to add another property (productGroups) to an existing state (this.state.mainProductGroups - type object array). So I want to find out the corresponding entry in the array and add the new property to it.

This is my function:

getProductGroups(mainProductGroupId) {
    $.ajax({
        type: "POST",
        context:this,
        dataType: "json",
        async: true,
        url: "ajax.php",
        data: ({ 
            requestType: 'getProductGroups',
            countryID: this.state.countryObject.countryNo,
            languageID: Language[this.state.currentLanguage].languageNo,
            mainProductGroupID: mainProductGroupId,
        }),
        success: function (data) {
           let mainProductGroups = this.state.mainProductGroups;
           let mainPGFound = false;
           let mainPG = mainProductGroups.filter(mainProductGroup => mainProductGroup.id == mainProductGroupId);
           mainPG.productGroups = data.productGroups;
           this.setState({
              mainProductGroups: mainProductGroups,
           });
           
        }
    });
  }

Here is an data example of the this.state.mainProductGroups:

enter image description here

The issue is now, that the productsGroup property is not being filled. The ajax request returns correct values (also type object array). Why is it not being updated? Is there a problem, because the initial value of the property productGroups is string and now I want to overwrite this with a type of object array?

Upvotes: 0

Views: 76

Answers (4)

dns_nx
dns_nx

Reputation: 3943

My final solution is this one.

getProductGroups(mainProductGroupId) {
    $.ajax({
        type: "POST",
        context:this,
        dataType: "json",
        async: true,
        url: "ajax.php",
        data: ({ 
            requestType: 'getProductGroups',
            countryID: this.state.countryObject.countryNo,
            languageID: Language[this.state.currentLanguage].languageNo,
            mainProductGroupID: mainProductGroupId,
        }),
        success: (data) => {
          let mainProductGroups = this.state.mainProductGroups.map((mainProductGroup) => {
            if(mainProductGroup.id === mainProductGroupId) {
              mainProductGroup.productGroups = data.productGroups;
            }
            return mainProductGroup;
          });
          this.setState({
             mainProductGroups: mainProductGroups,
          });
        }
    });
  }

I think, the reason was that I did not change the state property mainProductGroups at all in my first solution. Now it is working fine. Thanks all for your help.

Upvotes: 1

MinimumViablePerson
MinimumViablePerson

Reputation: 81

Manoz is right about this losing context in a regular function. I would just like to take it a little further and actually extract that function into its own component method, so you'd end up with something like this:

updateMainProductGroups = data => {
   const { mainProductGroups } = this.state;
   const mainPG = mainProductGroups.find(mainProductGroup =>
        mainProductGroup.id === mainProductGroupId
   );
   mainPG.productGroups = data.productGroups;

   this.setState({ mainProductGroups });
}

getProductGroups(mainProductGroupId) {
    $.ajax({
        type: "POST",
        context: this,
        dataType: "json",
        async: true,
        url: "ajax.php",
        data: ({ 
            requestType: 'getProductGroups',
            countryID: this.state.countryObject.countryNo,
            languageID: Language[this.state.currentLanguage].languageNo,
            mainProductGroupID: mainProductGroupId,
        }),
        success: updateMainProductGroups
    });
}

Note: I removed this line let mainPGFound = false; which appears to not be used within this function, and I also changed filter to find, because you seem to be wanting to operate on a returned object, and filter will actually give you back an array with that object inside.

Upvotes: 1

Manoz
Manoz

Reputation: 6587

Change your success handler to this

 success: function (data) {}

from this

 success: (data)=> {}

See when you set state while writing function it is a new scope for this context in your callback. So it won't find this as this from the context. What you need is a lexical scoping with arrow function. Which is something you need in this case.

The problem here is

Typically if we’re writing ES5, we’ll use something like Function.prototype.bind to grab the this value from another scope to change a function’s execution context. This will mainly be used in callbacks inside a different scope.

see more here

Upvotes: 1

MaddEye
MaddEye

Reputation: 741

Change

this.setState({
    mainProductGroups: mainProductGroups,
});

to

this.setState({
   mainProductGroups: mainPG.productGroups
});

Upvotes: 0

Related Questions