Reputation: 1154
I have an angular app that uses d3 to display items, and has an infoPanel that shows the info for items that are clicked on. This is working, but clicking on the item to activate/open the infopanel is not working.
In the d3 data control file, I have:
'use strict';
var settings ;
angular.module('App')
.directive('data', ['sessionmgmt', 'thedata', 'gui', function (session, data, gui) {
return {
link: function postLink(scope, element, attrs) {
var promise = angular....getData...;
promise.then(function () {
settings = session.settings;
svg = ...
createItems(svg, items);
}, function () {});
}
};
}]);
function createItems(svg, items) {
let item = svg.append("g")
.attr("class", "nodes")
.selectAll(".node")
.data(items, function (d) {
return d.id;
});
appendIcons(item);
}
function appendIcons(nodes){
nodes = nodes.enter().append("g")
.attr("class", "node");
nodes.append("title")
.text(function (d) {
return d.data['label'];
});
nodes.on("click",function(d){
if(settings.selectedItem === d.id){
settings.selectedItem = null;
}else{
settings.selectedItem = d.id;
}
});
}
And then in my infoPanel controller I have:
'use strict';
angular.module('App')
.controller('ContentpanelCtrl', ['$scope', 'sessionmgmt', function ($scope, sessionmgmt) {
var contentPanel = this;
this.settings = sessionmgmt.settings;
$scope.activate = function activate() {
contentPanel.settings.contentPanelOpen = true;
};
$scope.getSelected = function getSelected(){
return contentPanel.settings.itemSelected;
}
$scope.isNodeSelected = function isSelected(){
return contentPanel.settings.itemSelected !== null;
}
$scope.$watch("contentPanel.settings.itemSelected", function(newVal, oldVal) {
console.log(newVal);
if (newVal !== oldVal){
$scope.activate();
}
});
}]);
The console.log is running when the page first loads, but then when I click on the items, this watch is not being fired. I know the 'click' is working because getSelected is displaying the correct data on my infopanel. The 'watch' and getSelected are both using exactly the same settings variable.... stumped.
Upvotes: 0
Views: 69
Reputation: 2584
There are two ways of doing this. The first is what I uggested in the comment where you pass the scope of the directive as an argument into the createItems
and appendIcons
functions calling scope.$apply();
in the click event.
From the directive:
createItems(svg, items, scope);
And the other functions:
function createItems(svg, items, scope) {
let item = svg.append("g")
/* ... */
appendIcons(item, scope);
}
function appendIcons(nodes, scope){
nodes = nodes.enter().append("g")
/* ... */
nodes.on("click",function(d){
if(settings.selectedItem === d.id){
settings.selectedItem = null;
}else{
settings.selectedItem = d.id;
}
scope.$apply();
});
}
The other way is to change your $scope.$watch()
function. The contentPanel.settings.itemSelected
that you want to watch for is not part of the scope as you are using this
rather than $scope
, I assume as part of controllerAs
. To get the watch working you need to use a function as the first argument in the watch function like the following:
$scope.$watch(function(){
return contentPanel.settings.itemSelected;
}, function(newVal, oldVal) {
if (newVal !== oldVal){
$scope.activate();
}
});
Upvotes: 1
Reputation: 7179
Perhaps you can try passing the exact object into the watcher instead of string?
$scope.$watch(function() {
if (contentPanel && contentPanel.settings) {
return contentPanel.settings.itemSelected;
}
}, function(newVal, oldVal) {
console.log(newVal);
if (newVal !== oldVal){
$scope.activate();
}
});
Upvotes: 0
Reputation: 8423
As a complement to my comment.
In controller:
$scope.toggleSelectedItem = function(item) {
if(contentPanel.settings.itemSelected &&
contentPanel.settings.itemSelected === item.id){
contentPanel.settings.itemSelected = null;
}
else {
contentPanel.settings.itemSelected = item.id;
}
}
HTML:
<div ng-repeat="item in items" ng-click="toggleSelectedItem(item)">
<!--Content-->
</div>
Upvotes: 0