2

Yeah, I know, likely been answered, but can't find it or figure out how to successfully search for it, so, 45 minutes later i am succumbing to the potential of flaming...so go easy on me, ok?

It is a simple problem, and my issue is timing. One select holds Countries, it is bound to State/Province select. Change Country, State/Province loads appropriately via a separate function. Use a mouse to select from State/Province, perfection. Use JavaScript ..uh oh. Problem is I need to force my JavaScript to wait for the browser to load the State/Province data before I can target and select it. SetTimeout or using a Promise just seems... inelegant? How many seconds does a browser need to load 50 states or 8 provinces - on a new rocket or an old turtle? Is there a way to just know when the second select finishes loading when the load is in a separate function? Example is jquery, but any flavor will do.

$('#country option[value=US]').prop('selected', 'selected').change();
$('#stp option[value=VT]').prop('selected', 'selected').change();

Adding more clarification based on the responses so far.

Whena user changes the Country, the State/Province loads in the time it takes them to move their mouse down the page allowing them to select. Now I have implemented a helper that pulls the user's address from BigData using a phone number. This happens in a dialog box. When the user clicks "Accept" this code then fires

function setFormwithDF(){
    d={};
    // data from dialog
    d.address=$('#oaddress').text();
    d.city=$('#ocity').text();
    d.state=$('#ostate').text();
    d.zip=$('#ozip').text();
    d.country=$('#ocountry').text();

    $('#s_country option[value='+d.country+']').prop('selected', 'selected').trigger('change');
    // doesn't matter if this is .change() or .trigger('change')
    $('#s_addr1').val(d.address).change();
    $('#s_addr2').val('').change();
    $('#s_city').val(d.city).change();
    $('#s_st option[value='+d.state+']').delay(3000).prop('selected', 'selected');console.log(d.state);//getting a good value here - delay is desperation
    $('#s_zip').val(d.zip);
    $('#s_phone').val($('#dfsearch').val());
    $( "#dfsearchdialog" ).dialog('close');
   }

And for completeness, here is the loading code. Bunch of extras in here that don't pertain to the issue though

$('#s_country,#b_country').change(function(e){
    var st="";
    var addrType="S";
    var loadObj=$('#shipstp');
    if( $(this).attr("id") == 'b_country'){
      loadObj=$('#billstp');
      addrType="B";
    }
    if( typeof(e.st) != 'undefined'){st=e.st;console.log(5)}// this data is passed during the trigger() code
    uObj={c:$(this).val(),nc:Math.random(),t:addrType,p:st};
    uParam=$.param(uObj);
    loadObj.load('/stubs/state-n-province.cfm',uParam);
});
Kirill Simonov
  • 8,257
  • 3
  • 18
  • 42
MikeG
  • 107
  • 1
  • 8

2 Answers2

0

As per my understanding, you dont want user to select state until the state's are getting loaded. After loading only user should be able to select the state.

And I am assuming you are using AJAX to load the State.

If this is the issue :

you can use loading image, which will be displayed until the success has not been return and data has not been map to element.

In this case you can use below sample code :

function getData(p){
    .......
    $('#loadingmessage').show();  // show the loading message.
    $.ajax({
    url: "loadData.php?id=<? echo $id; ?>",
    type: "POST",
    cache: false,
    data: "&page="+ page,
    success : function(html){
        $(".content").html(html);
        $('#loadingmessage').hide(); // hide the loading message
    }
});
Sachin Bankar
  • 372
  • 6
  • 13
  • nope, not the problem. When a user interacts, everything works as planned. But when County change is triggered with JavaScript, the State cannot be selected with javascript until the select finishes loading. And the loading function is a seperate function – MikeG Feb 16 '18 at 07:35
  • Can u post the code, so I can actually see the flow – Sachin Bankar Feb 16 '18 at 07:40
0

I believe a Promise is what you need. It will allow you exactly

to just know when the second select finishes loading when the load is in a separate function

$('#country').change(function() {
    $("#stp").empty().append("<option>...</option>");
    loadStates($(this).val())
        .then(states => $("#stp")
            .empty()
            .append(states.reduce((acc, cur) => acc + `<option>${cur}</option>`, "")));
});


$('#country').change();

function loadStates(country) {
    console.log(`Loading states for country: ${country}...`); 
    //setTimeout here just emulates your long loading process
    return new Promise((res, rej) => setTimeout(() => {
            console.log(`States for country: ${country} are loaded!`); 
            res(["state1", "state2", "state3"]);
        }, 3000));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="country">
   <option>US</option>
   <option>UK</option>
   <option>RU</option>
</select>

<select id="stp">
</select>

For your actual use case you would write something like:

return new Promise((resolve, reject) => {
    var states = yourLoadingFunction();
    resolve(states);
});

UPDATE: Given your latest example, I think I understand your problem now. I suggest you to put your loading code into a separate function, for example:

function countryChanged(e, callback) {    
    var st="";
    var addrType="S";
    var loadObj=$('#shipstp');
    if( $(this).attr("id") == 'b_country'){
      loadObj=$('#billstp');
      addrType="B";
    }
    loadObj.prop("disabled", true);
    // this data is passed during the trigger() code
    if( typeof(e.st) != 'undefined'){st=e.st;console.log(5)}
    uObj={c:$(this).val(),nc:Math.random(),t:addrType,p:st};
    uParam=$.param(uObj);
    loadObj.load('/stubs/state-n-province.cfm', uParam, function() {
        // when the loading is complete, we enable the second select and 
        // call the callback function
        loadObj.prop("disabled", false);
        if (callback) callback();
    });
}

Note that jQuery .load() method has a third argument which is a callback function that will be called when the loading is complete.

Then you can use this function in two ways:

1) when the user changes the country:

$('#s_country,#b_country').change(countryChanged);

2) in your setFormwithDF() function:

function setFormwithDF(){
    d={};
    // data from dialog
    d.address=$('#oaddress').text();
    d.city=$('#ocity').text();
    d.state=$('#ostate').text();
    d.zip=$('#ozip').text();
    d.country=$('#ocountry').text();

    $('#s_country option[value='+d.country+']').prop('selected', 'selected');
    //instead of calling .trigger('change') just call countryChanged function
    countryChanged({st: "whatever you pass during the trigger() code"}, function() {
       //this will happen only after .load() is complete
        $('#s_st option[value='+d.state+']').prop('selected', 'selected');
    });
    $('#s_addr1').val(d.address).change();
    $('#s_addr2').val('').change();
    $('#s_city').val(d.city).change();
    $('#s_zip').val(d.zip);
    $('#s_phone').val($('#dfsearch').val());
    $( "#dfsearchdialog" ).dialog('close');
}
Kirill Simonov
  • 8,257
  • 3
  • 18
  • 42
  • all Promise is, is a timeout. What do I set it for? And what about Safari and IE? – MikeG Feb 16 '18 at 07:48
  • @MikeG Promise is not a timeout, it's an async executor. It allows you to execute some task exactly when some other task finishes, no matter how much time is passed. So I thought that it is what you need. What about Safari and IE... Well, for IE you have to use some polyfill, and Safari supports Promises – Kirill Simonov Feb 16 '18 at 07:56
  • ok, I will dig a bit deeper. But... from what I have read so far, I don't see how this is going to solve the problem. Looks like I need to change the loading function, but in your example the console logs way before the select finishes loading. I need to create the pause in my setFormwithDF() function between Country and state actions. Can you tweak your code so that the console loads after the select finishes loading? – MikeG Feb 16 '18 at 08:10
  • @MikeG sure! check the update. I've added an example of how you could use your loading function – Kirill Simonov Feb 16 '18 at 08:23
  • @MikeG I noticed that you use jquery `.load` function which has a callback argument. It could be helpful in your situation. Check my update – Kirill Simonov Feb 16 '18 at 17:29