Clean up your code with RxJS!

Today I would like to talk a bit about the Reactive Extensions for JavaScript (aka LinqToEvents).  From when I heard the first rumors about it, I had a very keen eye on the project because I just felt there was something fascinating about it.

Unfortunatly, I didn’t really “got it right” and never found a real use case to test things out. But with all this noise around the new jQuery deferred API I recognized some common ground between those two technics and started digging into RxJS/Rx .NET again.

Finally, I was able to scratch a bit on the surface which I would like to share with you 🙂

So let’s say you have built a web app with a search textbox that fires up an ajax request while the user is typing. This is quite common and I’m sure you have done that before.

You don’t want to fire up the ajax call on every keystroke but only when the user stopped typing instead.  So, you just encountered the first brainer. What does it mean “when the user stopped typing”?

There is no native way to do something like that:

$('#searchinput').bind('StoppedTyping', function() {
  console.log('stopped typing')
});

What you actually mean is, “I want this code only to execute when 500 milliseconds have passed after the last occurrence of the ‘keyup’ event”.

So, maybe u managed this by saving a timestamp inside an outter var. Or you were lucky enough to come up with a solution which doesn’t  rely on an outter var at all.

This is the Rx way to acomplish what I described earlier. How does that look for you? Pretty straight forward, isn’t it?

$(document).ready(function(){
    $('#myInput')
        .toObservable('keyup')
        .Select(function(){ return $('#myInput').val(); })
        .Throttle(500)
        .Subscribe(function(text){
          console.log('fire up ajax call'); 
        });
});

There is no outter var, therefore no side effect. I’m not going much into the details because there are better resources to look this up.

So let’s sum things up so far. While you type, nothing fires. The call will fire after you finished typing. But what if you finished typing a word, the call fires, you type again but end up with the same word for which you just fired the ajax call, the moment before. Let’s say we want avoid such a needless call. It’s trivial with RxJS!

$(document).ready(function(){
    $('#myInput')
        .toObservable('keyup')
        .Select(function(){ return $('#myInput').val(); })
        .Throttle(500)
        .DistinctUntilChanged()
        .Subscribe(function(text){
          console.log('fire up ajax call');
        });
});

Easy, isn’t it?

Or how about avoiding calls, for words with less than three letters?

$(document).ready(function(){
    $('#myInput')
        .toObservable('keyup')
        .Select(function(){ return $('#myInput').val(); })
        .SkipWhile(function(text){ return text.length < 3; })
        .Throttle(500)
        .DistinctUntilChanged()
        .Subscribe(function(text){
          console.log('fire up ajax call');
        });
});

This is just scratching the surface of what can be down with RxJS. I'm just starting my RxJS journey…but I like what I have seen so far!

Accessing return values from multiple Deferreds

It’s been a while since I wrote my last posting. As I feel that I am constantly in a hurry I rarely manage to find some time *sigh*.

However, too many interesting stuff which is worth blogging keeps flooding our beloved tech world! One of those things is the new Deferred object in jQuery 1.5.

I won’t go into every detail about what Deferreds are for because Eric Hynds already wrote an awesome article about it.

Just to give an example: Some month ago, I asked on stackoverflow which was the best way to spin off several async calls and do something when all those async calls have completed. Well, that’s one of the things that Deferreds can solve.

Today I want to show you how to deal with that and also how to deal with it if each call returns a value which you need to have access to afterwards.

Let’s look at this code:

$(document).ready(function(){

    var example = function (){
        var deferred = $.Deferred();

        setTimeout(function(){
            deferred.resolve(5);
        }, 1000); //Will finish first

        return deferred.promise();
    };

    var example2 = function (){
        var deferred = $.Deferred();
        setTimeout(function(){
            deferred.resolve(10);
        }, 2000); //Will finish second

        return deferred.promise();
    };

    $.when(example(), example2())
        .then(function(arg1, arg2){
            console.log("Example1 (Should be 5): " + arg1);
            console.log("Example2 (Should be 10): " + arg2);
          });
    });

jsFiddle: http://jsfiddle.net/cburgdorf/M4JKR/

We created two Deferred objects (Example1, Example2) which both resolve with an return value. In the callback, which is called on $.then we have access to those return values. It might be obvious to you (but wasn’t to me) that those parameters will be sorted in the order in which the Deferreds were registered to $.when. That means, no matter in which order those async operations complete, you will be save to access the values in the expected order.

Here comes the proof with the operations turned around:

$(document).ready(function(){

    var example = function (){
        var deferred = $.Deferred();

        setTimeout(function(){
            deferred.resolve(5);
        }, 2000); //Will finish second

        return deferred.promise();
    };

    var example2 = function (){
        var deferred = $.Deferred();
        setTimeout(function(){
            deferred.resolve(10);
        }, 1000); //Will finish first

        return deferred.promise();
    };

    $.when(example(), example2())
        .then(function(arg1, arg2){
            console.log("Example1 (Should be 5): " + arg1);
            console.log("Example2 (Should be 10): " + arg2);
          });
    });

jsFiddle: http://jsfiddle.net/cburgdorf/vmLfF/

There is a lot more to discover with jQuery Deferreds, but I hope you found this little piece useful 😉

struggleing through the ajax world

We recently decided to port our website over to the Kohana Framework. A great decision! However, we are not only switching over to Kohana and the MVC approach, we also want to make more use of ajax. Not at least because we want to give our users a better experience. Whatever, I will go more deeper into the whole migration process in some weeks. Today Im asking the jQuery heros for their help.

What I want is

1. to save a form

2. to show a modal box, telling the user the form can’t be saved, incase of any validation rule violation

3. to ask the user for confirmation incase of any special conditions. For example, if he changes his zipcode he will be informed that this will lead to loosing his credit points and he must confirm with yes in order to save the form.

What I have

I won’t post every detail but hopefully enough to understand my problem 😉 I should also mention that I use the simplemodal box[1] to show the dialog. And it might be also worth knowing that Im a total noob on javascript and the whole ajax thing.

The View

I have a simple form like that:

<?=form::open('editroot/save', array('id' => 'edit_root'), NULL)?>
<table border="0" cellpadding="5" cellspacing="5">
<tr>
<td width="100">Vorname:</td>
<td><?=form::input('firstname',$firstname, ' class="inputbox_mp" maxlength="50"');?></td>
</tr>
<tr>
<td>Nachname:</td>
<td><?=form::input('lastname',$lastname, ' class="inputbox_mp" maxlength="50"');?></td>
</tr>
</table>
<?=form::close()?>

And my javascript looks like that…


$(document).ready(function()
{
     //attach onSubmit to the form
     $('#edit_root').submit(function()
     {
         //When submitted do an ajaxSubmit
         $(this).ajaxSubmit(
         {
             dataType: 'json',
             success: function(data, responseCode)
             {
                 if (data.category == 'conditionApplied')
                 {
                     confirm("Are you sure you want to ignore condition XYZ", function ()
                     {
                         jQuery.post('<?=url::base(FALSE)?>editroot/save', {ignoreConditions : "ignoreConditions"});
                     });
                 }
                 else if (data.category == 'invalid')
                 {
                     confirm("Your data is wrong (invalid email etc.)", function ()
                     {
                         // do nothing because the user has to change his inputs
                     });
                 }
             }
         });
         //return false to prevent normal submit
         return false;
     })
 }); 

function confirm(message, callback)
{
    $('#confirm').modal(
    {
        close:false,
        position: ["20%",],
        overlayId:'confirmModalOverlay',
        containerId:'confirmModalContainer',
        onShow: function (dialog)
        {
            dialog.data.find('.message').append(message);
            // if the user clicks "yes"
            dialog.data.find('.yes').click(function ()
            {
                 // call the callback
                 if ($.isFunction(callback))
                 {
                     callback.apply();
                 }
                 // close the dialog
                 $.modal.close();
            });
        }
    });
}

The Controller

	public function save()
	{
		if(request::is_ajax())
		{
			$post = new Validation($_POST);
			$post->add_rules('firstname', 'required');
			if(!$post->validate())
			{
				echo json_encode(array('category'=>'invalid','text'=>'Error during saving'));
			}
			else
			{
				if (isset($_POST['ignoreConditions']))
					$this->store();
				else
				{
					echo json_encode(array('category'=>'conditionApplied','text'=>'Error during saving'));
				}
			}
			$this->auto_render=false; 
			return;
		}
	}
	
	private function store()
	{
		//its valid, the user had been asked to accept special conditions etc.
                //we are ready to update the user account in the database
	}

Let me explain what the code does:

1. When the user clicks on the submit button, the $_POST array will be send through an ajax request to the controller.

2. The controller validates the data:

Now A.) If the user made an invalid input (missing firstname in this example) the controller will return ‘category’=>’invalid’. The javascript will show a message telling the user that the data was wrong.

Or B.) If the user made an input that will lead to something special (loosing credit points etc.) the controller will return ‘category’=>’conditionApplied’. The javascript will show a confirm message asking the user if he was sure to save and accept the special conditions coming along with his decision.

The first one is not really interesting because it means the user can not proceed until he changes his input. However the second one is more interesting. Incase the user clicks ‘Yes’ I want to send the $_POST data again and would like to append a value as an indicator for the controller.

It’s easy to send this single $_POST indicator but I need it to be send TOGETHER with the actual data. I find that hard to manage. Does it mean that I need to manipulate the form by appending a hidden field or anything?

And somehow, I think the whole js code smells and it feels like a dirty hack to me. There must be a more straight forward approach to it, isnt there? I also dislike the way I return the json answers…however I just took an example from the web and changed it a bit to make it run for me 😉

Happy for anybody trying to help me on this…

UPDATE

I finally got it working on my own. So here is what I did:


$(document).ready(function()
{
     //attach onSubmit to the form
     $(document).ready(function() 
{ 
	//attach onSubmit to the form
	$('#edit_root').submit(function()
	{
		//When submitted do an ajaxSubmit
		$(this).ajaxSubmit(
		{
			dataType: 'json',
			success: function(data, responseCode) 
			{
				if (data.category == 'conditionApplied')
				{
					confirm(data.message, 'irgendein title', 'yesAndNo', function () 
					{
						var queryString = $('#edit_root').formSerialize(); 
						queryString = queryString + "&acceptConditions"
						jQuery.post('<?=url::base(FALSE)?>editroot/save', queryString);
					});
				}
				else if (data.category == 'invalid')
				{
					confirm(data.message,'irgendein anderer title', 'ok', function () 
					{
						// do nothing because the user has to change his inputs
					});
				}
			}
		});
	//return false to prevent normal submit
	return false;
	})
}
);  

function confirm(message, title, buttons, callback) {
	$('#confirm').modal({
		close:false,
		position: ["20%",],
		overlayId:'confirmModalOverlay',
		containerId:'confirmModalContainer', 
		onShow: function (dialog) {
		
		if (buttons == 'yesAndNo')
			dialog.data.find('.ok').remove();
		else if (buttons == 'ok')
		{
			dialog.data.find('.yes').remove();
			dialog.data.find('.no').remove();
		}
			
			dialog.data.find('.message').append(message);
			dialog.data.find('.header').append('<span>' + title + '</span>');			
			dialog.data.find('.yes').click(function () {
				if ($.isFunction(callback)) {
					callback.apply();
				}
				$.modal.close();
			});
			
			dialog.data.find('.ok').click(function () {
				if ($.isFunction(callback)) {
					callback.apply();
				}
				$.modal.close();
			});
		}
	});
}

The Controller

		public function save()
	{
		if(request::is_ajax())
		{
			$post = new Validation($_POST);
			$post->add_rules('firstname', 'required');
			if(!$post->validate())
			{
				$errorMessage = '';
				$errors = $post->errors();
				foreach ($errors as $key => $val)
				{
				   $errorMessage .= $key.' failed rule '.$val.'<br />';
				}				   
				
				echo json_encode(array('category'=>'invalid','message'=>$errorMessage));
			}
			else
			{
				if (isset($_POST['acceptConditions']))
					$this->store();
				else if (1 == 1) //special condition is true
					echo json_encode(array('category'=>'conditionApplied','message'=>'Wollen Sie Kondition XYZ in Kauf nehmen?'));
				else
					$this->store();	
			}
			$this->auto_render=false; 
			return;
		}
		else
		$this->template->content = 'Ohne Javascript nix los :-(';
	}
	
	private function store()
	{
		//its valid, the user had been asked to accept special conditions etc.
	}

Well, basically I wasn’t really aware that Im using jQuerys form plugin here. Once I figured it out, I just checked the docs and found out I can serialize the form and just append any variable I want. The rest is more or less some sugar…I modified the confirm dialog to be flexible with its button etc. Maybe this will ease the pain of some other ajax newbie out there…

[1] http://www.ericmmartin.com/projects/simplemodal/

Writing a GetFirstDayOfWeek(int week, int year) function

It took me some time to write a DateTime GetFirstDayOfWeek(int week, int year) function yesterday. I’m not going to say HOW long it took me but just…I HATE date calculations. This should be a built in .NET feature!

Hopefully this will ease the pain of someone out there!

public static class DateHelper
	{		

		public static DateTime GetFirstDayOfWeek(int week, int year)
		{
			ThrowExceptionOnInvalidWeek(week);
			return GetFirstDayOfFirstWeek(year).AddDays((week - 1) * 7);
		}

		private static void ThrowExceptionOnInvalidWeek(int week)
		{
			if (week < 1 || week > 54)
			{
				throw new ArgumentException("the week must be within 1 and 54");
			}
		}

		private static DateTime GetFirstDayOfFirstWeek(int year)
		{
			DateTime firstDayOfYear = new DateTime(year, 1, 1);
			DateTime firstDayOfFirstWeek = new DateTime(year, 1, 1);			

			if (firstDayOfYear.DayOfWeek == DayOfWeek.Monday)
			{
				firstDayOfFirstWeek = firstDayOfYear;
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Tuesday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-1);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Wednesday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-2);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Thursday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-3);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Friday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-4);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Saturday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-5);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Sunday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-6);
			}
			return firstDayOfFirstWeek;
		}

	}

Some trivia out of my life

I haven’t been blogging for a while but in fact several things happened that were worth to do so. I won’t go too much into detail as I would like to keep this blog a place for technic stuff…basically at least. However, here comes some trivia out of my life.  Some weeks ago I got my green belt in Taekwondo…actually, I got it again for the second time in my life. I started Taekwondo with the age of 10 or so and had to quit it being a green belt for some personal reasons. However I always knew I would start it again. For those of you who are not familiar with the different martial arts. Have a look at this video:

Two years ago I started Taekwondo again but decided to begin from scratch as a white belt and did all the tests again. Although I would have been allowed to wear my green belt I didn’t like to wear a belt that doesn’t reflect my phyisical skills. So, now Im once again a green belt and everything from now on will be new for me. Exciting stuff ahead!

Banshee

Banshee…yeah…banshee!!! For those of you following me on twitter you should have noticed there are already three patches from me commited to trunk. Rocks! I’m getting deeper into the source and I’m looking forward to hack on bigger tasks. I already got so much back from the banshee project. My coding skills developed a lot…it’s amazing how the banshee source is like a teacher to me!

Got one thing of my personal “must do” list

You know the phrase “a man must build a house, plant a tree, get a son and see AC/DC. Well, I just saw AC/DC yesterday…live in Dortmund. Stunning! Absolutely! I can’t believe what these guys perform on the stage…

banshee 1.4.2 makes me a lucky hacker

Some weeks ago I blogged about my first banshee patch which fixed the alignment issues with banshees track number. I can say proudly that my patch has recently been commited by Gabriel Burt and made it into the 1.4.2 release.  Some might think it’s ridiculous to blog about it, but some also might feel and share the joy.

Of course, what I did wasn’t world shaking, it’s truly just a small bit of code. But banshee is a big, fast growing project that will soon become one of the most important media player applications due to its clean code base. That’s at least what I think. Up to the moment the project is available for the linux and apple plattform while the windows version is still under development.  I guess the influence will rapidly grow once the player will be full functionally on all three major plattforms.

So, beeing a part of this great project just feels great. Some month ago I wouldnt have thought I could find my name on the list of banshee contributors in the near future.  But here it is:

banshee_contributors

What is the intension of this blog post? Am I just a geek looking for some fame? NO! I want to share the joy that I have with others and I want to encourage others to step up and join the project. The patch I wrote is the perfect proof, that it is possible for beginners to join the project and find some easy tasks to hack on.  It feels awesome to be  a part of a great project and hack together with other well known free software hackers. No money would have brought me the joy that I feel with that.

I defenetly will keep it up and Im quite confident that there will be banshee patches of my own in the future…

customize tasques todays tasks color

While I reside in Berlin at my girlfriends parents house for some days, I started to have a look at the young tasque project. Tasque is a small programm that creates to-do lists. Its quite handy and can use different backends (including evolution). And the best, its entirely written in c#!

I picked one of the suggested enhancement bugs and started to hack on it!

So here it goes. The color for todays tasks can now be customized from the preferences dialog:

customize todays tasks color
customize todays tasks color

I like to thank Sandy Armstrong for his help. The patch is now awaiting its review and will hopefully soon be committed to trunk.

Bugzilla Link: http://bugzilla.gnome.org/show_bug.cgi?id=563748

My first banshee patch fixed #553322

Yesterday I submitted my first patch for the popular banshee player. It fixes the issue that the track number is not right aligned.  It’s actually my first patch ever contributed to an open source project.  I have a desire growing inside me, that tells me to contribute code to open source projects. While I know that time is a valuable thing – and especially when you have to share it with many other persons and projects – I think whenever you feel a desire growing inside you, you have to follow it.

The patch I wrote isn’t worldshaking but means a lot to me though.

I still don’t know if or when it will be accepted, but if you like to check it out, you can get it here:

http://bugzilla.gnome.org/show_bug.cgi?id=553322

Bug 553322:

banshee_bug_5533221

Fixed 😉

banshee_bug_553322_fixed

…to be continued!

Picasa webalbum fetcher

Some days ago I wrote a little tool to download whole picasa web albums. I actually wrote it for my gf, who wanted to download a friends album. I was looking around but couldn’t find any comfortable way to get that done without installing the picasa software.

The tool I wrote is based on mono/gtk# and runs on linux and windows and I guess it should also run on a mac (not tested). If anybody cares for a .NET/Winforms solution – I have that, too. Just ask and I’ll bring it on.

Actually the winforms version is even more mature, because that’s the one I created for my girlfriend but as I use linux myself, I thought I should make an gtk# version for this blog.

I seperated the process of fetching the album into an assembly so that makes it easy for you to implement it anywhere else. Use it for whatever you like.

album fetcher in action
album fetcher in action

Download source and binary:

my personal experience with open source

I actually have been crazy about computers since I was a little boy.  It started even some years befor I had my first computer when I had some kind of  “kids-education-computer” which was able to understand some basic programing. I must have been maybe 10 years old.  Later when I had my first real computer I went on with some basic programming in QBasic. I remember I coded some kind of table tennis game…it where ugly flickering and the ball only had three fixed routes it could pass 😉

My brother were also coding, but he focused more on Lotus Approach which was some kind of database system like MS Access. He build up an icon gallery with various kinds of filter and search possibilities.  I can well remember the nights my brother and me were both coding in our rooms. It was some kind of competition and we kept our code closed source 😉

Well, you can say, I have been crazy about programming and computers in general for many years already . But the majority of my techie life I was using microsoft products and all my coding was focused on the microsoft plattform (QBasic, VB, .NET) .  For many years that was the only thing I knew.

Well, I must say my connection to the computer world changed drastically in the last three years. I began to get curious about Linux more and more, I tried some distributions, I was kinda fascinated but still not ready to move over. For more or less one year I was pending…

…for maybe two years already I got rid off Windows on all my machines. Well, I still work a lot on windows machines at my job.  But all the private things I do, and I guess half of my business time I’m working on a linux machine. The funny thing is, through linux, now I see how less I know about windows.  I mean, all the underlying process of a operation system are much clearer on linux for me than they are on windows. I know programms use dbus to communicate with each other on my linux desktop, when I need to get information about hardware devices HAL is there for me…I know HAL will soon be replaced by DeviceKit because HAL became too messy and huge to maintain. I could go on with that list for ever. Why is that? Why did I learn so much about the linux operation system in that short time?

Well, the cool thing about  linux[1]  is that not only the code is open and can be downloaded from anywhere, but the whole scene is open, too! At first you will start reading and posting in forums.  Later on you might subscribe to mailing list where the core developers of one system part are discussing their ideas. You might be also reading the blogs and planets[2] of all those hackers involved. The scene is so open and friendly that I sometimes can not really believe it.  Its not unlikely to get in touch with one of the core hackers who might be employed at one of the big global players like Red Hat[3] or Novell.

I also must say that my personal coding skills have improved a lot because of this whole open source thing. Because you get the opportunity to work on cool projects, to see their code, to read the svn logs, to discuss the design of the functions etc.

Well, I must say while I have been crazy about computers for nearly all my life, open source turned that craziness into passion.

[1] I use the term “linux” meaning the whole distribution while I know this is wrong.
[2] A planet is a collection of a bunch or blogs which are related to someting. I often read:
planet.gnome.org
planetkde.org
go-mono.com/monologue/
planet.fedoraproject.org/
planet.ubuntu.com
[3] A big THANK YOU to Dan Williams (the core developer of the NetworkManager which is a main feature on most distributions) for all his help he is providing on the network manager list.