2

I'm using Microsoft RxJS JavaScript library in two lightning components. One is autocomplete component and another coordination of reading multiple files. I really like this library and it is useful for building complex logic that depends on multiple events. Also it is so popular that there is propasal to do similar thing in ECMA script standard proposal-observable. Currently I need to deactivate LockerService to make it work. I don't see why it does something dangerous because its semantics is simple and it doesn't access or changes DOM tree.

Sample code:

    initSuggestions : function(component) {
    var subject = new Rx.Subject();
    component.set("v.searchSubject", subject);

    var contextSubscribe = $A.getCallback(function(observer, search) {
        if (component.isValid()) {
            if (search.length > 0) {
                var action = component.get("c.getSuggestions");
                action.setParams({filter: search});
                action.setCallback(this, function(response) {
                    var state = response.getState();
                    if (component.isValid() && state === 'SUCCESS') {
                        observer.onNext(response.getReturnValue());
                        observer.onCompleted();
                    }
                    else {
                        observer.onCompleted();
                    }
                });

                $A.enqueueAction(action, true);
            }
            else {
                observer.onNext([]);
                observer.onCompleted();
            }
        }
    });

    var getSuggestions$ = function(search) {
        return Rx.Observable.create(function(observer) {
            contextSubscribe(observer, search);
        });
    };

    var suggestions$ = subject
        .debounce(250)
        .distinctUntilChanged()
        .flatMapLatest(getSuggestions$)
        .distinctUntilChanged()
        .share();

    var isOpen$ = suggestions$
        .map(function(element) {
            return (element.length > 0);
        })
        .distinctUntilChanged();

    var subscription1 = suggestions$.subscribe(function(suggestions) {
        if (component.isValid()) {
            component.set("v.suggestions", suggestions);
        }
    });

    var subscription2 = isOpen$.subscribe(function(isOpen) {
        if (component.isValid()) {          
            var lookup = component.find("element-control");
            if (isOpen) {
                $A.util.addClass(lookup, "slds-is-open");
            }
            else {
                $A.util.removeClass(lookup, "slds-is-open");
            }
        }
    });

    component.set("v.suggestionsSubscription", new Rx.CompositeDisposable(subscription1, subscription2));
}

Another sample:

        //
    // Read files
    //
    var readFile$ = function(attachment) {
        return Rx.Observable.create(function(observer) {
            var reader = new FileReader();
            reader.onload = $A.getCallback(function(e) {
                observer.onNext({
                    attachment: attachment, 
                    result: e.target.result 
                });
                observer.onCompleted();
            });
            reader.onerror = $A.getCallback(function(e) {
                observer.onError();
            });
            reader.readAsDataURL(attachment);
        });
    }
    var readFile$s = attachments.map(readFile$);
    var readFiles$ = Rx.Observable.merge(readFile$s);
    var subscription = readFiles$.subscribe(
        //
        // When file is read
        //
        function(event) {
            var base64Mark = "base64,";
            var base64Start = event.result.indexOf(base64Mark) + base64Mark.length;
            event.attachment.body = event.result.substring(base64Start);
        },
        //
        // On error
        //
        function() {
            if (component.isValid()) {
                component.set("v.isSending", false);
                helper.showToast("Sending has failed", "There was a problem with reading attachments");
            }
        },
        //
        // On completed
        //
        function() {
            //
            // Send email
            //
            var addressEmail = function(address) {
                return address.email;
            };

            var action = component.get("c.sendEmail");
            action.setParams({
                orgWideEmailAddressId: orgWideEmailAddressId,
                toAddresses: toAddresses.map(addressEmail),
                ccAddresses: ccAddresses.map(addressEmail),
                bccAddresses: bccAddresses.map(addressEmail),
                subject: subject,
                objectId: objectId,
                templateId: templateId,
                fileNames: attachments.map(function(attachment) { return attachment.name; }),
                contentTypes: attachments.map(function(attachment) { return attachment.type; }),
                bodies: attachments.map(function(attachment) { return attachment.body; }),
            });
            action.setCallback(this, function(resp) {
                if (component.isValid()) {
                    component.set("v.isSending", false);
                    if (resp.getState() === 'SUCCESS') {
                        helper.navigateToRecord(component);
                    }
                    else {
                        component.set("v.isSending", false);

                        helper.showToast(
                            "Sending has failed",
                            "There was a problem with sending an email"
                        );
                    }
                }
            });
            $A.enqueueAction(action);
        }
    );
    component.set("v.filesSubscription", subscription);

Also it is used in some big companies so it would be very helpful if it would work with LockerService.We use ReactiveX Thank you!

2

On the surface I don't see any glaring reason why it shouldn't be supported when LockerService is activated. The first blocking issue the library runs in to is that MessageChannel is not properly wrapped by LockerService. I've filed a bug internally (W-3549049 if you ever need to reference it to support) to fix MessageChannel and investigate any other breakages encountered while using the library with your example code.

Edit (01/12/2017): The fix to properly expose MessageChannel in LockerService is scheduled be released to Sandbox next week and be included in the Spring '17 release.

6
  • I've noticed that RxJS library is not loaded on Chrome and Firefox. On Internet Explorer it works. Rx is not defined when I use it on console :( Dec 27 '16 at 16:17
  • @MarkoDvečko we're still investigating support for this library. I'll update this thread after anything substantial happens. Dec 27 '16 at 23:12
  • @MarkoDvečko I'm working on this now. I can get the app to load the lib fine and simple examples work. Do you have a more complete example of what you're doing I can try? It's hard to truly test your use cases without the markup and server-side code. Jan 5 '17 at 0:42
  • Thanks for this. I think that if it is loaded everything will work correctly. I'll add markup and server code so that you have complete example that you can test tomorrow. Jan 17 '17 at 15:34
  • I still have problem with LockerService and RxJS. Library is loaded correctly so that is ok. When I'll find cause or more evidence I will let you know. Apr 26 '17 at 12:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.