【问题标题】:AngularJS controller only updating part of the dataAngularJS 控制器只更新部分数据
【发布时间】:2016-04-22 08:53:22
【问题描述】:

我有一个小瓶服务器,它返回给定 machineID 的随机值,如下所示:

@app.route('/dataMachine')
@enable_cors
def simulatedMachineData():

    prevVals = {'machineID_1': 0,'machineID_2': 0, 'machineID_3': 0,}
    devVals = {'machineID_1': 5.3,'machineID_2': 2.1,'machineID_3': 7.1,}    

    dictVals  = bottle.request.query.decode()
    machineID = dictVals.get('machine', '')
    if machineID not in devVals.keys(): return '-1'
    prevVals[machineID] += normal(scale=devVals[machineID])
    return str(prevVals[machineID])

这没有问题。

现在我有一个 AngularJS 应用程序可以与这些数据进行交互,如下所示:

var app = angular.module('testBidirection', []);

app.controller('tempCntrl', function ($scope, $http, $interval){

    /////////////////////////////////////////////////
    // Data to display and its update function
    $scope.data = {
        'machineID_1':'0',
        'machineID_2':'0',
        'machineID_3':'0',
    };

    var machineIDs = ['machineID_1', 'machineID_2', 'machineID_3'];
    $scope.machineID = 'machineID_1';

    $scope.getData = function(){
        for (var i = 0; i < 3; i++) {
                $scope.machineID = machineIDs[i];
                $http.get('http://localhost:8080/dataMachine?machine=' + $scope.machineID).success(function(data) {
                    $scope.data[ $scope.machineID ] = data;
                });
        };
    };


    //////////////////////////////////////////////////
    // Button controller. Use this controller to 
    //      toggle the initiation of getting and 
    //      stopping data retrieval ...
    $scope.buttonText = 'start Comm';
    $scope.toggleComm = function(){
        if ($scope.buttonText == 'start Comm') {
            $scope.buttonText = 'stop Comm';
            stop = $interval($scope.getData, 2*1000);
        } else {
            $scope.buttonText = 'start Comm';
            $interval.cancel(stop);
            stop=undefined;
        }
    };

});

我认为问题出在这个函数中:

$scope.getData = function(){
    for (var i = 0; i < 3; i++) {
            $scope.machineID = machineIDs[i];
            $http.get('http://localhost:8080/dataMachine?machine=' + $scope.machineID).success(function(data) {
                $scope.data[ $scope.machineID ] = data;
            });
    };
};

当我运行这个脚本时,我只看到 last 机器 ID 发生了变化。脚本运行时浏览器上的示例输出如下:

{"machineID_1":"0","machineID_2":"0","machineID_3":"2.37252542925"}

"machineID_3" 的值每隔 2 秒就会改变一次,而 "machineID_1" 和 "machineID_2" 的值保持为 0。

我可以从我的 Python 输出中看到,服务器每 2 秒收到一次正确的 get 请求,如下面的示例所示。

127.0.0.1 - - [22/Apr/2016 16:33:32] "GET /dataMachine?machine=machineID_3 HTTP/1.1" 200 14
127.0.0.1 - - [22/Apr/2016 16:33:34] "GET /dataMachine?machine=machineID_1 HTTP/1.1" 200 14
127.0.0.1 - - [22/Apr/2016 16:33:34] "GET /dataMachine?machine=machineID_2 HTTP/1.1" 200 14
127.0.0.1 - - [22/Apr/2016 16:33:34] "GET /dataMachine?machine=machineID_3 HTTP/1.1" 200 14
127.0.0.1 - - [22/Apr/2016 16:33:36] "GET /dataMachine?machine=machineID_1 HTTP/1.1" 200 13
127.0.0.1 - - [22/Apr/2016 16:33:36] "GET /dataMachine?machine=machineID_2 HTTP/1.1" 200 14
127.0.0.1 - - [22/Apr/2016 16:33:36] "GET /dataMachine?machine=machineID_3 HTTP/1.1" 200 13

我是否遗漏了范围规则中的某些内容?

资源:

Bottle Server 的全部内容:

import bottle
from bottle import response
from numpy.random import normal

import json
import pandas as pd 

app = bottle.Bottle()

# the decorator
def enable_cors(fn):
    def _enable_cors(*args, **kwargs):
        # set CORS headers
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
        response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'

        if bottle.request.method != 'OPTIONS':
            # actual request; reply with the actual response
            return fn(*args, **kwargs)

    return _enable_cors

@app.route('/dataMachine')
@enable_cors
def simulatedMachineData():

    prevVals = {'machineID_1': 0,'machineID_2': 0,'machineID_3': 0,}
    devVals = {'machineID_1': 5.3,'machineID_2': 2.1,'machineID_3': 7.1,}    

    dictVals  = bottle.request.query.decode()
    machineID = dictVals.get('machine', '')
    if machineID not in devVals.keys(): return '-1'
    prevVals[machineID] += normal(scale=devVals[machineID])
    return str(prevVals[machineID])

HTML 文件的全部内容:

<!DOCTYPE html>
<html>
<head lang="en">
    <title>Plotly Graph Plotter Directive for AngularJS - Demo</title>
    <script src="jquery.min.js"></script>
    <script src="angular.min.js"></script>
    <script src="app3.js"></script>
</head>
<body ng-app="testBidirection">

Testing the return Values ...
<div  ng-controller="tempCntrl">

    <button ng-click='toggleComm()'>{{buttonText}}</button>
    <hr>
    {{data}}
    <hr>
</div>

</body>
</html>

【问题讨论】:

  • 在 for 循环中.. 应该 machineIDs[i];是 $scope.machineIDs[i];?
  • 我尝试了在任何地方添加$scope 的所有变体,包括$scope.i,使用不同形式的for 循环(例如for (machineID in $scope.data))等。似乎没有任何效果:(跨度>
  • 尝试在 $http.get 成功方法中添加 $scope.apply()
  • 原谅我的无知。刚从 AngularJS 开始。 $scope.apply() 是什么?
  • 我看到你已经找到了解决这个问题的办法。尽管如此,请通过此链接了解 $scope.$apply() jimhoskins.com/2012/12/17/angularjs-and-apply.html

标签: python angularjs


【解决方案1】:

我可以在以下几行代码中看到几个问题。

$scope.machineID = 'machineID_1';

为什么将它分配给 $scope 变量?正如我所看到的,您只使用它将机器 ID 发送到循环内的服务器。如果您不在视图中使用此变量,则应按如下方式进行更正。

var machineID = 'machineID_1';

$scope.getData = function(){ for (var i = 0; i < 3; i++) { $scope.machineID = machineIDs[i]; $http.get('http://localhost:8080/dataMachine?machine=' + $scope.machineID).success(function(data) { $scope.data[ $scope.machineID ] = data; }); }; };

向服务器发送 Http 调用是异步的。所以如果你像上面那样做,你的代码可能会发送 3 个 http 请求到 machineId=3 的服务器。因为,异步方式,您的循环将在所有 http 调用发送之前完成执行。应作如下修正。此外,您分配的服务器调用响应如下。

$scope.data[$scope.machineID] = 数据;

由于 http 调用的异步行为,现在 $scope.machineID 可能等于 3。因此,即使您从所有 3 个机器 IDS 获取数据,实际上您也为 machineId 3 分配了值。

$scope.getData = function(){
    for (var i = 0; i < 3; i++) {

            $http.get('http://localhost:8080/dataMachine?machine=' + machineIDs[i]).success(function(data) {
                $scope.data[machineIDs[i]] = data;
            });
    };
};

更新

    $scope.getData = function(){
       for (var i = 0; i < 3; i++) {
        var machineId=machineIDs[i];
        $http.get('http://localhost:8080/dataMachine?machine=' + machineId).success((function(machineId) {
                 return function(data) {
                 $scope.data[machineId] = data;
               }
        })(machineId));
      }
    }

【讨论】:

  • 我也试过了。不工作。我使用$scope.machineID 的原因是因为我认为machineID 无法从$http.get 请求中访问...
  • 如果您从服务器日志中看到,这三个调用总是发生。但是,如果我尝试您的建议(我已经尝试过),我在范围内的 machineIDs[i] 变得未定义。这是我在浏览器上看到的...{"machineID_1":"0","machineID_2":"0","machineID_3":"0","undefined":"0.0299554435569"}
  • 您的服务器是返回 machineId 还是只返回值?
  • 只有一个值。这是一个人为的例子。基本上每台机器最终只会返回生产中的当前测量值。
  • 我认为最简单的解决方案是从服务器发送带有值的 machineId。像下面的东西。 {"machineId":"1","value":"2"}。因为你的服务器知道机器 ID。
【解决方案2】:

基于 Madura Pradeep 发布的答案,要查看问题的根源,请考虑以下几点:

$http 调用是异步的,只有在收到来自服务器的响应时才调用成功函数。 HTTP 请求也比简单的 for 循环执行慢得多。因此,当收到第一个响应并且调用循环的成功函数已经终止并且循环变量i == undefined 和$scope.machineID == 'machineID_3' 时。结果,所有三个返回值都被分配给$scope.data[ 'machineID_3' ]

【讨论】:

  • 谢谢尼科!我明白这个问题,更重要的是,现在的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-31
  • 2014-09-14
  • 1970-01-01
  • 2014-11-27
  • 2015-11-30
  • 1970-01-01
相关资源
最近更新 更多