当信号器集线器推送新消息时,Angular不能更新集合

时间:2015-12-28 12:28:36

标签: angularjs signalr

这是一个网站,用户可以通过浏览器控制设备。浏览器和中间线之间的通信是通过信号器。这里的问题是:当来自信号器集线器的新消息到达时,我将数据重新绑定到集合,但页面没有刷新。

这是指令:

//主框架
app.directive('mainPart',['$compile',function ($compile) {
return {
    restrict: 'AE',
    replace: true,
    scope: { options: "=" },
    link: function(scope, element, attrs) {
        scope.$watchCollection('options', function (newValue, oldValue) {
                console.log("I see a data change!");
        });
    },
    template: '<div class="panel panel-info" style="margin:10px 10px 10px 10px">'
            + '  <div class="panel-heading">'
            + '    <h3 class="panel-title glyphicon glyphicon-user"><strong>{{options.title}}</strong></h3>'
            + '  </div>'
            + '  <div class="panel-body">'
            + '    <controller-part options="options.controller"></controller-part>'
            + '    <led-part options="options.led"></led-part>'
            + '  </div>'
            + '</div>'
};
}]);

//可控制的控制器部分
app.directive('controllerPart', function () {
return {
    restrict: 'AE',
    replace: true,
    scope: { options: "=options" },
    template: '<div class="panel panel-default">'
            + '  <div class="panel-heading">'
            + '    <h3 class="panel-title">控制器部分</h3>'
            + '  </div>'
            + '  <div class="panel-body">'
            + '    <controller-instance options="options"></controller-instance>'
            + '  </div>'
            + '</div>'
};
});

//不可控制的指示灯部分
app.directive('ledPart', function () {
return {
    restrict: 'AE',
    replace: true,
    scope: { options: "=options" },
    template: '<div class="panel panel-default">'
            + '  <div class="panel-heading">'
            + '    <h3 class="panel-title">指示灯部分</h3>'
            + '  </div>'
            + '  <div class="panel-body">'
            + '    <led-instance options="options"></led-instance>'
            + '  </div>'
            + '</div>'
};
});

//控制器具体的路数
app.directive('controllerInstance', function () {
return {
    restrict: 'AE',
    replace: true,
    scope: { options: "=options" },
    template: '<div class="panel panel-success" style="float:left;margin-left:20px;" ng-repeat="controller in options">'
             + '   <div class="panel-heading">'
             + '       <h3 class="panel-title">{{controller.title}}(在线)</h3>'
             + '   </div>'
             + '   <div class="panel-body">'
             + '       <div class="btn-group" role="group">'
             + '           <button type="button"  ng-repeat="function in controller.functionlist" tag="{{function.functionorder}}" class="btn {{function.state|onlineConverter}} glyphicon {{function.functionicon}}">{{function.functionname}}</button>'
             //+ '           <button type="button" class="btn btn-default glyphicon glyphicon-off">停止</button>'
             //+ '           <button type="button" class="btn btn-default glyphicon glyphicon-chevron-up btn-success">正转</button>'
             //+ '           <button type="button" class="btn btn-default glyphicon glyphicon-chevron-down">反转</button>'
             + '       </div>'
             + '   </div>'
             + '</div>'
};
});

//指示器具体的路数
app.directive('ledInstance', function () {
return {
    restrict: 'AE',
    replace: true,
    scope: { options: "=options" },
    template: '<div class="panel panel-success" style="float:left;margin-left:20px;" ng-repeat="led in options">'
            + '  <div class="panel-heading">'
            + '     <h3 class="panel-title">{{led.title}}(在线)</h3>'
            + '  </div>'
            + '  <div class="panel-body">'
            + '     <div class="btn-group" role="group">'
            + '         <button type="button"  ng-repeat="function in led.functionlist" tag="{{function.functionorder}}" class="btn {{function.state|onlineConverter}} glyphicon {{function.functionicon}}">{{function.functionname}}</button>'
            //+ '         <button type="button" class="btn btn-success glyphicon glyphicon-eye-close">灭</button>'
            //+ '         <button type="button" class="btn btn-default glyphicon glyphicon-eye-open">亮</button>'
            + '     </div>'
            + ' </div>'
            + '</div>'
};
});

//此过滤器主要是为了过滤工作状态的,将true和false转变为具体的css样式。
app.filter('onlineConverter', function () {
return function (input) {
    if (input) {
        return "btn-success";
    }
    else {
        return "btn-default";
    }
}
});

以下是服务部分:

app.service('dataService', function () {
var getData = function () {
    /*
    数据结构中的state代表当前路是否是工作状态
    */
    var controllerData =
        {
            title: '中国联通对接设备',
            controller: [{
                title: '风机',
                functionlist: [{ functionname: '停止', functionicon: 'glyphicon-off', functionorder: '0', state: true }, { functionname: '正转', functionicon: 'glyphicon-chevron-up', functionorder: '1', state: false }, { functionname: '反转', functionicon: 'glyphicon-chevron-down', functionorder: '2', state: false }]
            }, {
                title: '湿帘',
                functionlist: [{ functionname: '停止', functionicon: 'glyphicon-off', functionorder: '0', state: false }, { functionname: '正转', functionicon: 'glyphicon-chevron-up', functionorder: '1', state: false }, { functionname: '反转', functionicon: 'glyphicon-chevron-down', functionorder: '2', state: true }]
            }, {
                title: '暖灯',
                functionlist: [{ functionname: '停止', functionicon: 'glyphicon-off', functionorder: '0', state: false }, { functionname: '高光', functionicon: 'glyphicon-chevron-up', functionorder: '1', state: true }, { functionname: '低光', functionicon: 'glyphicon-chevron-down', functionorder: '2', state: false }]
            }],
            led: [{
                title: '电源',
                functionlist: [{ functionname: '灭', functionicon: 'glyphicon-eye-close', functionorder: '0', state: false }, { functionname: '亮', functionicon: 'glyphicon-eye-open', functionorder: '1', state: true }]
            }, {
                title: '转轴',
                functionlist: [{ functionname: '正转', functionicon: 'glyphicon-eye-close', functionorder: '0', state: true }, { functionname: '反转', functionicon: 'glyphicon-eye-open', functionorder: '1', state: false }]
            }, {
                title: '浇灌',
                functionlist: [{ functionname: '关闭', functionicon: 'glyphicon-eye-close', functionorder: '0', state: true }, { functionname: '打开', functionicon: 'glyphicon-eye-open', functionorder: '1', state: false }]
            }, {
                title: '电压',
                functionlist: [{ functionname: '正常', functionicon: 'glyphicon-eye-close', functionorder: '0', state: true }, { functionname: '异常', functionicon: 'glyphicon-eye-open', functionorder: '1', state: false }]
            }]
        };

    return controllerData;
}

return {
    controllerData: getData,
};
});

app.service('hubService', ['dataService', function (dataService) {

//添加对自动生成的Hub的引用
var chat = $.connection.chatHub;

//启动链接
$.connection.hub.start().done(function () { });

var getData = function () {
    return dataService.controllerData();
}

return {
    commandReceived: function(callback)
    {
        if(callback)
        {
            //调用Hub的callback回调方法
            chat.client.printCommand = function (command) {
                var data = getData();
                var obj = { data: data, command: command };
                return callback(obj);
            }
        }
    },
    controllerData:getData
};

}]);

这是控制器部分:

var mainController = app.controller('dsController', ['$scope', 'hubService', function ($scope, hubService) {

var currentData = hubService.controllerData();

$scope.controllerData = currentData;

hubService.commandReceived(function (result) {
    debugger;

    var command = result.command;
    var data = result.data;

    if (command != undefined) {
        if (command.localeCompare("aaaa")==0)
            data.controller[1].title = "哈哈哈";
        else if (command.localeCompare("bbbb") == 0)
            data.controller[0].title = "呵呵呵";
    }

    $scope.controllerData = data;
});

}]);

以下是截图: enter image description here

当有新消息到达时,我可以看到hubService.commandReceived被触发,然后我将数据重新绑定到集合。 这是屏幕截图: enter image description here

但问题是,重新绑定数据后,页面根本没有改变!

我已经检查了很多关于stackoverflow的文章,似乎很多问题都是通过在指令中添加链接函数来解决的,所以我做到了。但它对我没有用。

也许我认为问题应该放在我使用的指令中?还是我用来处理signalr回调消息的服务方法?

任何可以帮助我的人?

编辑次数:2015-12-28 22:06:01

对于沃尔特的回应,我会尝试一下,同时,希望你们这些人能够做到这一点。可以提供更多建议。我会在网上等再次。

1 个答案:

答案 0 :(得分:3)

您需要致电

 $scope.$apply(function {
     $scope.controllerData = data;
 })

通知angular您的数据已经更改,因为来自signalR的通知超出了angularjs范围生命周期。

  

$ apply()用于从角度框架外部以角度执行表达式。 (例如,来自浏览器DOM事件,setTimeout,XHR或第三方库)。因为我们正在调用角度框架,所以我们需要执行异常处理的适当范围生命周期,执行监视。

您可以阅读here

在某些情况下,您还需要检查$digest是否正在进行中,以免收到错误。