1

I have a simple activity viewer in a table that lists activities and their statuses (read or not read) from a db. On the page is a counter that shows how many activities are unread. Each activity gives the option to mark read or mark unread depending on the condition. For some reason after the model is being updated the computed value is not changing on the counter.

Controller

function Activity($scope, $http, $templateCache)
{
    $http.get('/activity/get').success(function(data, status)
    {
        $scope.activities = data;
    });

    $scope.totalActivities = function()
    {
        var count = 0;

        angular.forEach($scope.activities, function(activity)
        {
            count += activity.seen == 0 ? 1 : 0;
        });

        return count;
    }

    $scope.updateActivity = function(activity)
    {
        activity.seen = activity.seen == 0 ? 1 : 0;

        $http({
            method: 'PUT',
            url:    '/activity/' + activity.id,
            data:   { seen: activity.seen }
        })
        .success(function(data, status)
        {
            console.log(data);
        });
    }
}

Counter

<span class="badge badge-alert">{{ totalActivities() }}</span>

Table row + button

<tr ng-repeat="activity in activities" ng-class="{ 'activity-read': activity.seen == 1 }"> 
    <td>
        <button class="btn btn-default" ng-click="updateActivity(activity)"><span>@{{ 0 == activity.seen ? 'Mark Read' : 'Mark Unread' }}</span></button>
    </td>
</tr>

nav template (separate code block)

<div class="account-details" ng-controller="Activity">
    @if (Sentry::hasAccess('admin'))
    <a href="{{ route('activity.index') }}" class="activity pull-left">
            <span class="badge badge-alert">@{{ totalActivities() }}</span>
        </a>
    @endif
</div>

The counter works fine when first loaded but any updates to the model need a page refresh for the new calculation to show.

Jared Eitnier
  • 7,012
  • 12
  • 68
  • 123
  • the best way to get an answer would be to set up a jsfiddle or plnkr that reproduces the problem. – akonsu Mar 11 '14 at 14:18

2 Answers2

0

Something tells me we aren't seeing the relavant bits of your code here.

When I recreate your example using $timeout instead of $http everything is working just fine:

var Activity = function($scope, $timeout) {
    console.log('creating controller');

    var fakeData = [
          {name: 'One',   seen: 0}, 
          {name: 'Two',   seen: 0},
          {name: 'Three', seen: 1},
          {name: 'Four',  seen: 0}
    ];

    $timeout(function () {
        $scope.activities = fakeData;
        console.log('data returned');
    }, 500);

    $scope.totalActivities = function () {
        var count = 0;

        angular.forEach($scope.activities, function (activity) {
            count += activity.seen === 0 ? 1 : 0;
        });

        return count;
    };

    $scope.updateActivity = function (activity) {
        activity.seen = activity.seen === 0 ? 1 : 0;

        var payload = {
            method: 'PUT',
            url: '/activity/' + activity.id,
            data: {
                seen: activity.seen
            }
        };

        $timeout(function () {
            console.log(payload);
        }, 200);
    };
};

jsFiddle Here: http://jsfiddle.net/jwcarroll/EBSB4/

Josh
  • 44,706
  • 7
  • 102
  • 124
  • So I moved the counter around a bit and seems like it's a `scope` issue possibly? See updated code in my question. The counter is in a separate div outside of the original calling controller. I moved the `ng-controller` block up so it includes both the counter and the table. Is that just the best way to go about it? – Jared Eitnier Mar 11 '14 at 14:13
  • I figured out my `$scope` issue once I discovered `$emit` and `$on`. I setup a parent controller and sent the value up from the child controller and voila! Thanks – Jared Eitnier Mar 11 '14 at 15:05
0

I also struggled for a while with computed properties and $watch and so on, couldn't imagine that it should be so difficult, then I found this solution:

What is the analog for Knockout's writable computed observable in AngularJS?

Just use the power of Javascript itself to define an object getter and setter. No need for $watch, brilliantly simple.

Community
  • 1
  • 1
leo
  • 1,175
  • 12
  • 13