1

I am getting the data from api. I am displaying Feature ID, DisplayOrder textbox in the rows. User can change the Display Order value in the multiple rows. How to update the information using Post API? I am passing one value FeatureID and DisplayOrder in form submit. Please help to pass all the values that are changed(FeatureID, DisplayOrder) in form submit. If suppose FeatureID 11 and FeatureID 13 Display order changes, then form submit needs to pass these information only. enter image description here

{"FeatureID":"11","DescriptionText":"Travel","FeatureText":Feature2,"DisplayOrder":"1","Date":"08/30/2011","FeatureName":"Research"},
{"FeatureID":"12","DescriptionText":"Sport","FeatureText":Feature3,"DisplayOrder":"2","Date":"08/30/2011","FeatureName":"Research"},
{"FeatureID":"13","DescriptionText":"Art","FeatureText":Feature4,"DisplayOrder":"3","Date":"08/30/2011","FeatureName":"Research"}]
import React from "react";
export class EditFeatures extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      FeatureID: "",
      DisplayOrder: "",
      DescriptionText: "",
      FeatureText: "",
      Feature: [],
    };
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  componentDidMount() {
    this.DisplayFeatures();
  }
  DisplayFeatures() {
    fetch(REQUEST_URL, { "Content-Type": "application/xml; charset=utf-8" })
      .then((response) => response.json())
      .then((data) => {
        this.setState({
          Feature: data,
          loading: false,
        });
      });
  }
  handleSubmit(event) {
    event.preventDefault();
    const FeatureID = this.state.FeatureID;
    const DisplayOrder = this.state.DisplayOrder;
    const data = {
      FeatureID,
      DisplayOrder,
    };
    fetch(REQUEST_URL, {
      method: "POST",
      body: JSON.stringify(data),
      headers: { "Content-Type": "application/json" },
    })
      .then((response) => response.json())
      .catch((error) => console.error("Error:", error))
      .then((response) => console.log("Success", data));
    window.location.href = "/";
  }
  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <table>
            <tbody>
              {this.state.Feature.map((item, index) => {
                return [
                  <tr key={item.FeatureID}>
                    <td>
                      <input
                        type="text"
                        id={item.FeatureID}
                        name="DisplayOrder"
                        value={item.DisplayOrder}
                        onChange={(ev) => {
                          const newFeature = this.state.Feature.map((f) => {
                            if (f.FeatureID == ev.target.id) {
                              f.DisplayOrder = ev.target.value;
                            }
                            return f;
                          });
                          this.setState({ Feature: newFeature });
                        }}
                      />
                    </td>
                    <td>{item.DescriptionText}</td>
                    <td>{item.FeatureTex}</td>
                  </tr>,
                ];
              })}
            </tbody>
          </table>
          <button type="submit" name="submit">
            Update
          </button>
        </form>
      </div>
    );
  }
}
export default Edit_Features;
TestUser
  • 247
  • 1
  • 13
  • It's better to use a tool like `prettier` to beatify JavaScript code to make it more readable, you can add prettier as a plugin to VS Code – niceman Aug 13 '22 at 15:28
  • your JSX is wrong, you have two `` but only one `
    `, maybe remove the first `
    `?
    – niceman Aug 13 '22 at 15:30
  • Also, `{tem.FeatureTex}`, shouldn't it be `{item.FeatureTex}` – niceman Aug 13 '22 at 15:32
  • Updated FeatureText mistake also. – TestUser Aug 13 '22 at 15:33
  • https://stackoverflow.com/questions/8572826/generic-deep-diff-between-two-objects – niceman Aug 13 '22 at 15:35
  • Oh, and your input's onChange actually changes state directly in `f.DisplayOrder = ev.target.value;`, the correct way is to clone state first like this: `const newFeature = {...this.state.Feature}`, then use the function `findIndex` on `newFeature` instead – niceman Aug 13 '22 at 15:38
  • Looked the link, not able to understand how to fix my code. Please modify the code so that form submit will work for multiple row changes. DisplayOrder textbox values for multiple FeautureID's how to pass the changed data in form submit – TestUser Aug 13 '22 at 15:38
  • Isn't your example wrong? If Feature ID 11 and 13 changed, why are we passing feature ID 12 to server? – niceman Aug 13 '22 at 15:53
  • Suppose the GetAPi returns 10 rows. I need to display all 10 rows with their DisplayOrder information in the textbox. DisplayOrder is kind of arranging the data by putting the number. Lowest order item will be on the top. How to update the order of the rows if multiple rows DisplayOrder change. – TestUser Aug 13 '22 at 16:04
  • What is the order of items on UI, and what is the order of items in data posted to server? – niceman Aug 13 '22 at 16:12
  • DisplayOrder. Lowest DisplayOrder row will be at the top, highest will be at the bottom. Example Modified data after form submit. User changed the order of three items 12,13,14. Updated row will display like this. ``` [{"FeatureID":"10","DisplayOrder":"0"}, {"FeatureID":"12","DisplayOrder":"12"}, {"FeatureID":"14","DisplayOrder":"15"}, {"FeatureID":"13","DisplayOrder":"19"}] ``` – TestUser Aug 13 '22 at 16:18
  • Added an image with the original post. Data will be ordered according to DisplayOrder – TestUser Aug 14 '22 at 02:55

1 Answers1

0

The answer is simple, just sort Feature array on DisplayOrder in handleSubmit like this:

import React from "react";
export class EditFeatures extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      FeatureID: "",
      DisplayOrder: "",
      DescriptionText: "",
      FeatureText: "",
      Feature: [],
    };
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  componentDidMount() {
    this.DisplayFeatures();
  }
  DisplayFeatures() {
    fetch(REQUEST_URL, { "Content-Type": "application/xml; charset=utf-8" })
      .then((response) => response.json()) // you passed Content-Type: "application/xml" as request header but here you use response.json, remove Content-Type header if server API returns json
      .then((data) => {
        this.setState({
          Feature: data.map((feature) => ({ ...feature, changed: false })),
          loading: false,
        });
      });
  }
  handleSubmit(event) {
    event.preventDefault();
    const FeatureID = this.state.FeatureID;
    const DisplayOrder = this.state.DisplayOrder;
    const Feature = this.state.Feature;
    const data = {
      FeatureID,
      DisplayOrder,
      Feature, // this is how you pass an array to server, how will the server deserialize this depends on the framework used there
    };
    const self = this;
    fetch(REQUEST_URL, {
      method: "POST",
      body: JSON.stringify(data),
      headers: { "Content-Type": "application/json" },
    })
      .then((response) => response.json())
      .catch((error) => console.error("Error:", error))
      .then((response) => {
        /**
         * sort manipulates the array so we clone the Feature array before sorting it
         * we pass comparator function to sort so that we sort on DisplayOrder
         */
        const newFeature = [...this.state.Feature];
        newFeature.sort((f1, f2) => f2.DisplayOrder - f1.DisplayOrder);
        self.setState({ Feature: newFeature });
      });
    window.location.href = "/"; // ok why does this exist?!!
  }
  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <table>
            <tbody>
              {this.state.Feature.map((item) => {
                return [
                  <tr key={item.FeatureID}>
                    <td>
                      <input
                        type="text"
                        id={item.FeatureID}
                        name="DisplayOrder"
                        value={item.DisplayOrder}
                        onChange={(ev) => {
                          // this is the proper way to update an element inside an array
                          const newFeature = [...this.state.Feature];
                          // I prefer === over == to avoid errors
                          const featureIndex = newFeature.findIndex(
                            (f) => f.FeatureID === ev.target.id
                          );
                          newFeature[featureIndex].DisplayOrder =
                            ev.target.value;
                          this.setState({ Feature: newFeature });
                        }}
                      />
                    </td>
                    <td>{item.DescriptionText}</td>
                    <td>{item.FeatureTex}</td>
                  </tr>,
                ];
              })}
            </tbody>
          </table>
          <button type="submit" name="submit">
            Update
          </button>
        </form>
      </div>
    );
  }
}
export default EditFeatures;

this way when you click button submit, if the POST request to the server succeeds, the table will be updated according to DisplayOrder.

Note

If the request to the server fails for any reason the table won't be updated, if you don't care about the response of the server just sort the Feature array outside the .then before issuing the request.

niceman
  • 2,653
  • 29
  • 57
  • Thanks. When user click on Submit button, component will refresh and items will display in the sorter order in UI (DisplayOrder). How form submit will work, it will send all the featureid's whether its changed or not changed. – TestUser Aug 13 '22 at 16:41
  • === over == SonarQube gives error for === . – TestUser Aug 13 '22 at 16:43
  • I have problem with Form Submit. How form submit handles this requirement? How form submit will pass this information in post api(featureid, displayorder). – TestUser Aug 13 '22 at 17:16
  • I didn't understand this requirement from your comments and question, As I asked you before why feature ID 12 is included in your example in the question if it's not changed @TestUser – niceman Aug 13 '22 at 21:52
  • As for SonarQube hmm I always prefer `===`, don't know why it prefers `==`, you can configure it or just follow it – niceman Aug 13 '22 at 21:53
  • On Page load, we need to display all features with their current DisplayOrder. DisplayOrder is used for arranging the features. User can change the order by putting number in the DisplayOrder Textbox. Click update will update the information in the database. As soon as the update button will click, all the features are sorted with the new DisplayOrder. – TestUser Aug 14 '22 at 01:54
  • Added a picture with the original post. Features are displayed accoridng to DisplayOrder on page load and after form submit. – TestUser Aug 14 '22 at 03:24
  • @TestUser so now I understand your requirement, but what is `this.state.FeatureID`? I don't see its usage any place except in handleSubmit, also the same for `this.state.DisplayOrder` – niceman Aug 14 '22 at 07:35
  • FeatureID is the primary key of the item in database, DisplayOrder is some number that is given to that item in the textbox, its another column in the database. Its the number that tells which order user wants to display that item on UI. – TestUser Aug 14 '22 at 13:17
  • What item? @TestUser – niceman Aug 14 '22 at 13:32
  • These are three records/items in the database. FeatureID is the primary key. For FeatureID 11, DisplayOrder = 1,[{"FeatureID":"11","FeatureText":Feature2,"DisplayOrder":"1","Date":"08/30/2011","FeatureName":"Research"}, {"FeatureID":"12"","FeatureText":Feature3,"DisplayOrder":"2","Date":"08/30/2011","FeatureName":"Research"}, {"FeatureID":"13","FeatureText":Feature4,"DisplayOrder":"3","Date":"08/30/2011","FeatureName":"Research"}] – TestUser Aug 14 '22 at 13:57
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/247262/discussion-between-testuser-and-niceman). – TestUser Aug 14 '22 at 14:30
  • Please help how to handle form submit. – TestUser Aug 14 '22 at 17:39
  • @TestUser tell me difference between `this.state.FeatureID` and `this.state.Feature.id`? – niceman Aug 14 '22 at 18:16
  • Code is just having this.state.FeatureID. I am not finding this.state.Feature.id – TestUser Aug 14 '22 at 20:38
  • I meant the ID of items inside the `this.state.Feature` array @TestUser – niceman Aug 14 '22 at 20:55
  • It is FeatureID. Every row is related to FeatureID. – TestUser Aug 14 '22 at 21:09
  • What is the relationship between every row's FeatureID and `this.state.FeatureID` – niceman Aug 14 '22 at 21:45
  • Thanks Niceman, i tried the solution. Its not working . After button submit, rows still display in the original order, not with the new displayorder. Also post api, how to send the information. I do not know how to send multiple rows data in post form submit. thanks – TestUser Aug 15 '22 at 04:34
  • @TestUser updated the answer, you can see in code how to pass rows to server, as for why didn't it work did the request to server throw an error? see my note in the answer – niceman Aug 15 '22 at 09:16
  • Niceman, please help in finding the solution of this new post https://stackoverflow.com/questions/73479244/react-how-to-show-delete-confirmation-alert-on-button-click? – TestUser Aug 25 '22 at 14:11
  • Hi Niceman, would you please help me in finding the solution for this post: https://stackoverflow.com/questions/73612264/react-how-to-replace-unordered-list-bullets-with-images-in-the-treeview – TestUser Sep 06 '22 at 06:08