JavaScript Related Posts by ThinqLinq

ThinqLinq Samples on Github

When I first created this site, I used it both as a test bed for technologies as I played with them and as a repository for others to use for my presentations and other insights. Over the years people have been free to grab these samples, but haven’t had good ways of giving back to help improve the samples.

In the mean time, there have been quite a number of technology changes. While I may have been late to the party on some, there’s only so many things one can focus on. One of the advances we’ve seen is the explosion of use of web based distributed source control systems. In that light and as an effort to both make it easier for you to access the sample projects, and help you give back, I’ve started publishing my samples on GitHub. While you’ll still be able to download the samples from my downloads page, I won’t be updating them as new versions ship and instead will plan to keep the samples updated on GitHub instead.

At this point, the following projects are available via my Github repository:

  • RX Samples – Includes Windows Phone, Silverlight, Windows Store App, WebForm, HTML/RxJs, and SignalR samples with code in VB, C# and JavaScript.
  • WebAPI Samples – Includes Sample recipe EF 6 models and Web API endpoints.
  • Signalr RX Samples – Includes Chat samples in Web and WPF, Reactive Sensors in Web and Console projects, and Drag/Drop with MVC and WPF

As always, please let me know what you Thinq. Does Git make accessing the samples easier? Is there something else I should add to the samples?

Posted on - Comment
Categories: C# - Entity Framework - JavaScript - LINQ - Rx - RxJs - SignalR - VB - WinRT - WP7 -

Reactive Translator for RxJs

For several years, I’ve been demonstrating using Reactive Extensions to handle taking user input and providing real time translations into multiple languages. This code sample has been so popular that even Soma posted an example using the Bing translator in his introducing Rx post. In most cases, they only issue a single request or issue multiple individual requests for multiple languages. To add a bit of fun to my demo, I decided to spice it up a bit and turn the list of destination languages into another observable that I can join with as well. I’ve had this sample available in my Rx downloads for some time including one for RxJs, but haven’t updated them to newer versions (curently 2.2.2) until now. I figured it was about time that I shared my version.

To begin, let’s create a UI. We’ll keep it simple to allow us to focus on the code that comes later:

    <input type="text" id="TextToTranslate" size="80" />

    <div id="output">
    </div>

As they say at Staples, “That was easy.”

Next comes the fun part. Before you can do anything though, you do need to sign up to get a free Bing App ID. I’m not going to share mine Winking smile. Once you have that, your ready to code. But what are we going to do in our code? This example combines three observable sequences: User key presses, destination languages, and service request/responses. In order to work with the observables and to make it easy to work with our DOM, we need to start by importing two JavaScript libraries: jQuery and Rx (we only need the rx.lite.js version for this example).

    <script type="text/javascript" src="Scripts/jquery-2.1.0.js"></script>
    <script type="text/javascript" src="Scripts/rx.lite.js"></script>

Of our three observables, the second one is the easiest, so let’s get it out of the way first. To turn an array of languages into an observable sequence, we use the fromArray generator on a simple JavaScript array.

var destLanguages = ["de", "es", "zh-CHT", "fr", "it", "ar", "ht", "tlh"];
var languagesObs = Rx.Observable.fromArray(destLanguages);

With that out of the way, Let’s take a look at how we are going to issue the service requests to Bing and turn them into an observable stream. We’ll use the jQuery ajax method to issue our request to the Bing translator using jsonp and pass in the required app id, destination language (to), source language (I speak American English, so ‘from’ is ‘en-us’) and the text we want to translate (text). We can then use JavaScript promise to access this invoker and use RxJs’s fromPromise to turn it into an observable stream that returns the string result.

var translate = function (text, lang) {
    var p = { appId: appId, to: lang, from: 'en-us', text: text };
    var promise = $.ajax({
        url: 'http://api.microsofttranslator.com/V2/Ajax.svc/Translate',
        data: p,
        dataType: 'jsonp',
        jsonp: 'oncomplete',
    }).promise();
    return Rx.Observable.fromPromise(promise);
};

Now that we have these two observables, we need to wire this up with the user’s key presses. Instead of going on and on about each step, here’s the code in it’s glory detail annotated with what each line is doing.

// Get the keypresses
var textInputDetected = Rx.Observable.fromEvent($("#TextToTranslate"), 'keyup')
    // Wait for 1/2 second to see if they're still typing
    .throttle(500)
    // They're done typing. Clear the last output
    .do(function (_) { $("#output").empty(); })
    // Get the input string
    .select(function () { return $("#TextToTranslate").val(); })
    // If it's the same as the last one, don't re-issue the request
    .distinctUntilChanged()
    // Merge the search string with the list of languages
   .selectMany(function (text) {
        return languagesObs.select(function (t1) { return { source: text, dest: t1 }; });
    })
    // Call the service passing the source string and destination language
   .selectMany(function (sourceDest) {
       return translate(sourceDest.source, sourceDest.dest)
            // Return the destination language and translated result from the service
            .select(function (result) { return { dest: sourceDest.dest, translation: result }; });
    });

d = textInputDetected.subscribe(function (x) {
        // Add the result to the list
        $("#output").append(x.dest + ' : ' + x.translation + '<br />');
    },
    function (err) {
        // In case of an error, show the error
        $("#output").append(err + '<br />')
    });

We start by getting the keyup events for the input textbox and turning that into an observable stream (using fromEvent). This is an expensive service operation, so we throttle the request for 1/2 of a second before continuing to let the user finish typing. There’s no reason to send each keypress through the translator. The do method allows us to cause side effects, in this case to clear the last translated results if any exist. We then transform (using select or map) the result to get the user’s supplied text and pass that as the resulting stream. Similar to throttle, we also want to make sure that the user hasn’t just entered the same value twice which would result in the same translation results. We optimize our requests by not reissuing the request using distinctUntilChanged.

The fun stuff comes next. Here we start to merge our observables using selectMany (or flatMap) to match up the input text with the observable list of destination languages. Once we have that, we selectMany again, this time passing in the source string and destination language into the translate method that returns the observable string result and based on that result, we project out the result along with the enclosing destination language.

To conclude, we subscribe to the end observable stream and either append the result to the output list in the case of onNext, or append the error message for onError. Since this is set up over observables, the user can just start typing another string and the process will react to the request all over again. To put this all together, here is the complete code. Remember to get your AppId before you use it because the one I’m showing here won’t work.

    <input type="text" id="TextToTranslate" size="80" />

    <div id="output">
    </div>

    <script type="text/javascript" src="Scripts/jquery-2.1.0.js"></script>
    <script type="text/javascript" src="Scripts/rx.lite.js"></script>
    <script type="text/javascript">
        var appId = "GetYoursAt http://www.bing.com/developers/appids.aspx";
        var destLanguages = ["de", "es", "zh-CHT", "fr", "it", "ar", "ht", "he", "ja", "ko", "no", "ru", "th", "tlh"];

        (function ($) {

            var translate = function (text, lang) {
                var p = { appId: appId, to: lang, from: 'en-us', text: text };
                var promise = $.ajax({
                    url: 'http://api.microsofttranslator.com/V2/Ajax.svc/Translate',
                    data: p,
                    dataType: 'jsonp',
                    jsonp: 'oncomplete',
                }).promise();
                return Rx.Observable.fromPromise(promise);
            };

            // Turn the language array into a cold observable for the selectMany below
            var languagesObs = Rx.Observable.fromArray(destLanguages);

            // Get the keypresses
            var textInputDetected = Rx.Observable.fromEvent($("#TextToTranslate"), 'keyup')
                // Wait for 1/2 second to see if they're still typing
                .throttle(500)
                // They're done typing. Clear the last output
                .do(function (_) { $("#output").empty(); })
                // Get the input string
                .select(function () { return $("#TextToTranslate").val(); })
                // If it's the same as the last one, don't re-issue the request
                .distinctUntilChanged()
                // Merge the search string with the list of languages
                .selectMany(function (text) {
                    return languagesObs.select(function (t1) { return { source: text, dest: t1 }; });
                })
                // Call the service passing the source string and destination language
                .selectMany(function (sourceDest) {
                    return translate(sourceDest.source, sourceDest.dest)
                        // Return the destination language and translated result from the service
                        .select(function (result) { return { dest: sourceDest.dest, translation: result }; });
                });

            d = textInputDetected.subscribe(function (x) {
                    // Add the result to the list
                    $("#output").append(x.dest + ' : ' + x.translation + '<br />');
                },
                function (err) {
                    // In case of an error, show the error
                    $("#output").append(err + '<br />')
                });
            
        })(jQuery);

    </script>

Thinq you can improve on this sample, let me know.

Posted on - Comment
Categories: RxJs - JavaScript - Rx -

HTML5 mobile apps with RhoMobile

It seems that every customer I talk with these days are chasing the elusive write once run anywhere. Typically, the best answer is to go with HTML5/JavaScript because it is the most ubiquitous option across devices. One recent customer that I was working with has a fleet of Windows Mobile 6.5 devices with native applications that they are looking to upgrade to a more modern hardware device. Unfortunately, the browser on the Windows Mobile 6.5 devices do not support HTML5, or the necessary app packaging mechanism to keep their employees from using the device browser to access non-company web solutions.

Initially, we looked at using the popular PhoneGap solution for packaging applications built with HTML. While PhoneGap does have wide support for a number of platforms, they do not support the older Windows Mobile operating system.

Motorola does offer a solution that does work with Windows Mobile as well as newer platforms, including iOS, Android, and Windows Phone 7+. Their RhoElements suite provides the ability to build mobile applications either using Ruby or even plain HTML5. They offer a descent tutorial for getting started including a sample which can access the native barcode scanner on the Motorola devices.

So how are they able to support HTML5 on a device based on an OS with IE6? They have essentially ported WebKit to Windows compact allowing them to render HTML5 reasonably well. This appears to work fairly well for relatively simple layout options and does appear to support relatively complex JavaScript frameworks, including jQuery, backbone, underscore, require.

One issue that I did run into is the performance can leave a bit to be desired. Don’t expect to see V8 level performance from their JavaScript interpreter. They are still restricted by the memory and operating system limitations that come with an OS and hardware that are over 5 years old. For example, I tried to implement the iScroll plug-in to allow for flick and finger drag support over a list of items. Just adding 100 items to the demos that come with iScroll brought the UI to a screaming halt (actually, the UI paused briefly and then would immediately scroll to the bottom of the list regardless of how far I swiped with my finger). This caused the list to become utterly unusable.

I did find the RhoMobile platform to be an interesting option for Windows Mobile and beyond, you do have to be careful what you try to get it to do. If you’re not careful, your result may still lead you down the road of write once, suck everywhere.

Posted on - Comment
Categories: WP7 - HTML - JavaScript -