0

Using javascript to create the content of the body of a modal i notice that the result is not always the same. Sometimes the modal body is empty some times is as expected. The function is this:

function newServiceModal() {
$("#newServicesModal-bd").html("");
$("#newServiceModalHiddenId").val("");
$("#newServiceModal-title").html("New Service - body not created yet ");
var modalbody = "";
var div = document.createElement('div');
//var provideroptions = {
//    providerid:providerid
//}
$.ajax({
    type: 'post',
    url: baseSiteURL + 'home/ReturnProviders', //supposed to return all available providers
    //data: options
}).done(function (data) {
    $("#newServiceModal-title").html("New Service - body was created");
    modalbody = modalbody.concat(" <div class='col-md-4'> <p>Provider</p><select id='newproviderSelect' class='form-control'>");
    for (i = 0; i < data.length; i++) {
        if (i==0)
            modalbody = modalbody.concat(" <option value=" + data[i].id + " selected>Type: " + data[i].providerType + "</option>");
        else
            modalbody = modalbody.concat(" <option value=" + data[i].id + ">Type: " + data[i].providerType + "</option>");
    }
    modalbody = modalbody.concat('</select></div>');
    div.innerHTML = modalbody;
    document.getElementById('editServicesModal-bd').appendChild(div);
    $("#newServiceModal-title").html("New Service - body was created");
})

//var customeroptions = {
//    customerid: customerid
//}
$.ajax({
    type: 'post',
    url: baseSiteURL + 'home/ReturnCustomers', //supposed to return all available customers
    //data: options
}).done(function (data) {
    modalbody = modalbody.concat(" <div class='col-md-4'> <p>Customer</p><select id='newcustomerSelect' class='form-control'>");
    for (i = 0; i < data.length; i++) {
        if (i==0)
            modalbody = modalbody.concat(" <option value=" + data[i].id + " selected>" + data[i].company + "</option>");
        else
            modalbody = modalbody.concat(" <option value=" + data[i].id + ">" + data[i].company + "</option>");
    }
    modalbody = modalbody.concat('</select></div>');
    div.innerHTML = modalbody;
    document.getElementById('editServicesModal-bd').appendChild(div);
})

//var applicationroptions = {
//    applicationid: applicationid
//}
$.ajax({
    type: 'post',
    url: baseSiteURL + 'home/ReturnApplications', //supposed to return all available applications
    //data: options
}).done(function (data) {
    modalbody = modalbody.concat(" <div class='col-md-4'> <p>Application</p><select id='newapplicationSelect' class='form-control'>");
    for (i = 0; i < data.length; i++) {
        if (i==0)
            modalbody = modalbody.concat(" <option value=" + data[i].id + " selected>" + data[i].name + "</option>");
        else
            modalbody = modalbody.concat(" <option value=" + data[i].id + ">" + data[i].name + "</option>");
    }
    modalbody = modalbody.concat('</select></div>');
    div.innerHTML = modalbody;
    document.getElementById('newServicesModal-bd').appendChild(div);
})
$("#newServiceModal").modal('show');

}

the modal html is this:

<div id="newServiceModal" class="modal fade local-modal" role="dialog" aria-hidden="true" position="fixed">
<div class="modal-dialog">
    <!-- Modal content-->
    <div class="modal-content">
        <section id="newService">
            @using (Html.BeginForm("Services", "Home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
            {
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
                    <h4 class="modal-title" id="newServiceModal-title">original title</h4>
                </div>
                <div id="newServiceModalHiddenId"></div>
                <div class="modal-body row" id="newServicesModal-bd" style='margin-right:20px; margin-left:20px;'>
                    @* bootstrap.min.css applies here this rule : .row{margin-right:-15px;margin-left:-15px} *@
                    @* services.js puts content here *@
                </div>
                <div class="modal-footer">
                    <div class="col-md-6 pull-left">
                        <button id="savebtn" type="button" class="btn btn-primary ladda-button" data-style="expand-right" data-size="l" onclick="saveNewService()"><span class="ladda-label">Save</span></button>
                        <button type="button" class="btn btn-warning" data-dismiss="modal" aria-hidden="true">Close</button>
                    </div>
                    @*<div class="col-md-6">
                            <button type="button" class="btn btn-danger" onclick="deleteUser()">Delete</button>
                        </div>*@
                </div>
            }
        </section>
    </div>
</div>

The first line of the function

$("#newServicesModal-bd").html("");

is emptying the modal body (to not have concatenated the previous content with what is about to be created). I imagine my problem is related with this, because 9 of 10 times the modal is created as expected but some times its body is empty, which makes me suspect that either the body content is not created at all or the

$("#newServicesModal-bd").html("");

is executed after the body content is created. To verify that the content does get created i have this

$("#newServiceModal-title").html("New Service - body not created yet ");

right after i empty the body of the modal and i put this

$("#newServiceModal-title").html("New Service - body was created");

when i get some content created.

I would see the title always to be "New Service - body was created" so i think that its safe to assume that the body does get created. I read about hoilsting and scope and i dont think think that they have to do with this matter can't find but in any case i can find any reason for this inconsistent behaviour. If any one could point out why this happens i would appreciate it. Thank you for reading this.

Solution (?)

I investigated a little more and i want to make some more comments, maybe i will clarify the problem better. The function newServiceModal() is making 3 calls to different other functions. ReturnProviders, ReturnCustomers and ReturnApplications(which are in my HomeController class) and they are calling the functions that are actually retrieving the data from the database. I found that the problem occurs only when they (ReturnProviders, ReturnCustomers and ReturnApplications) are not called with this order. The reason that they are not called with the same order as they are written in the function was shown to me by a seasoned programmer after i explained him the problem and he googled, totally he needed 5 minutes. I just added

async: false

in my ajax requests and now the results are coming in the order that are expected. It was pointed out to me that my approach is not correct and i should be making one ajax call for all the data i need instead of 3. So i will post the correct solution as soon as i do it. Thank you all for your time and help.

I managed to solve the problem by making one ajax call, i think that the solution is irrelevant with my question, if anyone is interested email me to give more information. As far as my original question is concerned the answer is that the ajax requests are being executed as they are written in the function but sometimes the results are not coming back in the same order unless this is added to the ajax call

async: false

Solution was found in this post How do I make jQuery wait for an Ajax call to finish before it returns?

Community
  • 1
  • 1
lefteris
  • 13
  • 5
  • 1
    Depends where that bit of JavaScript is placed in your HTML file, to determine when it is run. It should only really be run after your page is fully loaded, given that it needs access to the DOM to update elements. – ManoDestra Apr 22 '16 at 14:21
  • Can you point to exactly which part doesn't execute properly? – Dellirium Apr 22 '16 at 14:26
  • @ManoDestra i am using the standard bundling procedure for mvc. I have this @Scripts.Render("~/bundles/services") at the top of my html, but i dont think that its a problem because all other javascript are working ok and are placed the same way – lefteris Apr 22 '16 at 14:37
  • @Dellirium i suspect that the problem is that this "$("#newServicesModal-bd").html("");" is executed after the part of the javascript that is creating the html but am not sure – lefteris Apr 22 '16 at 21:25
  • @lefteris there is just too many non-standard HTML/javascript elements in there for me to be able to understand what is happening as I do not know any framework or whatever you are using. JQuery included (though I do understand how jQuery works to some extent, but I really dislike it). – Dellirium Apr 23 '16 at 02:41

1 Answers1

1

Like @ManoDestra said in the comments, you shouldn't execute functions that reference or manipulate DOM elements until after they have been loaded. It's best practice to put your newServiceModal() code at the end of the body or run it inside a window.onload event or $(function(){ ... }) wrapper.

Brett
  • 4,268
  • 1
  • 13
  • 28
  • Yes. Even if it's in the head for the script declarations, or at the end of the file, then it should be fine. I tend to put my scripts in the head and then do any actual calls after the document has fully loaded by adding a listener to the load event. – ManoDestra Apr 22 '16 at 14:56
  • @Brett i just tried moving the whole function after body and there was no change. I dont think that this is the problem because the problem may not occur the first time that i call the function but it may occur the fifth or tenth time – lefteris Apr 22 '16 at 21:38