Pass some instructions to a function

半世苍凉 提交于 2021-01-29 14:43:17

问题


I'm trying to deduplicate a js code of major of form that do an ajax request, I initially do a php function that generate any form onsubmit function passing the different code as parameters but don't seems good. After I tried to a javascript function instead, for simple variables I did it working, for example:

// <script> inside of the page generate by php (and in some cases in html received by other ajax request)
$('#f_man-marker_edit-marker').on('submit', function(e){
    TM.editMarker(e, $(this), 'man-marker_edit-marker');
});

...
// in other js file
TM.editMarker = function (e, form, ajax_request) {
    // stop browser from submitting form!
    e.preventDefault();

    // Abort any pending request
    if (request) request.abort();

    // Let's select and cache all the fields
    let inputs = form.find("input, select, button, textarea");

    // Serialize the data in the form
    let serializedData = form.serialize();

    // Let's disable the inputs for the duration of the Ajax request.
    // Note: we disable elements AFTER the form data has been serialized.
    // Disabled form elements will not be serialized.
    inputs.prop("disabled", true);

    request = $.ajax({
        url: "ajax.php?req=" + ajax_request,
        type: "post",
        data: serializedData,
        dataType: "html"
    });

    request.done(function (response) {
        $("#ajaxoutput2").empty().append(response);
        $("#ResultModal2").modal("show");
    });

    request.fail(function (jqXHR, textStatus, errorThrown) {
        console.error(
            "Ajax " + ajax_request + " request failed. The following error occurred: " +
            textStatus, errorThrown
        );
    });

    request.always(function () {
        inputs.prop("disabled", false);
    });

};

Now is missed pass request.done instructions as parameter but I not found a good and working way to do it. Put them in a function gave me the variable response not defined, also adding it as parameter. More exactly I tried:

$('#f_man-marker_edit-marker').on('submit', function(e){
                    let req_done = function (response) {
                        $("#ajaxoutput2").empty().append(response);
                        $("#ResultModal2").modal("show");
                    };
                    TM.editMarker(e, $(this), 'man-marker_edit-marker', req_done());
                });

...
// in other js file
TM.editMarker = function (e, form, ajax_request, req_done()) {
...
    request.done(function (response) {
        req_done(response);
    });
...
};

Thas is not working. Is possible to pass the instructions as they are and have them working or must be in a function? If must be in a function what is the right way to do it? Probably is possibile with eval() but seems highly discouraged and I not tried it for now.

EDIT: I try to explain better: what I try to do is have a php or js function to call and pass as parameters the only things that changes, for example on on hundreds of similar forms that I will do on the project it will be fine there will be thousands or tens of thousands of lines of duplicate code avoided and a possible refactor or future improvements much simpler and faster. I started with a generation from php, for example:

...
// "f_man-marker_add-marker" is the id of the form, "man-marker_add-marker" is the id of the ajax request, $man_marker_jap1 contain that instructions printed inside of request.done function (they can be different on any form)

TM\UI\JSHelper::jqueryAjaxPost(
            "f_man-marker_add-marker", "man-marker_add-marker", $man_marker_jap1);

.....
// in the file of TM\UI\JSHelper:

...
/**
     * Generate a jquery ajax of type post and datatype html
     * will call the url ajax.php?req=$request_name
     * and request.done will do what define in $done_content
     *
     * @param string $form_id Id of the form
     * @param string $request_name Name of the ajax request parameter
     * @param string $done_content Content of request.done
     */
    public static function jqueryAjaxPost(string $form_id, string $request_name, string $done_content){
        echo <<<HTML

$("#$form_id").submit(function(event){

    // Prevent default posting of form - put here to work in case of errors
    event.preventDefault();

    // Abort any pending request
    if (request) { request.abort(); }

    let form = $(this);

    // Let's select and cache all the fields
    let inputs = form.find("input, select, button, textarea");

    // Serialize the data in the form
    let serializedData = form.serialize();

    // Let's disable the inputs for the duration of the Ajax request.
    // Note: we disable elements AFTER the form data has been serialized.
    // Disabled form elements will not be serialized.
    inputs.prop("disabled", true);

    request = $.ajax({
        url: "ajax.php?req=$request_name",
        type: "post",
        data: serializedData,
        dataType: "html"
    });

    request.done(function (response){
        $done_content
    });

    request.fail(function (jqXHR, textStatus, errorThrown){
        console.error(
            "Ajax $request_name request failed. The following error occurred: "+
            textStatus, errorThrown
        );
    });

    request.always(function () {
        inputs.prop("disabled", false);
    });

});

HTML;
    }

but not have js "issue" (if done correctly) because the generated code is specific per form and "full js" without call to other external functions. I then thinked to do it mainly in js only file (which to logic would seem more correct rather generate all the js from php) and was ok except of the content of request.done that must change, so I open this post to aswer what is the best and correct way to do it. If instead there is no better method to do what I need mainly in js and the less worst seems to remain in the php generation tell me.

EDIT2: I did other tests and found a working solution without using eval (I don't know if good):

// inside a <script> of part of page generated by php or html code received from ajax request
$('#f_man-marker_edit-marker').on('submit', function(e){
    let req_done = function (response) {
        $("#ajaxoutput2").empty().append(response);
        $("#ResultModal2").modal("show");
    };
    TM.jqueryAjaxPost(e, $(this), 'man-marker_edit-marker', req_done);
});

...
// in other js-only file
/**
 * Basic jquery ajax request of type post from form
 * where changes only request.done content
 * @param e Event received from onsubmit of the form
 * @param form Receive the element with $(this)
 * @param ajax_request Name of the ajax request send to php
 * @param req_done Instruction to do on request.done
 */
TM.jqueryAjaxPost = function (e, form, ajax_request, req_done) {

    // stop browser from submitting form!
    e.preventDefault();

    // Abort any pending request
    if (request) request.abort();

    // Let's select and cache all the fields
    let inputs = form.find("input, select, button, textarea");

    // Serialize the data in the form
    let serializedData = form.serialize();

    // Let's disable the inputs for the duration of the Ajax request.
    // Note: we disable elements AFTER the form data has been serialized.
    // Disabled form elements will not be serialized.
    inputs.prop("disabled", true);

    request = $.ajax({
        url: "ajax.php?req=" + ajax_request,
        type: "post",
        data: serializedData,
        dataType: "html"
    });

    request.done(function (response) {
        req_done(response);
    });

    request.fail(function (jqXHR, textStatus, errorThrown) {
        console.error(
            "Ajax " + ajax_request + " request failed. The following error occurred: " +
            textStatus, errorThrown
        );
    });

    request.always(function () {
        inputs.prop("disabled", false);
    });

};

Is this good or is there a better way to do it and/or possible improvement?

EDIT3: I tried also to do something working with additional parameters:

TM.deleteMarker = function (id) {
    let req_done = function (response, parArray) {
        $("#ajaxoutput").empty().append(response);
        $('#link_open-marker' + parArray[id]).remove();
    };
    TM.jqueryAjaxGet('man-marker_delete-marker&id=' + id, req_done, {id: id});
};

/**
 * Basic jquery ajax request of method get and datatype html
 * @param ajax_request Name of the ajax request send to php and get parameters, it will be
 * will be added to the end of the url
 * @param req_done Instruction to do on request.done
 * @param parArray Additional parameters used in req_done
 */
TM.jqueryAjaxGet = function (ajax_request, req_done, parArray = {}) {
    // Abort any pending request
    if (request) {
        request.abort();
    }

    request = $.ajax({
        url: "ajax.php?req=" + ajax_request,
        method: "get",
        dataType: "html"
    });

    request.done(function (response) {
        req_done(response, parArray);
    });

    request.fail(function (jqXHR, textStatus, errorThrown) {
        console.error(
            "Ajax " + ajax_request + " request failed. The following error occurred: " +
            textStatus, errorThrown
        );
    });
};

don't gave errors or warning and work all except

$('#link_open-marker' + parArray[id]).remove();

so I suppose I did something wrong about parArray but I not undestand what, Can someone help me to solve (or do in a different way if not good this) please?

Thanks for any reply and sorry for my bad english.


回答1:


I'm not quite sure if i understood your question right, but if its about getting a done callback outside of your method you have two possible ways of doing that.

Use closures:

TM.editMarker = function (e, form, ajax_request, doneHandler) {
   ...

   request.done(function (response) {
        $("#ajaxoutput2").empty().append(response);
        $("#ResultModal2").modal("show");

        if(doneHandler !== undefined)
             doneHandler();
    });
}

TM.editMarker(e, $(this), 'man-marker_edit-marker', function() {
   console.log("done");
});

Use promises:

TM.editMarker = function (e, form, ajax_request) {
   ...

   var prom= jQuery.Deferred();
   request.done(function (response) {
        $("#ajaxoutput2").empty().append(response);
        $("#ResultModal2").modal("show");

        prom.resolve();
    });

    return prom.promise();
}

TM.editMarker(e, $(this), 'man-marker_edit-marker').then(function() {
   console.log("done");
});

Answer on edit:

Ok, so what you are trying to do is executing a javascript function through the ajax response. You could achieve this by doing something like this:

$.ajax({
    url: "somejs.js",
    context: document.body,
    success: function(responseText) {
        eval(responseText);
    }
});

However this is really dirty and not good practice because javascript is usually UI manipulating commands. Keep the UI stuff in the frontend and only return raw data / json from your backend. Can you give me an example of what the response looks like then I can give you an example of how I would solve it.



来源:https://stackoverflow.com/questions/60315890/pass-some-instructions-to-a-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!