Vignesh PT
Vignesh PT

Reputation: 644

angular $watch over a particular field for all objects of an array

I have an array of halls like this, which I am getting from a $http.get().

$scope.halls = [
{
    "_id": "524886d4c6d8a5a3b8949f6f",
    "alias": "",
    "hallId": "2",
    "locationHint": "Near support team",
    "name": "Conference Hall",
    "bookQueue": [],
    "occupancy": {
        "occupied": true,
        "occupiedBy": "Vignesh",
        "purpose": "Sync up",
        "team": "Edge",
        "timeRange": {
            "from": "2013-10-02T19:08:44.752Z",
            "to": "2013-10-02T19:08:44.752Z"
        }
    },
    "capabilities": [
        "ceiling mic",
        "room speaker",
        "projector",
        "Mac machine"
    ]
},
{
    "_id": "524886fbc6d8a5a3b8949f70",
    "alias": "",
    "hallId": "3",
    "locationHint": "Near Edge Team",
    "name": "Training room",
    "bookQueue": [],
    "occupancy": {
        "occupied": true,
        "occupiedBy": "Tharma",
        "purpose": "Review",
        "team": "Platform",
        "timeRange": {
            "from": "2013-10-02T19:08:44.752Z",
            "to": "2013-10-02T19:08:44.752Z"
        }
    },
    "capabilities": [
        "ceiling mic",
        "room speaker",
        "projector"
    ]
},
{
    "_id": "52488794c6d8a5a3b8949f71",
    "alias": "",
    "hallId": "4",
    "locationHint": "Near front office",
    "name": "Front Office Discussion room",
    "bookQueue": [],
    "occupancy": {
        "occupied": false,
        "occupiedBy": "",
        "purpose": "",
        "team": "",
        "timeRange": {
            "from": "2013-10-02T19:08:44.752Z",
            "to": "2013-10-02T19:08:44.752Z"
        }
    },
    "capabilities": [
        "ceiling mic",
        "room speaker",
        "TV"
    ]
}
]

I want to update the hall.occupancy, when the current date ( Date.now() )is greater than hall.occupancy.timeRange.to . In this case, I am not going to watch hall.occupancy.timeRange.to because, it is not the property that is going to change. Is there an angular way to do this, because it would get really messy to put a setInterval.

I am not really sure on how to go about this.

I am still in the early stages of learning angular, so it would be good if you were gentle in pointing out an efficient way.

Upvotes: 1

Views: 209

Answers (3)

Vignesh PT
Vignesh PT

Reputation: 644

Perhaps, I am doing this to solve this problem, but I am not sure if this is the best way.

setInterval(function(){
    if($scope.halls)
    {
        for(var i =0 ;i< $scope.halls.length;i++){
            var hall = $scope.halls[i];
            if(hall.occupancy.timeRange.to){
                if(Date.now() > new Date(hall.occupancy.timeRange.to.toString())){
                    //change occupancy.. either dequeue from blockQueue, shift to occupancy, or change occupancy.occupied to false
                    $scope.halls[i].occupancy = {occupied:false,occupiedBy:"",purpose:"",team:"",timeRange:{from:"",to:""}};
                    socket.emit('updateHall',$scope.halls[i]);
                    $scope.$apply();
                }
            }
        }
    }
},500);

So, basically, it checks every 500 milliseconds whether the current time is later than hall.occupancy.timeRange.to , if so, it resets the hall.occupancy field.

Let me know if you have a better solution.

Upvotes: 0

kseb
kseb

Reputation: 702

You can sort your array by hall.occupancy.timeRange.to and execute setInvertal to the nearest upcoming date. Do the same again after timer event is fired taking the next item from sorted list.

If your list changes you have to cancel active timeout and set the new one using described procedure.

In my opinion $digest phase is not enough if you want to create notifications for inactive users - they leave the site with opened tab and do something else (I do that very often with Stackoverflow).

However if there is a lot of user events (clicks, playing with ng-model etc) in your application you should watch time and check the list after each 10 seconds:

var watchFn = function() {
    var d = new Date();
    return '' + d.getMinutes() + Math.floor(d.getSeconds()/10);
};
$scope.$watch(watchFn, function() {
    console.log('User did something and $watch is fired after minimum 10s.');
});

Upvotes: 1

Jason Goemaat
Jason Goemaat

Reputation: 29234

I don't think that is something you can easily do. the $watch function watches a certain angular expression executed in the scope. You don't have a $scope.hall so it won't do anything. You could possibly watch each instance, but what if you add or remove items from the array?

$scope.$watch('halls[0].occupancy.timeRange.to', function(a, b) {

It would probably be better to just watch the halls array and loop through it to do your check on each item when anything changes. That is basically what angular does to detect changes itself.

$scope.watch('halls', function (newValue, oldValue) {
    var now = Date.now();
    for (var i = 0; i < newValue.length; i++) {
        // check each item
    }
};

Upvotes: 1

Related Questions