简体   繁体   中英

Submitting a form in React via Ajax

My program works this way:

  1. You choose a video from select-option menu of videos.

  2. After appropriate video is selected(onChange event), list of subtitles for it are displayed in, again select-option menu for subs.

  3. After appropriate subtitle is selected(onChange event), a form with textarea, prefilled with text content from subtitle file.

This stuff works as advertised. Problem occurs when i submit(submit event) changed stuff in third form whom contains that textarea with text from subtitle. I need it to press submit button twice to submit updated content that need to be written to file.

Notice : It works only on second submit. Reading file and other stuff is done in Laravel and all works ok. Only this AJAX part is giving me the problems.

Here is my React component with AJAX code:

import React from 'react';
import ReactDOM from 'react-dom';

class Modsub extends React.Component {

    constructor(props) {

        super(props);
        this.state = {
            videos: null,
            subtitles: null,
            subText: null,
            subTextFormId: null,
        };
        this.select = this.select.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.getCkEditor = this.getCkEditor.bind(this);
        this.getSubText = this.getSubText.bind(this);
    }

    getSubText(e){

        this.setState({
            subText: e.target.value,
        });

    }

    getCkEditor(){
        console.log("got ckeditor");
        CKEDITOR.replace("ckeditor");
    }

    select(e){

        this.handleSubmit(e);

    }  

    handleSubmit(e) {
        e.preventDefault();

        let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
        let formId =  e.target.id==="subText" ?  e.target.id : e.target.parentElement.parentElement.id;
        let url = "";
        let formElements = {};
        let myformData = new FormData();

        if(formId==="videos"){

            url = "/modSubOfVideo";
            formElements.videoId = e.target.value;
            myformData.append('videoId', formElements.videoId);

        }

        if(formId==="subtitles"){
            url = "/openSubOfVideo";
            formElements.subId = e.target.value;

            this.setState({
                subTextFormId: formElements.subId,
            });

            myformData.append('subId', formElements.subId);

        }

        if(formId==="subText"){

            url = "/writeSubOfVideo";
            formElements.subId = e.target.elements[0].value;
            formElements.subText = e.target.elements[1].value;

            this.setState({
                subText: formElements.subText,
            });

            myformData.append('subText', formElements.subText);
            myformData.append('subId', formElements.subId);

        }

        myformData.append('_token', token);
        myformData.append('message', "bravo");

        $.ajax({
            url: url,
            enctype: 'multipart/form-data',
            type: 'POST',
            data: myformData,
            dataType: 'JSON',
            cache: false,
            contentType: false,
            processData: false,
            success: (response) => { 
                console.log("success");
                console.log(response);

                if(formId==="videos"){

                    this.setState({
                        subtitles: response.subtitles,
                    });
                }

                if(formId==="subtitles"){

                    this.setState({
                        subText: response.subText,
                    });
                    //this.getCkEditor();
                }

                if(formId==="subText"){

                    this.setState({
                        subText: response.subText,
                    });

                }

            },
            error: (response) => {

                console.log("error");
                console.log(response);

            }

        });

    }   

    componentDidMount(){
        //get all videos

        let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");

        $.ajax({
            url: '/addSubAjax',
            type: 'POST',
            data: {_token: token , message: "bravo"},
            dataType: 'JSON',

            success: (response) => { 

                console.log("success");
                //console.log(response);

                this.setState({
                    videos: response.videos,
                });

            },
            error: (response) => {

                console.log("error");
                //console.log(response);

            }

        });

    }

    render(){
        /*console.log("****");
        console.log(this.state);
        console.log("****");*/

        let videos = this.state.videos ? this.state.videos.map((item, index) => {

            return <option key={index} value={item.id}>{item.name.substr(0, 30)+"..."}</option>

        }) : null;

        let subs = this.state.subtitles ? this.state.subtitles.map((item, index) => {

            return <option key={index} value={item.id}>{item.name.substr(0, 30)+"..."}</option>

        }) : null;

        let subtitles = subs ? <form id="subtitles" encType="multipart/form-data">
                <div className="form-group">
                    <label htmlFor="subtitles">Choose sub to modify:</label>
                    <select className="form-control" id="subtitlesId" name="subtitlesId" onChange={this.select} required>
                        {subs}
                    </select>
                </div>
            </form>
        : "";

        let subTextPre = "<pre>"+this.state.subText+"</pre>";
        let subText = this.state.subText ? <form id="subText" onSubmit={this.handleSubmit} encType="multipart/form-data">
                <div className="form-group">
                    <input type="hidden" name="subId" value={this.state.subTextFormId}/>
                    <label htmlFor="subText">Modify subtitle:</label>
                    <textarea className="form-control" id="ckeditor" rows="5" onChange={this.getSubText} name="subTextId" defaultValue={subTextPre}/>
                </div>
                <button type="submit" className="btn btn-outline-primary">Submit</button>
            </form>
        : "";

        return (
            <div className="container">
                <form id="videos" encType="multipart/form-data">
                    <div className="form-group">
                        <label htmlFor="video">Choose video:</label>
                        <select className="form-control" id="videoId" name="videoId" onChange={this.select} required>
                            {videos}
                        </select>
                    </div>
                </form>

                {subtitles}

                {subText}

            </div>
        );

    }

}

if(document.getElementById('modsub')){

    ReactDOM.render(<Modsub/>, document.getElementById('modsub'));

}

Considering my previous questions, i'm probably don't seeing the obvious.... Despite that, if any of you kind souls would point me in the right directions, i would appreciate it. Mucho kudos in advance:D

EDIT1:

I kind a figured out what;s causing the problem. It was ckeditor envokement. By removing this.getCkEditor(); from condition in handleSubmit() method, it all works as it should be. But how to make it to work with ckeditor?

Sounds like an asynchronous issue. Try adding a callback to ckeditor so that you are ensuring the Axiom call is made after ckeditor is finished.

I finally figured it out. Of how to do it, not why it's happening. So, here it is:

Just before ajax call in handleSubmit method, i added

if(CKEDITOR.instances['ckeditor']){
  formElements.subText = CKEDITOR.instances['ckeditor'].getData();
  myformData.append('subText', formElements.subText);
}

to manually "rip" text content from ckeditor instance and set myformData with it. I don't know why or how, but it works. And by reading numerous posts and answers to them on numerous forums, i concluded is that this is just some of ckeditor quirks. Especially if you use it with ajax, let alone with more frameworks, frontend and backend alike.

Thanks everyone for the guidance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM