1

Trying to get my feet wet with RxJS, specifically with rx.jquery. I found a little tutorial here and tried to set it up as follows. It's supposed to take what you type and offer suggestions, pulled from Wikipedia. The call to Wikipedia is successful (I see in Chrome's Network debugging window), but the app gives me an error:

Uncaught TypeError: Object #<Object> has no method 'subscribe'

I've tried several versions of jQuery (1.8.3, 1.10.2, 2.0.3), and that makes no difference. Bootstrap doesn't seem to be an issue, either. I see almost no mention of rx.jquery here (and there's no tag for it), so I don't know whether it's maybe not ready for prime-time or what. I have pulled the most recent rx.* libs, as older ones were giving me different errors.

Of course, I can't rule out that I've just bungled something. But it's not jumping out at me.

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Reactive Elements</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="apple-mobile-web-app-capable" content="yes" />
        <link href="/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
        <script src="/lib/jquery-1.8.3.min.js"></script>
    </head>
    <body>
        <div class="container">
            <div class="page-header">
                <h1>Reactive Extensions <small>in JavaScript</small></h1>
            </div>
            <input id="textInput" type="text" class="form-control"/>
            <ul id="results"></ul>
        </div>
        <script src="/lib/rx.min.js"></script>
        <script src="/lib/rx.binding.min.js"></script>
        <script src="/lib/rx.time.min.js"></script>
        <script src="/lib/rx.jquery.min.js"></script>
        <script>
            $(function () {
                var throttledInput = $('#textInput').
                    keyupAsObservable().
                    map(function (ev) {
                        return $(ev.target).val();
                    }).
                    filter(function (text) {
                        return text.length > 2;
                    }).
                    throttle(500).
                    distinctUntilChanged();

                function searchWikipedia(term) {
                    return $.ajaxAsObservable({
                        url: 'http://en.wikipedia.org/w/api.php',
                        data: { action: 'opensearch',
                            search: term,
                            format: 'json' },
                        dataType: 'jsonp'
                    });
                }

                var suggestions = throttledInput.flatMapLatest(function (text) {
                    console.debug('Searching wiki', text);
                    return searchWikipedia(text);
                });

                var selector = $('#results');
                suggestions.subscribe(
                    function (data) {
                        console.debug('Data!', data);
                        selector.empty();
                        $.each(data[1], function (_, text) {
                            $('<li>' + text + '</li>').appendTo(selector);
                        });
                    },
                    function (e) {
                        console.debug("ERROR!", e);
                        selector.empty();
                        $('<li>Error: ' + e + '</li>').appendTo('#results');
                    }
                );
            });
        </script>
    </body>
</html>
Roy J
  • 42,522
  • 10
  • 78
  • 102
  • 1
    Here's my 5-minute conversion to Bacon.js. Seems to work. http://jsfiddle.net/T6Xtv/ – raimohanska Oct 08 '13 at 06:14
  • Nice. Maybe I just need to learn Bacon instead of Rx. – Roy J Oct 08 '13 at 16:00
  • 1
    I tested this code with the latest versions of Rx and it works correctly (except for $.each, which is throwing an exception). The only thing I can think of this that one of the Rx libs is not being loaded correctly, or you that you may be using an older version that does not have one of the functions you are trying to use. – cwharris Nov 16 '13 at 06:43
  • 1
    Without the stack trace, it's difficult to be specific, but I typically see errors like "Uncaught TypeError: Object # has no method 'subscribe'" when RxJS expects to be an Observable and it is not. I've found that sometimes you need to wrap "x" in Rx.Observable.return(x), or something like that. I've also seen this when RxJS is expecting some kind of Observable Collection, but it instead has just a basic Observable. Good luck! – Greg Edwards Mar 06 '14 at 13:50

1 Answers1

3

You seem to have an error on this line:

$.each(data[1], function (_, text) { //...

It needs to be:

$.each(data.data[1], function (_, text) { //...

To match the incoming data. Here's the working example:

$(function run() {
    var throttledInput = $('#textInput').
        keyupAsObservable().
        map(function (ev) {
            return $(ev.target).val();
        }).
        filter(function (text) {
            return text.length > 2;
        }).
        throttle(500).
        distinctUntilChanged();

  
    function searchWikipedia(term) {
        return $.ajaxAsObservable({
            url: 'http://en.wikipedia.org/w/api.php',
            data: { action: 'opensearch',
                search: term,
                format: 'json' },
            dataType: 'jsonp'
        });
    }

    var suggestions = throttledInput.flatMapLatest(function (text) {
        console.debug('Searching wiki', text);
        return searchWikipedia(text);
    });

    var selector = $('#results');
    suggestions.subscribe(
        function (data) {
            console.debug('Data!', data);
            selector.empty();
            $.each(data.data[1], function (_, text) {
                $('<li>' + text + '</li>').appendTo(selector);
            });
        },
        function (e) {
            console.debug("ERROR!", e);
            selector.empty();
            $('<li>Error: ' + e + '</li>').appendTo('#results');
        }
    );
});
<!DOCTYPE html>
<html lang="en">
    <head>
<script src="//cdnjs.cloudflare.com/ajax/libs/rxjs/2.3.22/rx.all.js"></script>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
      <script src="//cdnjs.cloudflare.com/ajax/libs/rxjs-jquery/1.1.6/rx.jquery.js"></script>
        <title>Reactive Elements</title>

  </head>
    <body>
        <div class="container">
            <div class="page-header">
                <h1>Reactive Extensions <small>in JavaScript</small></h1>
            </div>
            <input id="textInput" type="text" class="form-control"/>
            <ul id="results"></ul>
        </div>
    </body>
</html>

NOTE: My example uses a more current jQuery version (2.1 vs 1.8), however I've done some testing and it does not seem to cause problems.

Jon Surrell
  • 9,444
  • 8
  • 48
  • 54