Improving the hannoverjs.de site

A couple of days ago we came together again at the EDELSTALL to have our regulary hannoverjs meetup. It was that day when someone on Facebook asked me where he should have looked to figure out the date earlier.

My immediate rection was: “It’s every two month and it’s the fourth Thursday.”

Well, while me and a couple of others now about the rhythm and it’s also mentioned on the hannoverjs.de site, we shouldn’t assume that everyone does. It’s a huge fail when we rely on the assumption that everybody knows about that for sure.

So I pulled up my sleeves and automated the appearance of the date on our website so that it always points to the correct next date for our event.

And while I was at it, I rewrote the whole page with AngularJS (it previously used jQuery and Backbone). One of the benefits is that the talk section is much more maintainable now.

1. All talks for one event are written in it’s own file which follows the pattern MM_YYYY.tpl.html (Example)

2. Old talks can be viewed by just changing the date in the URL. (http://hannoverjs.github.com/hannoverjs.de/#/talks/01/2013)
(but I didn’t finish to extract the complete history from the commit logs yet)

3. There’s a default talk template which is automatically shown when nobody added a talk for the upcoming meetup yet.
So whenever one views the talk section, it should always make sense 🙂
On a side note: when you feel something about the site or the meetup in general could be improved. Don’t hesitate. Send PRs. Get in touch. We are a community.

From jQuery Deferred to RxJS ForkJoin

In a recent posting I blogged about how to process some code after several asynchronous operations have finished and how to access each return value of those operations no matter in which order those would finish.

To make this happen I used the new jQuery Deferred API. While this is a great way, I would also like to show you that there are other (even more advanced) ways to do so.

One of my heart warming interests is to dig deep into reactive functional programming and therefore digging into RxJS.

So let’s see how we can rewrite our example to make use of RxJS!

$(document).ready(function(){

    var example = function (){
        var deferred = new Rx.AsyncSubject();

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

        return deferred;
    };

    var example2 = function (){
        var deferred = new Rx.AsyncSubject();
        setTimeout(function(){
            deferred.OnNext(10);
            deferred.OnCompleted();

        }, 2000); //Will finish second

        return deferred;
    };

    Rx.Observable
      .ForkJoin(Example(), Example2())
      .Subscribe(function(args){
            console.log("Example1 (Should be 5): " + args[0]);
            console.log("Example2 (Should be 10): " + args[1]);
          });
    });

As you can see, nothing ground shaking happened to our code. Things are just named slightly different.

Did we gain anything? Yes, we did! ForkJoin not only combines two observable streames and waits until both have finished, but in fact returns a new observable stream. Having an observable stream as an first class object is a major benefit! For example, let’s say we are only interested if first stream matches a certain condition. We can just filter out the undesired values using the Where operator.

    Rx.Observable
      .ForkJoin(Example(), Example2())
      .Where(function(x){ return x[0] == 5; })
      .Subscribe(function(args){
            console.log("Example1 (Should be 5): " + args[0]);
            console.log("Example2 (Should be 10): " + args[1]);
          });
    });

And once again, the Where operator returns a new observable stream. This is great in terms of composability. You can easily just hand this new observable stream over to another component which will react on a stream of data that exactly matches the conditions the component was intended for.

Having events as first class citizen which you can compose and pass on, is what makes Rx so great.

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…