JavaScript
Feb 15th, 2011
I use firefox for the vast majority of my web browsing, with IE and Chrome occasionally thrown in. While using IE 7 the other day, I opened up this very site, and to my dismay, discovered a javascript error: Line 89, Object doesn't support this action.
I was surprised, since I tested the site on IE 7 not too long ago and am not using any plugins or 3rd party code (i.e. this isn't a wordpress site). At first, it appeared the Core MooTools was the culprit, as removing that file stopped the error. But that didn't explain why there was no error when I tested it on my development box, which had the MooTools JavaScript included. After a little more head scratching I realized the only difference between the site on my dev box and production box was the fact that I have Google Adsense ads on the live site, but not on the dev site.
Sure enough, removing the ads caused the error to go away. Trying to be a good web developer, I was loading my MooTools scripts at the bottom of the page to prevent locking the browser while rendering the page. When I moved the Core MooTools script into the head tag at the top of the page, the error went away. Not sure the exact details of the problem, but loading MooTools after Google Adsense was causing errors in IE 7...
Posted In: JavaScript |
1 comment
Aug 27th, 2010
My lack of javascript knowledge is really becoming a pain in the ass. I was trying to add multiple markers and infowindows via Google Maps v3 API, and whichever marker I clicked on, it would always open the infowindow of the last marker. Here is the code I was using:
//photoMarkers is a JavaScript array of objects that PHP spits out to the page, and the script below is from an external javascript file and is contained within a function
for (var i = 0; i < photoMarkers.length; i++) {
var p = photoMarkers[i];
var marker = new google.maps.Marker({position: new google.maps.LatLng(p.latitude, p.longitude), title: p.alt, map: map, draggable: true});
var infowindow = new google.maps.InfoWindow({content: p.content});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, marker);
});
}
I was baffled as to why this didn't work. I am creating new variables on every loop and then passing the marker to the infowindow via a closure. After some searching, I found a
solution which worked. But it still didn't explain why this wasn't working. Surely the Google code must be doing something strange in the addListener function, making my life difficult? Some more searching resulted in
this article, explaining why you can't have closures in loops. The closure is using the scope of the function it was created in and not the loop.Therefore each closure is "sharing" the variables, and when the closure is executed, it has a reference to the last marker and infowindow. Shows how little I know about JavaScript.
Another way of dealing with this is to return an anonymous function that acts as a closure from within another function. Now the closure, e.g. the inner function, takes the environment of the outer function on each loop, and it doesn't "share" the scope/environment with the other closures. E.g.
function infoCallback(infowindow, marker) {
return function() {
infowindow.open(map, marker);
};
}
for (var i = 0; i < photoMarkers.length; i++) {
var p = photoMarkers[i];
var marker = new google.maps.Marker({position: new google.maps.LatLng(p.latitude, p.longitude), title: p.alt, map: map, draggable: true});
var infowindow = new google.maps.InfoWindow({content: p.content});
google.maps.event.addListener(marker, 'click', infoCallback(infowindow, marker));
}
Posted In: JavaScript |
8 comments
Oct 16th, 2009
I am new to MooTools and was using MooTools 1.2.3 to submit a form via Ajax - pretty standard stuff. When trying to put in callbacks for onSuccess,onRequest, etc... I kept getting JavaScript errors (b.lastIndexOf is not a function). Looks like you need to use set() function first, then call send(). MooTools must have been updated, because there are a lot of examples on the intraweb that do not do this, but work in my browser. To add to my confustion, you can call send() on the form without set first as long as you don't pass an object with callbacks as a parameter in send().
This works
window.addEvent('domready', function() {
$('myForm').addEvent('submit',function(event) {
event.preventDefault();
this.send();
})
});
This does not work
window.addEvent('domready', function() {
$('myForm').addEvent('submit',function(event) {
event.preventDefault();
this.send({onComplete:function(){alert('this');}});
})
});
This works with callbacks
window.addEvent('domready', function() {
$('myForm').addEvent('submit',function(event) {
event.preventDefault();
this.set('send',{onComplete:function(){
alert('this');
}
}).send();
})
});
Anyways, after a day of playing with MooTools, I have say I am impressed. Not sure why, but I think this is my favorite framework. I can't say I have much experience with JS frameworks, and my JavaScript is pretty bad these days, but I am impressed with MooTools so far.
Posted In: Uncategorized, JavaScript |
No Comments
Dec 25th, 2008
I have a bunch of javascript objects flying around page that interacts with Google Maps, and I wanted to get the data out of some of the objects to pass via a jQery AJAX $.post call to a PHP script. jQuery seems to have everything, so I was surprised there wasn't any functionality built in to do this (at least as far as I am aware of). I found
JSON stringify, which may come in very handy in the future, but seemed like overkill for this particular instance, as I needed a very limited set of data. Below is the code I came up with. My object lineM has an array of Line objects (lineM.lines), and I added a method getWaypoints to the Line object prototype (this method returns a regular javascript array). Then it's just a matter of creating an object literal, and adding properties with "[]" appended to the property name.
var params = {};
for(var i = 0; i < lineM.lines.length;i++) {
params['line'+i+'[]']=lineM.lines[i].getWaypoints();
}
$.post('/test.php',params,function(data) {
$("#ieTest").text(data);
});
When I spit out the results in PHP, I get :
Array ( [line0] => Array ( [0] => 47.399458084,-121.393484585 [1] => 47.405251153,-121.395479813 [2] => 47.412148202,-121.397021664 [3] => 47.419077186,-121.395984907 [4] => 47.422244288,-121.387493955 [5] => 47.427556822,-121.382973259 [6] => 47.431650627,-121.383301159 [7] => 47.433441086,-121.382011855 [8] => 47.432344733,-121.381145837 [9] => 47.431196412,-121.37981873 ) [line1] => Array ( [0] => 47.457933301545786,-121.42310857772827 [1] => 47.46124106812506,-121.41435384750366 [2] => 47.46318500928391,-121.40516996383667 [3] => 47.45874575472201,-121.40710115432739 [4] => 47.458716738753324,-121.41165018081665 ) [line2] => Array ( [0] => 47.45471721756243,-121.42242193222046 [1] => 47.45404979509893,-121.41409635543823 [2] => 47.4578510880274,-121.41624212265015 [3] => 47.45634221074817,-121.40671491622925 [4] => 47.459766139142666,-121.40469789505005 ) )
Posted In: PHP, JavaScript |
3 comments
Nov 27th, 2008
In my controllers, I use Zend_Acl to check whether or not a user is allowed to perform an action (i.e. should the code in the method be executed). I also have to check permissions once in a method, as someone might be trying to access an object that does not belong to them - i.e. edit a blog post of someone else. In that case, I was forwarding to a method in the Error controller and adding a 403 to denote that the user could not access the page, as well as displaying a generic page saying the user does not have the proper permissions :
[php]
$this->getResponse()->setRawHeader('HTTP/1.1 403 Forbidden');
[/php]
I am using jQuery with AJAX to run methods on occasion, and whenever returning a 403, my jQuery callbacks never executed : $.post('/tripreport/admintr/saveroute',doThis);. In reading the jQuery documentation, I need to use the $.ajax function instead of $.post : $.ajax({type:"POST",url:"/tripreport/admintr/saveroute",error:handleError,success:handleSuccess});. In the handleError function, I can test whether or not the status code is a 403, and then take the appropriate action : XMLHttpRequest.status == '403'.
On a related note, if you are using $this->_forward in your methods in the Action Controllers like I mentioned above, be sure to use "return" right after, if you don't want to execute any more code in that method.
Posted In: PHP, JavaScript, Zend Framework |
No Comments
Nov 14th, 2008
I have spent over an hour trying to get a simple page using Dojo's lightbox and no luck. I am more of a jQuery fan, but thought I would give Dojo a try since it is coupled with Zend Framework now. I tried adding the script and css tags manually to the page, not through Zend Framework, but for the life of me could not get it to work. Not sure what the deal is. Searching, I came to
this page on Dojo, where it doesn't even work. In the comments it says this example is outdated and points to another page that didn't help at all. I'm pretty frustrated right now, so I'll have to try again on a clear head. Maybe trying to use the CDN instead of downloading the files is causing the problems? Man, jQuery's thickbox was painless to get up and running, may have stick with that...
Posted In: Uncategorized, JavaScript |
2 comments
Oct 14th, 2007
Had a question come up from a colleague that used to cause problems when I first started using JavaScript. How to test whether a variable is undefined:
var a = 'defined'
if(typeof a == 'undefined') {
alert('it is undefined');
}
Posted In: JavaScript |
No Comments
Oct 10th, 2007
Javascript is an interesting language and like any language, the more you use it, the more functionality you find. Without getting into the specfics, I occasionally need to modify a site’s HTML and or JavaScript with an external JavaScript file (i.e I can’t touch the page I am modifying, I can only touch one external JavaScript file). And no, this is not some nefarious activity, we are doing this with full knowledge and compliance of the sites that are loading out JavaScript file.
Anyways, you can modify a page’s javascript functions to your heart’s content. You simply cast a function to a string, remove the “function†syntax, modify the string, and then create an anonymous function and assign it to the same variable name as the existing function. Code and explanation below
function simpleFunction(param1,param2) {
alert(param2);
}
//run the function and see it alert "2";
simpleFunction('1','2');
//get the function as a string
var newFunctionString = window.simpleFunction.toString();
//remove the function construct
newFunctionString = newFunctionString.replace(/^[^{]*{/,'').replace(/}$/,'');
//replace the alert message with our own message
newFunctionString = newFunctionString.replace(/param2/,'"this is our new message"');
//create an anonymous function and assign to the function you are overwriting
window.simpleFunction = new Function('param1', 'param2',newFunctionString);
//run the modified function and see it alert "this is our new message"
simpleFunction('1','2');
We can cast the function to a string. If you were to alert the variable newFunctionString after casting it as a string, you would see the function construct ("function", plus the name of the function and the parameters, etc...) plus the code inside the function. We want to remove this to get only the code inside the function and this can be accomplished with a regular expression. If you alerted newFunctionString after removing the function construct, you would only see "alert(param2)"'. Using a regular expression, we can modify the code to our needs. For simplicity, I am just changing the alert message. Finally, we create an anonymous function with the parameters of the existing function and our new string that contains the modified code, and assign it to the variable "simpleFunction", which overrides the existing function with our version!
Posted In: JavaScript |
No Comments
Oct 2nd, 2007
Using console.log with
Firebug can be a real time saver. The problem arises when you need to test the same code in IE. You can either let the code fail with errors, or comment out your logging and use the dreaded alerts. That’s where
Firebug Lite comes to the rescue – it replicates some of Firebug’s functionality in other browsers, like IE and Opera.
Posted In: JavaScript |
No Comments
Sep 25th, 2007
I have been playing around with jQuery a lot, as I am building a new site devoted to ski mountaineering. The site is progressing slowly, as I don't have a lot of spare time these days. Hence my desire to use a js library to speed up development and abstract the browser differences.
I really enjoy jQuery so far, and am amazed at how quickly I can build out functionality. The maintainability of the code I am writing is a different story. Anonymous functions nested n times; not sure that sites right with me if I was trying to write robust and testable code. But for a personal site, it works and the impetus is on me to write good code (although some libraries/frameworks make it easier).
One thing that tripped me up was ajax error handling. I didn't want to use the convenience methods like $.get because I think you need to plan for an error. I am using an alert if the ajax call fails, so a user would know why clicking on a link was
not doing anything. In IE, it was triggering two alerts. I was putting in a bogus url, as I am developing locally and that is the easiest way to trigger an error. I am still not sure why it called my error function twice in IE and once in FF, but in reading the documentation I found out three parameters can be passed into the error function. The second and third parameters, error string and the exception, are null in the extraneous error call, so I can filter out the extra call. Not sure if it is because I am testing locally and the file doesn't exist, rather than a web server returning a 404 error. I'll have to run a test on a real server to see. Anyone else have this problem?
Posted In: JavaScript |
No Comments
Nov 27th, 2006
I was trying to dynamically add rows to a table and ran into a problem with both Firefox and Internet Explorer. I had a table with a couple rows of data and there was a link to add a new row at the bottom of the table (in its own row).
The javascript simply cloned the first row, cleaned out some values from the td’s and inserted the new row into the table before the last row (i.e., the inserted row would be the second to last row) . That's where the problems arose. In firefox, table.appendChild(newRow) functioned fine, but when I tried table.insertBefore(newRow,lastRow) it threw a DOMexception saying it could not replace the child node because it didn't exist. In Internet Explorer, I could use appendChild or insertBefore. It turns out, you need to append and or insert to the tbody html element, instead of the table element. A real basic example:
<html>
<body>
<table>
<tbody id="useThis">
<tr id="row1"><td>Row One</td></tr>
<tr id="row2"><td>Row Two</td></tr>
</tbody>
</table>
<script type="text/javascript">
//clone row1
var newRow = document.getElementById('row1').cloneNode('true');
//get row2
var row2 = document.getElementById('row2');
//add cloned row1 one before row2
document.getElementById('useThis').insertBefore(newRow,row2);
</script>
</body>
</html>
Posted In: JavaScript, firefox, Internet Explorer |
6 comments
Aug 28th, 2006
I have been working on a website that allows photo uploading and manipulation via a web interface. The webpage uses a hidden iframe so that uploading can take place without refreshing the page and AJAX that allows users to rotate and delete photos, again without refreshing the page. I am developing the application on my linux desktop and I thought it would be useful to simulate delays and normal response times if the application where on the internet, hence the use of the sleep function.
Nothing too spectacular here, but it is useful to throw sleep(10) into all your methods on the controller and see what happens. I found I had forgot to provide any user notification on delete of a photo. If the request was processed fast, as it always was on my desktop and usually was live on the internet, it wasn’t a problem because the JavaScript removed the photo. But if the request took 5 seconds to delete the photo, then the user would site there for 5 seconds wondering what was going on. Worse, they may hit the delete link again, causing another request to be sent, running a method to delete a possibly non-existent image. I guess the more I get used to AJAX and its idiosyncrasies, the less need I will have for this. But for now, it is a useful way to quickly simulate lag time on your desktop and ensure you are providing proper user notification.
On a different note, this application quickly became complex. I have wrapped all my JavaScript code into nice functions, but I was left wondering how I can better organize my code? Obviously using objects would help, and I need to become more familiar with JavaScript objects (It doesn’t seem worth the effort to just wrap the functions in an object). I was also left wondering what is the best way to organize code when your application becomes complex. Is the MVC paradigm somehow malleable to client side code? Something I need to investigate further….
Posted In: PHP, JavaScript |
No Comments
Aug 16th, 2006
Twice in one week I ran into the same problem. I put Google Maps on a webpage, only to find that the drop down navigation menu went behind the map. One navigation was nested ul's with CSS for formatting and a small piece of unobtrusive JavaScript to deal with IE's problem on not recognizing :hover on non "a" tags (suckerfish), while the other had JavaScript sprinkled into the code and a fairly complex script that animated the dropdown menu (slide effect).
The solution, which worked on Internet Explorer and Firefox, was to apply a style of "z-index:9999" to the dropdown menus. I had apply that style to a number of divs in the javascript powered menu, as putting it on the top container, which was a table, didn't seem to work. On the CSS menu, I used a selector to apply the z-index to all the uls in my nav, and it worked like a charm. Of course you don't have to use a value of "9999", just a number sufficiently high to prevent something else from appear above it.
Posted In: JavaScript, Mashup |
27 comments
Jul 22nd, 2006
Sitepoint has an interesting
interview with Jacob Nielson about usability and AJAX. One of the points Nielson brought up really strikes a cord with me. He says “It's important to remember that most web sites are not used repeatedly. Usually, users will visit a given page only once.â€. I think this is key when deciding whether to implement functionality with DHTML/AJAX. If it is a content management system or some other web application that people will continually use, you can expect more from them. They may (definitely not always) be willing to spend time learning how to use the features in order to make themselves more productive.
Conversely, on public facing websites, people want to access information as quick as possible without spending the effort nor time to learn something new. So if you create some fancy effects that are not in widespread use, you run the risk of confusing people and causing them to abandon the site. Add to this the skill-level, if you can call it that, of the average internet user and certain DHTML effects can be downright confusing. I recently saw someone somewhat baffled by Google’s mapping application. They didn’t realize you could scroll by clicking the mouse and moving it and they didn’t know how to effectively use the controls to pan in and out. For this person, MapQuest might be a better site in their eyes because it behaves as they would expect. Of course, as more applications make use of DHTML, the average user’s familiarity will increase. But this functionality is brand spanking new for the most part and the average user doesn’t know nor care about AJAX or how cool drop and drop components are…
Posted In: JavaScript |
2 comments
Jul 15th, 2006
I noticied (and read online) that Google had put in scrolling on their maps via the mouse wheel. But I just stumbled across something new while using Gmail - if you are typing an email and hit crtl+s, the normal Microsoft save command for word docs, it will actually use AJAX to save the email into your drafts (works on both IE and firefox on windows, but you have to have focus on the text area for composing the email in order for it to work) . They had auto-save, but this is something I wasn't aware of. I also tried it on firefox on Linux, but it didn't do it. You may be wondering why I hit crtl+s? It was a habit I developed while working as a webmaster for a ski area. Not that often, but often enough, the power would go out and I would lose all my unsaved data on the computer. It only had to happen a couple of times before I developed a habit if saving all the time. Such is the price of working at a ski area and being able to get powder for lunch...
Posted In: JavaScript, firefox, Internet Explorer |
No Comments
Jul 4th, 2006
I just finished creating a “value†calculator for a company using JavaScript. It computed the overall value a person would save by joining the organization – nothing fancy, just a couple of input boxes, some simple equations and 10 values to display. What was tricky, at least for a JavaScript neophyte like me, was getting the numbers in the correct format - both on output and input.
For instance, something as trivial as grabbing the number from an input box and using in a calculation took me some time to figure out. First, I didn’t want to limit what the user could put into the text box. Ie, I wanted to allow “$30,000â€, “30,000†, “30000†or “ 30,000.00†and not force the user to enter some contrived number for the sake of computational ease. After some mucking around, I came up with this:
// get the value from the form field
var cop = document.getElementById('cop').value;
//strip out all non-numbers, except a decimal and turn into a float
cop = parseFloat(cop.replace(/[^.0-9]/g,''));
// if it still isn’t a number (user had nothing in the field), make it 0
cop = isNaN(cop) ? 0 : cop;
I remember when I was very new to JavaScript and programming in general, and didn’t know to use parseFloat and parseInt. If you forget to do that for a value you have pulled from a input box, JavaScript will typically concatenate the value, as it treats it as a string:
// num = 6 (as a string)
Var num = document.getElementById('cop').value;
//outputs “65†instead of 11
alert(num + 5);
Next, I had to display the damn thing like this “$30,000.06â€. I started with a regular expression I have used in PHP before: /(?<=\d)(?=(?:\d\d\d)+$)/ . But javascript complained about “?<=†which is a positive lookbehind. Apparently, JavaScript doesn’t support it. Digging into my books, I found toLocaleString(), which seemed to meet my criteria. In fact, it works without a problem in Internet Explorer (at least 6.0), but it exhibits some strange behaviors in Firefox. In Firefox, it doesn’t display the “.00†if the number doesn’t already contain it and it will only display one decimal place without the trailing “0â€. It wasn’t a major problem, but an annoyance nonetheless. I tried using toFixed(2) and then toLocaleString(), but it still didn’t work in Firefox and rather than writing extra code, I let it be.
One final note. Using the CSS selector :disabled doesn’t work in Internet Explorer. I wanted to hide input boxes I used to display the numbers and disabled them. But in Internet Explorer, it ignores any “font-color†declarations and outputs grey text, so it will look different than the rest of the text. I just hide the input boxes, and left them as enabled…
Posted In: JavaScript, regular expressions |
No Comments
Mar 21st, 2006
Continuing from the last post, for the javascript I checked the credit card number of form submittal, (along with a lot other things, like required fields, correct phone numbers, etc… ) and if it isn’t correct, throw an alert and prevent the form from submitting (Ignore the PHP tags, haven't gotten around to adding a generic code highlighting plug yet...).
[php]
var ccType = document.getElementById('credit_card').value;
switch(ccType) {
case 'AMEX':
var goodCC = /^3[47]{1}[0-9]{13}$/;
break;
case 'Visa':
var goodCC = /^4[0-9]{15}$/;
break;
case 'Mastercard':
var goodCC = /^5[1-5]{1}[0-9]{14}$/;
break;
case 'Discover':
var goodCC = /^6011[0-9]{12}$/;
break;
default:
var goodCC = /^[0-9]{15,16}$/;
}
if(!goodCC.test(ccNum)) {
problem += "Please enter in a valid credit card number (only use numbers)\n";
}
}
if (problem != ‘’) {
alert(problem);
//code to stop the form from submitting
}
[/php]
Posted In: JavaScript, regular expressions |
No Comments