1

With Angular/UI-Router, is it possible to change an element's class in viewA@stateA from viewB@stateA.stateB's controller? WITHOUT changing state?

Here are my state definitions:

.state('map', {
    url: '/map',
    views:
    {
        '': {
            templateUrl: 'Views/templates/layout.html'
        },
        ......
        'kymap@map': {
            templateUrl: 'Views/templates/ky.map.html',
            controller: 'MapController'
        }
    }
})
.state('map.districts', {
    params: { fips: null },
    views:
    {
        'districtlist': {
            templateUrl: 'Views/templates/county.districts.html',
            controller: 'CountyDetailsController'
        }
    }
})
.....
.state('map.distributordistricts', {
    params: { distributorid: null, distributorname: null },
    views:
    {
        'distributordistricts': {
            templateUrl: 'Views/templates/distributor.districts.html',
            controller: 'DistributorDistrictsListController'
        }
    }
})
.....

EDIT: ADDED RELEVANT SERVICE AND CONTROLLERS CODE

// the Sharing Service
 app.factory('HighlightService', function () {
    return {
        sharedObject: { data: [] }
    };
});

// Controller that has the data I want to share with the other controller
 app.controller('DistributorDistrictsListController', ['$scope', '$state', '$stateParams', 'DistributorDistrictsService', 'HighlightService',
    function ($scope, $state, $stateParams, DistributorDistrictsService, HighlightService) {
        $scope.distributorname = $stateParams.distributorname;
        $scope.distributordistricts = DistributorDistrictsService.query({ id: $stateParams.distributorid })

        $scope.distributordistricts.$promise.then(function (data) {

            var countyfpList = [];

            for (var i = 0; i < data.length; i++) {
                countyfpList.push(data[i].CountyFP);
            }
            // clear
            HighlightService.sharedObject.data.length = 0;
            // 2. fill the first array with items from the second
            [].push.apply(HighlightService.sharedObject.data, countyfpList);

        });


        $scope.showDetail = function (id) {
            $state.go('map.districtdetails', { districtid: id });
        }
}]);

// controller I want to get the data (without activating its state.
// i simply want an ng-class directive's expression to act on it.
/* Map Controller  */
app.controller('MapController', ['$scope', '$state', 'HighlightService', function ($scope, $state, HighlightService) {
    $scope.showDetail = function (fips) {
        $scope.toggleActiveCountyFP = fips;
        $state.go('map.districts', { fips: fips });
    }

    $scope.$watch('HighlightService.sharedObject.data', function (newValue, oldValue) {
        console.log(newValue)
    }, true);
}]);

END EDIT

From DistributorDistrictsListController, I have a list of County codes that are associated with the id of several SVG path elements in kymap@map... I need to toggle a class on or off on these path's based on whether or not the associated id is in that list.

I attempted it with a service that exposed an object to share, and then used ng-class with an expression like SharingService.SharedObject.MyList.indexOf(id) > -1 but couldn't get it to work.

Also of note, the SVG is created with d3 inside a custom directive that is compiled so that angular directives are working properly.

Can anyone provide some insight, or maybe a simple example?

mkelley82
  • 177
  • 1
  • 13

1 Answers1

1

There are two general ways

1) Use service (as you've tried)
2) Profit from scope inheritance coming with UI-Router - How do I share $scope data between states in angularjs ui-router?

In case, that service is not working for you - be sure that you DO NOT change reference... to shared array:

Short way to replace content of an array

So, if you do $watch the

$scope.$watch('SharingService.SharedObject.MyList', ...

you should always keep its reference, even when replacing the content

// clear
SharingService.SharedObject.MyList.length = 0;
// 2. fill the first array with items from the second
[].push.apply(SharingService.SharedObject.MyList, someSource);

because

SharingService.SharedObject.MyList = someSource // any[]

would change the reference

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Ok, I tried implementing your $scope.$watch suggestion but can't seem to get it to work. I've edited my question to include the relevant sharing service, and the two controllers. From the console.log inside $scope.watch( ... ), it doesn't seem to be seeing it update. Any insight? – mkelley82 Oct 26 '15 at 06:22
  • Here I have an simplified, but really comprehensive example for http://plnkr.co/edit/sOERAGU2HeI37zHSVL7H?p=preview. I created this one, because I miss lot of your settings. You can create or extend my plunker and I could assist to ... hope it helps ;) (1. first state add random numbers, 2. second one always reload the array - but they do share reference) – Radim Köhler Oct 26 '15 at 06:45
  • There is an enhnaced ;) version.. which contains also "load" ... so we can see that the shared array is still properly used/shared http://plnkr.co/edit/g4FoqPrIydRd9fEi5HwA?p=preview – Radim Köhler Oct 26 '15 at 07:21
  • This is definitely the solution. I'm not quite sure what I was doing wrong before, but I found a similar example to yours.... [fiddle](http://jsfiddle.net/n2CPC/16/) from this answer [http://stackoverflow.com/questions/21414675/angular-ui-router-nested-views-dont-refresh-data-retrieved-by-angular-services](http://stackoverflow.com/questions/21414675/angular-ui-router-nested-views-dont-refresh-data-retrieved-by-angular-services). Thank you so much. Exactly what I needed! – mkelley82 Oct 26 '15 at 07:26
  • Amazing to see that you do have solution. Enjoy mighty UI-Router and angular, sir ;) – Radim Köhler Oct 26 '15 at 07:27