Skip to content
Advertisement

Understanding Promise() for Controlling when Form Inputs are Displayed

I have certain form inputs that are only displayed depending on other input’s value. I am trying to control when inputs fadeOut() and fadeIn() with, I think, a promise() but it seems the call-stack still runs everything synchronously – maybe I am not configuring the promise correctly?

Here is some pseudo code. The catch here is one of my inputs, input3 needs to be removed, then re-added to correct some JQuery validation and JQuery automcomplete rules, so I am trying to create the function to do that, every time that function is called to fadeIn().

function display_input1() {

    return new Promise(function (resolve) {
        resolve(hide_input3())
        var new_element = `...`

        $(new_element)
            .hide()
            .insertAfter(
                $("#input0")
            )

        $("new_element").fadeIn("fast")
    })
}

function hide_input1() {

    $("#input1")
        .fadeOut("fast", function () {
            $("#input1").remove()
        })
}

function display_input2(data) {

    var new_element = `...`

    $(new_element)
        .hide()
        .insertAfter(
           $("#input0")
         )


    $("new_element").fadeIn("fast")
}

function hide_input2() {

    $("#input2")
        .fadeOut("fast", function () {
            $("#input2").remove()
        })
}

function display_input3(search_type) {

    return new Promise(function (resolve) {
        resolve(hide_input1(), hide_input3())

        if (search_type == "some_varible") {
            var new_element = `...`
        } else if (search_type == "some_variable") {
            var new_element - `...`
        }

        $(new_element)
            .hide()
            .insertAfter(
               $("#input2")
             )

        $("new_element").fadeIn("fast")
    })
}

function hide_input3() {

    if ($("#input3").length) {
        $("#input3")
            .fadeOut("fast", function () {
                $("#input3").remove()
            })
    }
}

$(document).on("change", "#input0", function (e) {
    var option = $(this).find("option:selected")
    var data = AJAX response

            if (data["some_attr"]) {
                display_input2(data)
                hide_input1()
            } else {
                hide_input2()
                if (data["some_attr"]) {
                    if (!$("#input1").length) {
                        display_input1()
                    }
                } else {
                    hide_input1()
                }
            }
})

$(document).on("change", "input2", function (e) {
    var option = this

    if (option.value === "input1") {
        display_input1()
    } else if (["input2", "input3"].includes(option.value)) {
        if (option.value === "input2") {
            var search_type = "some_varible"
        } else {
            var search_type = "some_varibale"
        }

        display_input3(search_type)
    }
})

$(document).on("click", "button.cancel", function (e) {

    hide_input1()
    hide_input2()
    hide_input3()

    $(form).validate().resetForm()
})

UPDATE

Based on comments, I’ve reflected my code block for better understanding. I’ve consolidated functions in hopes to make the code more malleable.

function display_form_input(input_type, search_type = null, data = null) {
    if (input_type == "input_var1") {
        var new_element = `...`

        $(new_element)
            .hide()
            .insertAfter(
                $("#input1")
            )

        $("#input1").fadeIn("fast")
    } else if (input_type == "input_var2") {
        var new_element = `...`

        $(new_element)
            .hide()
            .insertAfter(
                $("#input0")
            )

        $("#input2").fadeIn("fast")
    } else if (input_type == "input_var3") {
        if (search_type == "some_var1") {
            var new_element = `...`
        } else if (search_type == "some_var2") {
            var new_element = `...`
        }

        $(new_element)
            .hide()
            .insertAfter(
                $("#input3")
            )

        $("#input3").fadeIn("fast")
    }
}

function hide_form_input(input_type) {

    return new Promise(function (resolve) {
        if (input_type == "input_var1") {
            $("#input1")
                .fadeOut("fast", function () {
                    $("#input1").remove()
                    resolve()
                })
        } else if (input_type == "input_var2") {
            $("#input2")
                .fadeOut("fast", function () {
                    $("#input2").remove()
                    resolve()
                })
        } else if (input_type == "input_var3") {
            $("#input3")
                .fadeOut("fast", function () {
                    $("#input3").remove()
                    resolve()
                })
        }
    })
}

$(document).on("change", "#input0", function (e) {
    var option = $(this).find("option:selected")

    $.ajax({
        ...
        success: function (data) {
            if (data["key1"]) {
                hide_form_input("input_var1")
                display_form_input(
                    "input_var2",
                    null,
                    (data = data["key1"]),
                )
            } else {
                hide_form_input("input_var2")
                if (data["key2"] && !$("#input1").length) {
                    display_form_input("input_var1")
                }
            }
        },
    })
})

$(document).on("change", "#input2", function (e) {
    var option = this

    if (option.value === "value1") {
        var search_form = hide_form_input("input_var3")

        search_form
            .promise()
            .done(display_form_input("input_var1"))
    } else if (["value2", "value3"].includes(option.value)) {
        if (option.value === "value2") {
            var search_type = "value22"
        } else {
            var search_type = "value33"
        }

        hide_form_input("input_var1")
        var search_form = hide_form_input("input_var3")

        search_form
            .promise()
            .done(display_form_input("input_var3", search_type))
    }
})

$(document).on("click", "button.cancel", function (e) {

    var items = ["input_var1", "input_var2", "input_var3"]

    items.forEach(function (item) {
        hide_form_input(item)
    })

    $(form).validate().resetForm()
})

Advertisement

Answer

Thanks to @Bergi and @ControlAltDel for walking me through understanding .promise(). I now have a working example I was trying to achieve! Thank you guys so much for your patience.

Here is my working example in pseudo code. I made some improvements too on a function based @Bergi comments (always strive for DRY code)

function display_form_input(input_type, search_type = null, data = null) {
    /*
    create_form_input: Display the form input for a given input_type.

    Args:
        input_type (str): The type of input to create.

    Optional Args:
        search_type (str): The type of results expected from this search.

    Returns:
        None
    */

    if (input_type == "input_var1") {
        var new_element = `...`

        $(new_element)
            .hide()
            .insertAfter(
                $("#input0").closest("div.row").children(),
            )

        $("#input1").parents(":eq(1)").fadeIn("fast")
    } else if (input_type == "input_var2") {
        var new_element = `...`

        $(new_element)
            .hide()
            .insertAfter($("#input0").closest("div.row"))

        $("#input2").parents(":eq(2)").fadeIn("fast")
    } else if (input_type == "input_var3") {
        if (search_type == "some_var1") {
            var new_element = `...`
        } else if (search_type == "some_var2") {
            var new_element = `...`
        }

        $(new_element)
            .hide()
            .insertAfter($("#input2").closest("div.row").children())

        $("#input3").parents(":eq(1)").fadeIn("fast")
    }
}

function hide_form_input(input_type) {
    /*
    hide_form_input: Hide the form input for a given input_type.

    Args:
        input_type (str): The type of input to hide.

    Returns:
        JQuery Promise.
    */

    if (input_type == "input_var1") {
        var form_element = $("#input1").parents(":eq(1)")
    } else if (input_type == "input_var2") {
        var form_element = $("#input2").parents(":eq(2)")
    } else if (input_type == "input_var3") {
        var form_element = $("#input3").parents(":eq(1)")
    }

    return form_element
        .fadeOut("fast")
        .promise()
        .then(function () {
            form_element.remove()
        })
}

$(document).on("change", "#input0", function (e) {
    /*
    Event Handler: Trigger what form field to display when a the input0 
         changes.
    */

    var option = $(this).find("option:selected")

    $.ajax({
        ...
        success: function (data) {
            if (data["key1"]) {
                hide_form_input("input_var1").then(function () {
                    if (!$("#input2").length) {
                        display_form_input(
                            "input_var2",
                            null,
                            data["key1"],
                        )
                    }
                })
            } else {
                hide_form_input("input_var2")
                if (data["key2"] && !$("#input1").length) {
                    display_form_input("input_var1")
                } else if (!data["key2"]) {
                    hide_form_input("input_var2")
                }
            }
        },
    })
})

$(document).on("change", "#input2", function (e) {
    /*
    Event Handler: Trigger what form field to display when a the input2
        changes.
    */

    var option = this

    if (option.value === "value1") {
        hide_form_input("input_var3").then(function () {
            display_form_input("input_var1")
        })
    } else if (["value2", "value3"].includes(option.value)) {
        if (option.value === "value2") {
            var search_type = "some_var1"
        } else {
            var search_type = "some_var2"
        }

        hide_form_input("input_var1")
        hide_form_input("input_var3").then(function () {
            display_form_input("input_var3", search_type)
        })
    }
})

$(document).on("click", "button.cancel", function (e) {
    /*
    Event Handler: Make form back to default state.
    */

    var button = this
    var form = $($(button).closest("form"))
    var items = ["input_var1", "input_var2", "input_var3"]

    items.forEach(function (item) {
        hide_form_input(item)
    })

    $(form).validate().resetForm()
})
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement