Solved

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

Posted on 2013-01-02
13
686 Views
Last Modified: 2013-01-05
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

0
Comment
Question by:hitman3030
  • 9
  • 3
13 Comments
 
LVL 17

Expert Comment

by:sonawanekiran
Comment Utility
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
0
 

Author Comment

by:hitman3030
Comment Utility
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

0
 

Author Comment

by:hitman3030
Comment Utility
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?
0
 

Author Comment

by:hitman3030
Comment Utility
As a test, I added an additional image to download, but no change.
0
 
LVL 11

Expert Comment

by:mcnute
Comment Utility
WHERE and WHEN do you call the functions above in your code?
0
 

Author Comment

by:hitman3030
Comment Utility
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.
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 11

Expert Comment

by:mcnute
Comment Utility
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 ;-)
0
 

Author Comment

by:hitman3030
Comment Utility
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

0
 

Author Comment

by:hitman3030
Comment Utility
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.
0
 

Author Comment

by:hitman3030
Comment Utility
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.
0
 

Author Comment

by:hitman3030
Comment Utility
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

0
 
LVL 11

Accepted Solution

by:
mcnute earned 500 total points
Comment Utility
Hello again. Now I can help you better.

First I would recommend to clean up your code according to w3c validator. Always a good idea.
W3C-Errors and Fixing

Second:
Since you have jquery already there, I would do the following changes to your code which I tested on a IE 8.
$(function(){
    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;

    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);
        $('#txtSpeed').val(speedKbps);
        getHeightWidth();
    }

    function getHeightWidth() {
        var w = $(window).width();
        var h = $(window).height();
        $('#txtScrnWidth').val(w);
        $('#txtScrnHeight').val(h);
    }

});

Open in new window


The problem was that the onload function was never triggered so the storeValues function never was executed. By wrapping that into a jqeury onload function altogether you get by this issue. I've worked with the code you have on your website, there it is stlightly different. Let me know if the issue continues.
0
 

Author Closing Comment

by:hitman3030
Comment Utility
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.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Introduction Knockoutjs (Knockout) is a JavaScript framework (Model View ViewModel or MVVM framework).   The main ideology behind Knockout is to control from JavaScript how a page looks whilst creating an engaging user experience in the least …
In this article we will discuss all things related to StageFright bug, the most vulnerable bug of android devices.
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now