event publishing fails, console error

I have a master page which publishes an event when a popup is closed.

After upgrading from Brooklyn to Spark, the event publishing seems to be failing, and I’m getting this error in the console:




Hi Matt, we were wondering what you’d get if you clicked the “nav.js” reference, does the information contain anything useful? If not, are you able to reproduce this issue on a simple test page? Would be great if you could share that XML with us here, so that we can test the page in one of our orgs. Please find more information about creating test pages here: http://community.skuid.com/skuid/topics/how-to-create-a-good-test-page


Here’s the code for the nav.js. It’s a custom component that is dynamically building a nav component based on data in a settings for specific staff records.

Since the code requires access to specific custom objects, I don’t think I can create a generic test page…

Let me know if you notice anything in the script that might be causing an issue?

    var $ = skuid.$,
        $u = skuid.utils,
        $xml = $u.makeXMLDoc,
        $uid = $u.generateUniqueId,
        $e = skuid.events.subscribe,
        mm = skuid.model.Model;
    //Helper function to generate random string if script label or signature type isn't available
    var randomString = function(length) {
        var result = '',
            chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        for (var i = length; i > 0; i--) result += chars[Math.floor(Math.random() * chars.length)];
        return result;
        removeSpaces = function(text){
        return text.split(' ').join('');
    //Staff and User Info
        getCurrentSession = function(){
        var model = skuid.$M('CurrentStaffSession'),
            row = model && model.getFirstRow();
        return row;    
        getCurrentStaff = function(session){
        return session && session.Staff__c;
        getCurrentProfile = function(session){
        return session && session.Staff__c && session.Staff__r.Profile__c;
        getCurrentStaffName = function(session){
        return session && session.Staff__c && session.Staff__r.Name;
        getUserProfile = function(){
            var model = skuid.$M('CurrentUser'),
                row = model && model.getFirstRow();
        return row && row.Optimize_Profile_Type__c;
    skuid.componentType.register('ccoptimize__nav',function (element,xmlDef,component){
        // Get properties and variables
        var navCode = xmlDef.attr('code'),
            navName = xmlDef.attr('nav'),
            navRBP = xmlDef.attr('responsivebreakpoint'),
            navAlt = xmlDef.attr('alternateformat'),
            navLabel = 'Navigation_' + removeSpaces(navName),
            navModelId = (navLabel) ? navLabel.replace(/[^A-Z0-9_]+/ig, "") : 'Navigation_' + randomString(4),
            staffId, staffProfile, navMenuModel, navCustomModel;
        var getStaff = function(){
            var staffSession = getCurrentSession();
            staffId = getCurrentStaff(staffSession);
            staffProfile = getCurrentProfile(staffSession);
            return staffId;
        var getNavVisibility = function(){
            var dfd = new $.Deferred(),
                model = new mm();
            model.objectName = 'Navigation_Menu_Set__c';
            model.id = removeSpaces(navCode)+'Model';
            model.recordsLimit = 1;
            model.fields = [
                { id: 'Optimize_Code__c'},
                { id: 'Id'},
                { id: 'Profile_Visibility__c'},
                { id: 'Name'}
            model.conditions = [
                    type: 'fieldvalue',
                    field: 'Optimize_Code__c',
                    operator: '=',
                    value: navCode,
                    encloseValueInQuotes: true
                var row = model.getFirstRow();
                if (row){
                } else {
                console.error('Dynamic model query failed: ' + result.error);
            return dfd.promise();
        // Function to include legacy menu if no custom navigation available
        var includeLegacyMenuPage = function(){
            var xmlPageInclude = $xml('');
            var includeContainer = $('
'); skuid.component.factory({ xmlDefinition: xmlPageInclude, element: includeContainer }); // Add components to the DOM element element.append(includeContainer); }; // Generate Nav Menu Model var buildNavMenuModels = function(){ var dfd = new $.Deferred(); //Customizations Model navCustomModel = new mm(); navCustomModel.objectName = 'Navigation_Customization__c'; navCustomModel.id = 'NavCustomizations'; navCustomModel.fields = [ { id: 'Id'}, { id: 'Name'}, { id: 'Navigation_Menu__c'}, { id: 'Navigation_Menu__r.Item__c'}, { id: 'Navigation_Menu__r.Item__r.Icon__c'}, { id: 'Navigation_Menu__r.Item__r.Name'}, { id: 'Navigation_Menu__r.Item__r.Open_URL_In__c'}, { id: 'Navigation_Menu__r.Item__r.URL__c'}, { id: 'Navigation_Menu__r.Name'}, { id: 'Navigation_Menu__r.Navigation_Menu_Set__c'}, { id: 'Navigation_Menu__r.Navigation_Menu_Set__r.Name'}, { id: 'Navigation_Menu__r.Navigation_Menu_Set__r.Optimize_Code__c'}, { id: 'Navigation_Menu__r.Order__c'}, { id: 'Navigation_Menu__r.Parent_Menu__c'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Item__c'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Item__r.Name'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Name'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Order__c'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Parent_Menu__c'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Parent_Menu__r.Item__c'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Parent_Menu__r.Item__r.Name'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Parent_Menu__r.Name'}, { id: 'Navigation_Menu__r.Parent_Menu__r.Parent_Menu__r.Order__c'}, { id: 'Staff__c'}, { id: 'Staff__r.Name'}, { id: 'Visible__c'} ]; navCustomModel.conditions = [ { type: 'fieldvalue', field: 'Navigation_Menu__r.Navigation_Menu_Set__r.Optimize_Code__c', operator: '=', value: navCode, encloseValueInQuotes: true }, { type: 'fieldvalue', field: 'Staff__c', operator: '=', value: staffId, encloseValueInQuotes: true } ]; navCustomModel.initialize().register(); //Defaults Model navMenuModel = new mm(); navMenuModel.objectName = 'Navigation_Menu__c'; navMenuModel.id = navModelId; navMenuModel.dataSourceTypeName = 'salesforce'; navMenuModel.orderByClause = "Parent_Menu__c NULLS FIRST, Order__c"; navMenuModel.fields = [ { id: 'Default_Profile_Visibility__c'}, { id: 'Id'}, { id: 'Item__c'}, { id: 'Item__r.Icon__c'}, { id: 'Item__r.Name'}, { id: 'Item__r.Open_URL_In__c'}, { id: 'Item__r.URL__c'}, { id: 'Name'}, { id: 'Navigation_Menu_Set__c'}, { id: 'Navigation_Menu_Set__r.Name'}, { id: 'Navigation_Menu_Set__r.Optimize_Code__c'}, { id: 'Order__c'}, { id: 'Parent_Menu__c'}, { id: 'Parent_Menu__r.Item__c'}, { id: 'Parent_Menu__r.Item__r.Name'}, { id: 'Parent_Menu__r.Name'}, { id: 'Parent_Menu__r.Order__c'}, { id: 'Parent_Menu__r.Parent_Menu__c'}, { id: 'Parent_Menu__r.Parent_Menu__r.Name'}, { id: 'Parent_Menu__r.Parent_Menu__r.Order__c'}, { id: 'Parent_Menu__r.Parent_Menu__r.Item__c'}, { id: 'Parent_Menu__r.Parent_Menu__r.Item__r.Name'} ]; navMenuModel.conditions = [ { type: 'fieldvalue', field: 'Navigation_Menu_Set__r.Optimize_Code__c', operator: '=', value: navCode, encloseValueInQuotes: true }, { type: 'fieldvalue', field: 'Default_Profile_Visibility__c', operator: 'includes', value: staffProfile, encloseValueInQuotes: true } ]; navMenuModel.initialize().register(); $.when(mm.load([navCustomModel,navMenuModel])).done(function(){ dfd.resolve(); }).fail(function(result){ console.error('Dynamic Nav Customizations model query failed: ' + result.error); dfd.reject(result.error); }); return dfd.promise(); }; var mergeMenus = function(){ var menuRows = navMenuModel.getRows(), rowsToAdopt = []; $.each(navCustomModel.getRows(),function(n,customRow){ var found = false, i = 0; while (!found && i

After inspection, it appears that the events are firing, but when the custom component attempts to unsubscribe, the error is being thrown.

It looks like this inline script on the page is actually the one that is failing:

var $ = skuid.$;
        var model = skuid.$M('CurrentStaffSession'),
            row = model && model.getFirstRow(),
            staff = row && row.Staff__c;
        if (!model.isRowNew(row) && staff) {
        } else {
                //Load page include
The bold section is somehow failing. Not sure if the subscription is not working, but the script inside the function never runs when the staffSelected event is fired.

I’m wondering if the problem is that the script on the page is subscribed, and then I have two versions of the same nav.js custom component script is also subscribed, and then somehow they’re conflicting with each other?

Only the first custom nav component is working properly.

Were there any changes to how event subscriptions are managed between Brooklyn and Spark?

Matt, yes there were changes to how Event Subscriptions work between Brooklyn and Spark, some pretty significant changes, but the API should have remained the same.

What I’m seeing here is that you’re trying to call unsubscribe() with an event name — and I think that’s what’s causing the console error. As the documentation shows: https://docs.skuid.com/latest/en/skuid/api/skuid_events.html#skuid.events.unsubscribe , this method expects to be provided an Event Subscription, which is the output of calling skuid.events.subscribe(). Calling this method with an event name is not supported, and never has been — and in Spark the internal changes we make are now more explicitly verifying that what is provided is in fact an Event Subscription and we are attempting to call methods on that object, but what you are providing as the argument is not correct.

If you want to use unsubscribe(), you will need to keep a reference to any/all Event Subscriptions, and then unsubscribe them by calling skuid.events.unsubscribe(eventSubscription), or via the shortcut, eventSubscription.unsubscribe()

This line in particular is the problem: skuid.events.unsubscribe(‘staffSelected’);

Change the code block to this:

<b>var eventSubscription =</b> $e('staffSelected',function(){&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; staffId = getStaff();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (staffId) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; checkProfileAndGenerate();<br><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; skuid.events.unsubscribe(eventSubscription);</b><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>



Tada! Working again. Here’s to reading the docs! :wink:

Thanks so much, Zach.