true false maybe

tom longson’s blog on software, design, and user experience

When form.submit() doesn’t refresh in IE6

I ran into a problem with some legacy code which looked like this:

Delete

And the corresponding function:

function doDelete() {
    var submitForm = function() {
        document.forms[1].method="POST";
	document.forms[1].action="myThing.do?dispatch=delete";
        document.form[1].submit();
    }
    var messageBoxConfig = {
		message:"Are you sure you want to delete?",
		title:"Confirm",
		style:YUI.widget.MessageBox.STYLES.CONFIRM,
		buttons:YUI.widget.MessageBox.BUTTONS.YESNO,
		callback:submitForm
    };
    YUI.widget.MessageBox.show(messageBoxConfig);
}

Inline onclick handler aside (again legacy code), IE6 would submit the form without causing a page refresh. The form would submit transparently, leaving the user on the same page, which meant the backend wouldn’t have a chance to update the page with the results of the action. Firefox on the other hand, had no trouble submitting the form as I would expect.

In order to get IE6 to behave correctly, I had to use a setTimeout 0 in order to defer the action, and get IE6 to execute it.

function doDelete() {
    var submitForm = function() {
        document.forms[1].method="POST";
	document.forms[1].action="myThing.do?dispatch=delete";
        setTimeout(function() {
            document.form[1].submit();
        },0);
    }
    var messageBoxConfig = {
		message:"Are you sure you want to delete?",
		title:"Confirm",
		style:YUI.widget.MessageBox.STYLES.CONFIRM,
		buttons:YUI.widget.MessageBox.BUTTONS.YESNO,
		callback:submitForm
    };
    YUI.widget.MessageBox.show(messageBoxConfig);
}

From what I understand, Internet Explorer 6 has issues with submitting from an onclick event in an anchor, although when I remove the MessageBox code, it worked as expected again (without the setTimeout). Some people have reported onmousedown instead of onclick gets IE6 to work correctly. Possibly the default behavior of the anchor is causing it to break? Nevertheless, using timers to queue the submit action makes it work properly regardless of the browser. Will update this post if I find out more!

Related posts:

  • Filed under: javascript
  • Published at: 5:34 pm on February 23, 2011
  • Comments: 1 comment
  • Written by: admin

PubSub in jQuery with Custom Events

Demo: PubSub in jQuery

Recently I did a post on Data Binding in JavaScript using the YUI3 Library as my base. h3 and MikeInVB wanted to see it in jQuery, so I rewrote it and it turns out is a great example of PubSub (publish / subscribe) for jQuery.

For this example, we’re using an object named DB, which is short for DataBind. Basically it’s an object with getters and setters.

  var DB = function (data) {
      this._d = null;

      this.set = function (data) {
           this._d = data;
      };

      this.get = function () {
          return this._d;
      };

      this.set(data);
  };

Really, this is just an abstracted way to store data. To create an instance of it, set it and get the value back, we would do something like:

var myData = new DB();
myData.set("We can't fight in here, this is a war room!");
console.log(myData.get();) // "We can't fight in here, this is a war room!"

But lets say, we want to subscribe to this data object, and be notified whenever it changes. Instead of polling it and checking to see if the value is the same as last time, we can use jQuery’s custom events to trigger a custom event.

  var DB = function (data) {
      this._d = null;

      this.set = function (data) {
           this._d = data;
           // notify all subscribers when this function is used
           $(this).trigger("change");
      };

      this.get = function () {
          return this._d;
      };

      this.set(data);
  };

Now, we can subscribe to it like this:

$(myData).bind("change", function() {
     alert("The data was changed!");
});

Additionally, we can access that data in our handler:

$(myData).bind("change", function() {
     alert("My data was set to " + myData.get());
});

You can set up any number of subscribers to myData this way now, and they’ll be triggered when that instance is set().

If you want to further improve DB, you can add a function to make it easier to attach change events, jQuery style:

  var DB = function (data) {
      this._d = null;

      this.set = function (data) {
           this._d = data;
           // notify all subscribers when this function is used
           $(this).trigger("change");
      };

      this.get = function () {
          return this._d;
      };

      // shortcut for functions trying to bind to the change custom event
      this.change = function (fn) {
          $(this).bind("change", fn);
      };

      this.set(data);
  };

With our new shortcut, we can subscribe to it like this:

var alexSez = new DB();
alexSez.set("Initiative comes to thems that wait.");
alexSez.change(function() {
    alert("Alex says: '" + myData.get() + "'");
});
alexSex.set("Welly, welly, welly, welly, welly, welly, well. To what do I owe the extreme pleasure of this surprising visit?")
// an alert will come up that says "Alex says: 'Welly, welly, welly, welly, welly, welly, well. To what do I owe the extreme pleasure of this surprising visit?'".

In the same way, you can set up two input boxes to “share” the same value by subscribing to a shared instance of DB like this:



  var myData = new DB();

  var inputs = $("#in1, #in2");
  myData.change(function() {
      inputs.val(myData.get());
  });

  inputs.bind("keyup", function(ev) {
      myData.set($(ev.target).val());
  });

Ta da!

If you’re still interested in PubSub for jQuery, I recommend checking out Jamie Thompson’s example using the $(document) namespace instead of specific object instances, or Peter Higgin’s jQuery.pubsub, which reportedly is significantly faster, although doesn’t allow object specific subscribing.

Demo: PubSub in jQuery

What do you think? Would you do this differently? Leave a comment, I read them all!

  • Filed under: javascript
  • Published at: 2:08 pm on April 23, 2010
  • Comments: 2 comments
  • Written by: admin

Data Binding in JavaScript

See the demo here: Data Binding in JavaScript

Back when I was in Flex land one of the things that I found to be really neat was data binding… you could essentially have widgets that would update if the data updated automagically. I also wanted to take a stab at doing publishing and subscribing in YUI3, so built this an object called DB, which stores data. It can do three things, it can set() data, it can get() data, and it’s an EventTarget, so you can subscribe to it’s change event:

var DB = function (data) {
    this._d = null;

    this.publish("change",{emitFacade: true});

     this.set = function (data) {
         this._d = data;
         this.fire("change");
      };

      this.get = function () {
          return this._d;
      };

      this.set(data);
};
 Y.augment(DB, Y.EventTarget);

And to instantiate an instance of DB you just do var myData = new DB();, and then you can subscribe to it any number of times to be notified when the data has been updated. For example:



var myData = new DB();
var inputs = Y.all("#in1, #in2");
myData.on("change", function() {
    inputs.each(function(node) {
        node.set('value', myData.get());
    });
});

inputs.on("keyup", function(ev) {
    myData.set(ev.currentTarget.get('value'));
});

This code is pretty simple. In YUI3 it creates an instance of DB, which has it’s own private data (unset initially), subscribes to the change event with a function that updates both text inputs on the page if myData gets set(), and then binds to the keyup event on the text inputs to call myData.set() whenever the contents of either text input has something typed into it. This results in a page where both inputs update whenever you type into either one.

See the demo here: Data Binding in JavaScript

Is this useful? Practical? UnJavaScripty? I don’t know, but I’d love to hear what you think ;-)

  • Filed under: javascript
  • Published at: 5:32 pm on April 15, 2010
  • Comments: 5 comments
  • Written by: admin

Better JavaScript Templating

I recently had to do some really heavy lifting with templates in JavaScript, and opted to use John Resig’s “Micro-templating” within the Underscore.js Library. It’s nice, you can write JavaScript within your templates to control your flow, like:

It's been <%= (new Date()).getTime() %> milliseconds since the epoch.

Which, if you’re like me is great. You could use Google Closure Templates, which probably is faster, but then you would have to precompile your templates, which is a pain.

The only problem I personally had with the Resig solution was that if you tried to call a variable that didn’t exist within your data object, it would fail horrifically, so I modified it slightly to be slightly more forgiving:

  // JavaScript templating a-la ERB, pilfered from John Resig's
  // "Secrets of the JavaScript Ninja", page 83.
  // Single-quote fix from Rick Strahl's version.
  _.template = function(str, data) {
    var fn = new Function('obj',
      'var p=[],print=function(){p.push.apply(p,arguments);};' +
      'with(obj){p.push(\'' +
      str.replace(/[\r\t\n]/g, " ")
         .replace(/'(?=[^%]*%>)/g,"\t")
         .split("'").join("\\'")
         .split("\t").join("'")
         .replace(//g, "',(typeof($1)!='undefined') ? $1:'','") // modified to allow undefined variables pass through
         .split("").join("p.push('")
         + "');}return p.join('');");
    return data ? fn(data) : fn;
  };

The 12th line where it says .replace(//g…) includes a test for the data that is being passed into the function that’s being created to output just an empty string if the variable is undefined.

  • Filed under: javascript
  • Published at: 4:51 pm on April 15, 2010
  • Comments: Comments Off
  • Written by: admin