Link to home
Start Free TrialLog in
Avatar of hitman3030
hitman3030

asked on

jQuery $(window).width() working only in Firefox

I have put together a function to get screen width and a rough estimate of download speed and write those values to hidden textbox.

Then, I intend to access the values in .net to deliver best resolution images to the user.

The code works in Firefox, but not IE or Chrome. In the page, I have only included the min jquery file below.

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>

Here is the javascript...


 
     function getSpeedWidth() {
            var w = $(window).width();
            var h = $(window).height();
            document.getElementById('txtScrnWidth').value = w;
            document.getElementById('txtScrnHeight').value = h;

            var imageAddr = "../images/Logo_UMS_Trans.png";
            var startTime, endTime;
            var downloadSize = 19865.6;
            var download = new Image();
            download.onload = function () {
                endTime = (new Date()).getTime();
                var duration = (endTime - startTime) / 1000;
                var bitsLoaded = downloadSize * 8;
                var speedBps = (bitsLoaded / duration).toFixed(2);
                var speedKbps = (speedBps / 1024).toFixed(2);
                document.getElementById('txtSpeed').value = speedKbps;
            }
            startTime = (new Date()).getTime();
            download.src = imageAddr;
        }
 

Open in new window

Avatar of Kiran Sonawane
Kiran Sonawane
Flag of India image

The problem is your onload function executes asynchronously.  here is solution to your problem

http://stackoverflow.com/questions/8645143/wait-for-image-to-be-loaded-before-going-on
Avatar of hitman3030
hitman3030

ASKER

I'm getting closer. I added "when done"  to the code and cleaned everything up. It still only works in Firefox, so I must be missing something. Javascript is my third language and I am struggling with this.

Here is the modified code:
      function getSpeedSize() {
            var startTime, endTime;
            var img = new Image();
            var downloadSize = 19866.6;
            var imageAddr = "../images/Logo_UMS_Trans.png" + "?n=" + Math.random();
            startTime = (new Date()).getTime();
            img.src = imageAddr;
            $.when(img.onload).done(function () {
                // callback when file is loaded
                endTime = (new Date()).getTime();
                storeValues(downloadSize, startTime, endTime);
            })
        }

        function storeValues(downloadSize, startTime, endTime) {
            var duration = (endTime - startTime) / 1000;
            var bitsLoaded = downloadSize * 8;
            var speedBps = (bitsLoaded / duration).toFixed(2);
            var speedKbps = (speedBps / 1024).toFixed(2);
            document.getElementById('txtSpeed').value = speedKbps;
            getHeightWidth();
        }
  
        function getHeightWidth() {
            var w = $(window).width();
            var h = $(window).height();
            document.getElementById('txtScrnWidth').value = w;
            document.getElementById('txtScrnHeight').value = h;
        }

Open in new window

In the jQuery docs I found this: "If a single argument is passed to jQuery.when and it is not a Deferred, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately. "

I am only passing one argument. Is there a way to still make it defer? Do I have to load two graphics? Is there a simple "space holder" argument that I can pass to "up the count" but not actually do anything to slow that function?
As a test, I added an additional image to download, but no change.
WHERE and WHEN do you call the functions above in your code?
I've tried three variations:

1) adding it to the BODY tag onload event
2) putting it just after the HEAD tag without wrapping it in a function declaration so that it would execute as soon as encountered
3) placing a Query(document).load call just after the HEAD tag.

All three produce the same end result. All works only in FFox only.
Can you post full code please within the code method in the comment box? If not I have a fourth option for you:

put your function into a <script></script> tag on the bottom of your page just behind your <body> tag. So it is between the closing body and html tag. What happens then?

And I strongly suggest you to use Chrome Developer Tools and click on the console tab in it and reload the page, so you can see which error is being thrown exactly. Or use the IE Developer Tools pressing F12 in IE  7+. There the same, click the console tab and reload page with Tools open and see which error is being thrown into console.

Hope that helps debugging! If you tell us, we can help even better. Or can you provide a link, this would be an Experts dream ;-)
I moved the js to the location you suggested. Still only works in FFox. I debugged in IE and did not get any errors. I could step through each line. I have to admit when it opened the jquery file to trace that code, it was hard to follow.

At one time, I thought the fields may not be loaded at the time it's setting value. I have the hidden fields at the top of the page just after the BODY and FORM tags and have the JS at the bottom just before the HTML tag  now.

The page is loaded at this url: upmyscore.com/lp/

Here are the blocks of code:

</head>
<body style="margin-top:-25px;" >
    <form id="form1" runat="server">
        <input type="hidden" runat="server" id="txtScrnWidth" name="txtScrnWidth" />
        <input type="hidden" runat="server" id="txtScrnHeight" name="txtScnHeight" />
        <input type="hidden" runat="server" id="txtSpeed" name="txtSpeed" />

Open in new window


Then at the bottom:

</body>
<script>
    var startTime, endTime;
    var img1 = new Image();
    var downloadSize1 = 19866.6;
    var imageAddr1 = "../images/Logo_UMS_Trans.png" + "?n=" + Math.random();
    var img2 = new Image();
    var downloadSize2 = 19866.6;
    var imageAddr2 = "../images/Logo_UMS_Trans.png" + "?n=" + Math.random();
    startTime = (new Date()).getTime();
    downloadSize = downloadSize1 + downloadSize2;
    img1.src = imageAddr1;
    img2.src = imageAddr2;
    $.when(img1.onload, img2.onload).done(function () {
        // callback when everything was loaded
        endTime = (new Date()).getTime();
        storeValues(downloadSize, startTime, endTime);
    })


    function storeValues(downloadSize, startTime, endTime) {
        var duration = (endTime - startTime) / 1000;
        var bitsLoaded = downloadSize * 8;
        var speedBps = (bitsLoaded / duration).toFixed(2);
        var speedKbps = (speedBps / 1024).toFixed(2);
        document.getElementById('txtSpeed').value = speedKbps;
        getHeightWidth();
    }

    function getHeightWidth() {
        var w = $(window).width();
        var h = $(window).height();
        document.getElementById('txtScrnWidth').value = w;
        document.getElementById('txtScrnHeight').value = h;
    }

</script>
</html>

Open in new window

As I continue to debug it in IE, I can see that the code is executing a second time immediately on completion of the first, but I don't know why.
I can confirm that the three values are present in all browsers (width, height, speed). In debug, the value is assigned to the hidden field (ie  document.getElementById('txtScrnWidth').value = w;)...
But there is no value when you look at the source code after loading, except for FFox.)

Since I have the values, is there a better way to make them available to .net. (I'm coding in vb)
Maybe stuff them in an array saved in a cookie? I was trying to avoid cookies here. Thanks for any ideas.
BREAK THROUGH: The code will work as originally posted if I assign the values to a regular textbox. It is the hidden field that does not work. I have no idea why. I placed them both together on the page and tested and retested. The hidden fields show the value in FFox only while the regular textbox shows values in all browsers I tested.

Also, I dropped the jQuery "when done"
Here is the final code placed in the HEAD tag:

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<script>
    var imageAddr = "../images/Logo_UMS_Trans.png" + "?n=" + Math.random();
    var startTime, endTime;
    var downloadSize = 19866.6;
    var download = new Image();
    download.onload = function () {
        endTime = (new Date()).getTime();
        storeValues();
    }
    startTime = (new Date()).getTime();
    download.src = imageAddr;

    function storeValues() {
        var duration = (endTime - startTime) / 1000;
        var bitsLoaded = downloadSize * 8;
        var speedBps = (bitsLoaded / duration).toFixed(2);
        var speedKbps = (speedBps / 1024).toFixed(2);
        document.getElementById('txtSpeed1').value = speedKbps;
        getHeightWidth()
    }

    function getHeightWidth() {
        var w = $(window).width();
        var h = $(window).height();
        var newH = document.createElement('input');
        document.getElementById('txtScrnWidth1').value = w;
        document.getElementById('txtScrnHeight1').value = h;
    }

</script>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of mcnute
mcnute
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
This worked! I had to add the img.onload(function)  back into the code to make it wait before setting an end time. Otherwise, the speed calc was before the file finished downloading. Thanks.

I also ended up storing this in a cookie.