简体   繁体   中英

array reference javascript angular

i'm trying to reference one item in an array, and i have no idea why this is not working,

console.log($scope.Times);
console.log($scope.Times[0]);

these two lines of code are EXACTLY after eachother, but the output i get from the console is the following..

Output from the console

any ideas why this is not working? the commands are exactly after each other as I mentioned before and in the same function, the variable is global in my controller.

i can add more code if you think it can help, but i don't really understand how..

some more code:

$scope.Times = [];
$scope.getStatus = function(timer){
   $http.post('getStatus.php', {timer : timer})
        .success(function(response){
            $scope.response = response;

            if ($scope.response.Running === "0"){
                $scope.model = { ItemNumber : $scope.response.Part };
                $scope.loadTiming($scope.response.Part);
                console.log($scope.Times);
                console.log($scope.Times[0]);
            }
    });
};

 $scope.loadTiming = function(itemNumber) {
     $http.post('getPartTimings.php', {itemNumber : itemNumber})
        .success(function(response){
            $scope.selectedTiming = response;
            $scope.Times.splice(0); 
            var i = 0;
            angular.forEach($scope.selectedTiming, function(value) {
                if (value !== 0)
                    $scope.Times.push({
                                    "Process" : $scope.procedures[i],
                                    "Duration" : value*60
                                    });   
                i++;
            });
    });
};


<?php


$postData = file_get_contents("php://input");
$request = json_decode($postData);

require "conf/config.php";

 mysqli_report(MYSQLI_REPORT_STRICT);
    try {  
        $con=mysqli_connect(DBSERVER,DBUSER,DBPASS,DBNAME);
    } catch (Exception $exp) {
        echo "<label style='font-weight:bold; color:red'>MySQL Server Connection Failed.     </label>";
        exit;
    }

 $query = 'SELECT *,
            TIME_TO_SEC(TIMEDIFF(NOW(),Timestamp)) 
       FROM live_Timers 
       WHERE Timer='.$request->timer;

 $result = mysqli_query($con, $query);
 $data = mysqli_fetch_assoc($result);

 echo JSON_ENCODE($data);

thanks for your help.

OK, so more code does help. It looks like you have asynchronous logic happening here. loadTiming is fired, which does a POST and then a splice on the Times array. One console.log could be firing before this POST and the other after. There's no easy way to tell.

One possible fix would be to only log these once the loadTiming async process runs. Return a promise from the loadTiming function and then in the then callback of the promise, log your array.

$scope.getStatus = function(timer){
   $http.post('getStatus.php', {timer : timer})
        .success(function(response){
            $scope.response = response;

            if ($scope.response.Running === "0"){
                $scope.model = { ItemNumber : $scope.response.Part };
                $scope.loadTiming($scope.response.Part).then(function () {

                    console.log($scope.Times);
                    console.log($scope.Times[0]);
                });
            }
    });
};

 $scope.loadTiming = function(itemNumber) {
     return $http.post('getPartTimings.php', {itemNumber : itemNumber})
        .success(function(response){
            $scope.selectedTiming = response;
            $scope.Times.splice(0); 
            var i = 0;
            angular.forEach($scope.selectedTiming, function(value) {
                if (value !== 0)
                    $scope.Times.push({
                                    "Process" : $scope.procedures[i],
                                    "Duration" : value*60
                                    });   
                i++;
            });
    });
};

I think your issue is a $scope reference issue.

I would try this:

$scope.vm = {};
$scope.vm.Times = [];

Adding the "." is Angular best practice when attaching to $scope. This is best described here Understanding Scopes

I have experienced a similar situation a while ago , related with this issue .

Since then, I've encountered related issues a bunch of times (AngularJS, due to its cyclic nature seems prone to produce this behaviour).

In your case, using JSON.stringify($scope.Times) might "fix" this.


Context

Usually this happens in this context:

  • An async call or a expensive DOM manipulation is made.
  • You make 2 (or more) calls to console.log in between.
  • The state of the DOM or object is changed
  • The output shows inconsistent (and strange) results

How

Take this example:

console.log(someObject);
console.log(someObject.property);

After digging a lot (and talking to Webkit developers) this is what I've found:

The second call to console.log is "resolved" first .

Why?

In your case, this has to do how Console handles objects and "expressions" in a different way:

An "expression" is resolved in the time of call, while with objects, a reference to said object is stored instead

Note that expression is used loosely here. You can observe this behaviour in this fiddle


More in depth analysis

Regarding display discrepancies, the behaviour posted above is not the only gotcha with Console. In fact, it is related in how Console works.

Console is an external tool

First you must realize that Console is an external tool and not part of the ECMAScript spec. Implementations differ between browsers and it shouldn't be used in production. It certainly won't work the same for every user.

Console is a non-standard external tool and is not on a standards track.

Console is dynamic

Console as a very dynamic tool. With console you can make assertions (test), time and profile your code, group log entries, remote connect to your server and debug Server Side Code. You can even change code itself, at runtime. So..

Console is not just a static log displayer... Its dynamic nature is one its most features

Console has a slight delay

Being an external dynamic tool, Console works as a watcher process attached to the javascript engine. This is useful in debugging and among other things prevents Console to inadvertently block the execution of the script. A simple and crude way of thinking about this is picturing console.log as a kind of non-blocking async call. This means that:

With Console, there's a slight delay between 1)call, 2)processing and 3)output.

However, calling Console is not "instant" per se. In fact, by itself, can delay script execution. If you mix this with complex DOM manipulations and events, it can cause weird behaviours.

I've encountered an issue with Chrome, when using MutationObserver and console.log . This happened because the DOM Painting was delaying the update of the DOM object but the event triggered by that DOM change was fired nevertheless. This meant the event callback was executed and finished before the DOM Object was fully updated, resulting in an invalid reference to the DOM object.

Using console.log in the observer caused a brief delay in the callback execution, that, in most of the times, was enough to let the DOM Object update first. This proves that console.log delays code execution.

But even when an invalid reference error occurred, console.log ALWAYS showed a valid object. Since the object couldn't have been changed by code itself, this proves there is a delay delay between the call of console.log and the processing.

Console log order matches the code path

Console log entries order is unaffected by entries update status. In other words,

The order of the log entries reflect the order in which they are called, not their "freshness"

So, if an object is updated, it does not move to the end of the log. (makes sense to me)


Counterintuitive behaviour

This can lead to a number of possible counterintuitive behaviours because one might expect a console.log to be some kind of snapshot of the object, not a reference to it.

For instance, in your case, the object is changed between the the call to console.log and the end of the script.

  • At the time of calling, $scope.Times is empty, so $scope.Times[0] is undefined.
  • However, the $scope.Time object is updated posteriorly.
  • When the Console report is displayed, it shows an updated version of the object.

Fix

In your case, transforming the object in an "expression" can solve the "issue". For instance, you can use JSON.stringify($scope.Times) .


Debate

It is debatable if the way console handles objects is a Bug or a Feature. Some propose that, when called with an object, console.log should clone that object making a kind of snapshot. Some argue that storing a reference to the object is preferable, since you can easily create a snapshot yourself if you wish to do so.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM