-1

I have a website that is functioning fine, but when I try to add a signalr hub to it I get the error

Uncaught TypeError: this.hasSubscriptions is not a function
at Function.<anonymous> (jquery.signalR-2.2.0.js:2878)
at Function.each (jquery-2.1.4.js:382)
at hubConnection.fn.init.<anonymous> (jquery.signalR-2.2.0.js:2877)
at hubConnection.fn.init.<anonymous> (jquery.signalR-2.2.0.js:759)
at hubConnection.fn.init.dispatch (jquery-2.1.4.js:4435)
at hubConnection.fn.init.elemData.handle (jquery-2.1.4.js:4121)
at Object.trigger (jquery-2.1.4.js:4350)
at jQuery.fn.init.triggerHandler (jquery-2.1.4.js:4907)
at hubConnection.fn.init.start (jquery.signalR-2.2.0.js:652)
at connection._.deferredStartHandler (jquery.signalR-2.2.0.js:463)

interrogating line 2878 in the signalr library leads me to find that this is a prototype I have defined in another script

Object.prototype.myfunction = function(){
    ...
}

Firstly, I cannot see why this prototype function is being interrogated for signalr subscriptions.

And secondly, how do I get past this problem without removing the prototype and rewriting swathes of code in the site?

Note:

I tried adding a prototype for hasSubscriptions, but this lead to other errors around the handling of my existing prototypes

Also, all the code around the signalr works fine if the prototypes are removed (but this breaks the rest of the site)

Actual code:

<div ng-show="noPartialView()" class="well well-lg">
    <div class="row" data-bind="foreach:counters">

        <div class="col-md-12 canvas-container">
            <h2 data-bind="text:name" class="graph-header"></h2>
            <div data-bind="foreach:lines">
                <div class="indicatorLine inline" data-bind="style:{borderColor:color}"><img /></div>
                <span data-bind="text:name"></span>
            </div>
            <canvas width="1700" height="200" data-bind="attr:{'id': name}" class="responsive-canvas"></canvas>
        </div>

    </div>
</div>

@Scripts.Render("~/bundles/jquery")
<script src="~/SignalR/hubs"></script>
@Scripts.Render("~/bundles/angular")
@Scripts.Render("~/bundles/realtimedata")
@Scripts.Render("~/bundles/AngularMVCApp")

where bundles are:

bundles.Add(new ScriptBundle("~/bundles/jquery")
            .Include("~/Scripts/jquery-2.1.4.js")
            .Include("~/Scripts/jquery.signalR-2.2.0.js")
            .Include("~/Scripts/jquery.color-2.1.2.js"));

        bundles.Add(new ScriptBundle("~/bundles/angular")
            .Include("~/Scripts/angular.js")
            .Include("~/Scripts/angular-sanitize.js")
            .Include("~/Scripts/angular-bootstrap-confirm.js")
            .Include("~/Scripts/angular-animate.js")
            .Include("~/Scripts/angular-ui/ui-bootstrap-tpls.js")
            .Include("~/Scripts/angular-route.js")
            .Include("~/Scripts/datetime-picker.js")
            .Include("~/Scripts/angular-locale_en-gb.js")
            .Include("~/Scripts/moment-with-locales.js"));

        bundles.Add(new ScriptBundle("~/bundles/bootstrap")
            .Include("~/Scripts/bootstrap.js"));

        bundles.Add(new ScriptBundle("~/bundles/realtimedata")
                .Include("~/Scripts/knockout-2.3.0.js")
                .Include("~/Scripts/smoothie.js")
                .Include("~/Scripts/realtimedata.js"));

       bundles.Add(new ScriptBundle("~/bundles/AngularMVCApp")
                .Include("~/Scripts/Helpers.js")
                .Include("~/Scripts/InFill.js")
                .Include("~/Scripts/ArrayComparer.js")
                .IncludeDirectory("~/Scripts/Providers", "*.js")
                .IncludeDirectory("~/Scripts/Directives", "*.js")
                .IncludeDirectory("~/Scripts/Services", "*.js")
                .IncludeDirectory("~/Scripts/Controllers", "*.js")
                .Include("~/Scripts/AngularMVCApp.js"));

and the realtimedata library is

(function () {

var countersHub = $.connection.countersHub;
$.connection.hub.logging = true;
$.connection.hub.start();

countersHub.client.newCounters = function (counters) {
    model.addCounters(counters);
};

....
}());

but the problems are caused by any prototype functions added to Object (which are defined in Helpers.js) e.g.

Object.prototype.getFieldValue = function () {
if (arguments == null || arguments.length != 1) {
    return null;
}

var fieldName = arguments[0];

if (this == null || fieldName == null || typeof fieldName != 'string') {        
    return null;
}

var temp = this;
var fieldNameSplit = fieldName.split('.');

for (i = 0; i < fieldNameSplit.length; i++) {
    if (temp == null) {
        return temp;
    }
    if (fieldNameSplit[i].indexOf('[') > -1) {
        var fieldNameWithoutIndex = fieldNameSplit[i].split('[')[0];
        var index = fieldNameSplit[i].split('[')[1].split(']')[0];
        temp = temp[fieldNameWithoutIndex][index];
    }
    else {
        temp = temp[fieldNameSplit[i]];
    }
}
return temp;
};

Edit: Extra information found

the problem looks to be caused by the object prototype functions being exposed in the iteration

for (i in obj)

yet the native javascript prototype functions (such as toString and hasOwnObject) are not.

Why are my prototype functions being exposed by the iteration yet the native ones are not and is there a way to 'mask' my functions so they do not appear as the iterand?

MikeW
  • 1,568
  • 2
  • 19
  • 39
  • It's probably [this issue](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback), but without any code, it's impossible to know for sure. – T.J. Crowder Feb 08 '17 at 08:32

1 Answers1

1

The problem was due to the functions I added to the prototype being enumerable and the underlying signalr code (and jquery) is not under my control. As a result when looking for the hubs on the connection (Function.each (jquery-2.1.4.js:382)) it also found the functions I had added to the prototype.

To solve this I simply needed to declare the prototype functions as not enumerable and it all started working:

Object.defineProperty(Object.prototype, "getFieldValue",{
    enumerable:false,
    value: function () {
        ...
    }
});

thanks to JS non-enumerable function and How to define method in javascript on Array.prototype and Object.prototype so that it doesn't appear in for in loop for the answer

Community
  • 1
  • 1
MikeW
  • 1,568
  • 2
  • 19
  • 39