I am trying to watch when an array in a service is updated. I update this array in the service using a function in a directive based controller. Now for some reason the watch function does not get called in the link function of the second directive. Why is watch not being called in the second directive. I am trying to update the scope of a variable in the second directive so that it updates when the first directive function updates the service.
The Service
var productServices = angular.module('productServices', ['ngResource']);
productServices.factory('PlayerListS', [function() {
var playerList = [];
function getList() {
console.log(playerList);
return playerList;
}
function addToList(name) {
playerList.push(name);
}
return {
addToList :addToList,
getList: getList
}
}]);
The Directives
'use strict';
bands.directive("player",['PlayerListS', function (PlayerlistS) {
return {
restrict: 'E',
scope: {
person:'#person',
add:'&add'
},
replace: false,
templateUrl: "partials/player.html",
controller: function($scope, $element, $compile) {
$scope.playerList = ["A", "B"];
$scope.add = function(name) {
PlayerlistS.addToList(name);
PlayerlistS.getList();
}
},
link: function(scope, el, attrs) {
}
};
}]);
bands.directive("playerList", ['PlayerListS', function (PlayerlistS) {
return {
restrict: 'E',
replace: false,
template: "<p>Test</p>",
controller: function($scope, $element, $compile) {
},
link: function($scope, $el,$attrs) {
console.log('added');
var x = PlayerlistS.getList()
/*THIS IS WHERE THE WATCH IS HAPPENING*/
$scope.$watch('x', function (newVal, oldVal) {
console.log("CHANGED");
}, true);
}
};
}]);
The Controller
var bands = angular.module('bands', []);
bands.controller('ViewHousesCtrl', ['$scope', '$element', '$routeParams', '$q',
function ViewHousesCtrl($scope, $element, $routeParams, $q) {
$scope.playerLis = ["A","B","C"];
}]);
HTML
<player ng-show="true" person="RandomName" add="add()"></player>
<player-list ng-show="true" ng-repeat="a in playerLis"></player-list>
What your watcher is really doing, is trying to watch a variable called x on the directive scope. But your variable x is just a regular local variable, so your watcher doesn't trigger. So what your watcher basically translates to is this:
$scope.$watch(function(scope){
return scope['x'];
}, function (newVal, oldVal) {
console.log("CHANGED");
}, true);
You can probably see why it doesn't trigger. There is no variable $scope.x. Instead you should try watching the service directly, by specifying the watch function. Like this:
$scope.$watch(function(){
return PlayerlistS.getList();
}, function (newVal, oldVal) {
console.log("CHANGED");
}, true);
You have a spelling mistake in your HTML, it should be:
<player-list ng-show="true" ng-repeat="a in playerList"></player-list>
Related
Currently, I am facing one issue related to angularjs directive. I want to send outlet object from directive1 to directive2. Both directives having same controller scope. I tried with emitting event from directive1 to controller, broadcasting that event from controller to directive2 and listening to that event on directive2. but that is not working.
Directive1:
angular.module('moduleName')
.directive('directive1', function() {
return {
restrict: 'E',
templateUrl: 'directive1.html',
scope: false,
link: function(scope) {
scope.selectOutlet = function(outlet) {
scope.order.entityId = outlet.id;
scope.navigation.currentTab = 'right';
};
}
};
Here, in directive1, scope.selectOutlet() setting outletId to scope.order.entityId. I want to move/set that line to directive2 save function.
Directive2:
angular.module('moduleName')
.directive('directive2', function(config, $rootScope, $state) {
return {
restrict: 'E',
templateUrl: 'directive2.html',
scope: false,
link: function(scope) {
scope.save = function() {
// Save functionality
// scope.order.entityId = outlet.id; This is what i want to do
};
}
};
});
});
Any help.
you can use a factory or a service. Inject that factory into your directive. Now when you are trying set the data in function written into factory. `app.factory('shared',function(){
var obj ={};
obj.setData = function(){
// call this function from directive 1.
}
return obj;
})`
So if you include this factory into your directives you will get the data in 2 directives.
I will try to make some jsfiddle or plunker. If it is not clear.
Do the following in first directive
angular.module('moduleName')
.directive('directive1', function($rootScope) {
return {
restrict: 'E',
templateUrl: 'directive1.html',
scope: false,
link: function(scope) {
scope.selectOutlet = function(outlet) {
$rootScope.$broadcast('save:outlet',outlet);
//scope.order.entityId = outlet.id;
//scope.navigation.currentTab = 'right';
};
}
};
and in second
angular.module('moduleName')
.directive('directive2', function(config, $rootScope, $state) {
return {
restrict: 'E',
templateUrl: 'directive2.html',
scope: false,
link: function(scope) {
$rootScope.$on('save:outlet',function(event,data){
// do staff here
});
}
};
});
My app is like this:
angular.module('app', [
// other includes
'ui.bootstrap'
])
in my directive I'm working on :
angular.module('app').directive('DateFields','DatepickerController', ['$timeout', 'DatepickerController', function ($timeout, DatepickerControlle) {
return {
restrict: 'A',
replace: true,
templateUrl: 'path to calendar.html',
scope: {
element: "=",
flowParameterMap: "=?"
},
controller: ['$scope', '$element', '$timeout', function (scope, element, $timeout) {
if (!scope.element)
return;
scope.overlayClick = function (e)
{
scope.isOpen = true;
var input = $(e.currentTarget).next();
$timeout(function () {
$(input).focus();
$DatepickerController.isOpen = true;
});
}
}]
};
}]);
As you can see I'm trying from code change value of datepickers isOpen variable to show datepicker binded to the other dom object.
But all my tries end in "is undefined" error.
Try this in your directive:
scope: {
element: "=",
isOpen: "=",
flowParameterMap: "=?"
},
Now you should be able to chagne isOpen value.
I have a directive in which controller exists, where i have a function. I need to call that function from another controller.
Directive :
angular.module('test.directives').directive("manageAccess", function() {
return {
restrict: "E",
replace: true,
templateUrl: "template/test.html",
controller: function($scope, $element, $http) {
$scope.getRoles = function() {
console.log('hi');
};
}
};
});
$scope.getRoles method is the method i need to call from different controller.
Controller:
angular.module("test.controllers").controller("testController", function($scope, $http) {
$scope.getUsers = function() {
// i need to call getRoles method here
}
});
How can i do that?
Please help,
Thanks.
You can use AngularJS Service/Factory
I put the getRoles function within the factory for the API which can be injected anywhere.
Working Demo
var RolesModule = angular.module('UserRoles', []);
RolesModule.factory('RolesAPI', function() {
return {
getRoles: function() {
this.roles = 'my roles';
console.log('test');
}
}
});
angular.module("test.controllers",['UserRoles'])
.controller("testController",function($scope,$rootScope,RolesAPI, $http) {
$scope.getUsers = function() {
RolesAPI.getRoles();
}
});
angular.module('test.directives',['UserRoles'])
.directive("manageAccess", function() {
return {
restrict: "E",
replace: true,
templateUrl: "template/test.html",
controller: function($scope, $element, $http) {
}
};
})
Try following
angular.module('test.directives').directive("manageAccess", function() {
return {
restrict: "E",
replace: true,
scope: {getRoles: '='},
templateUrl: "template/test.html",
controller: function($scope, $element, $http) {
$scope.getRoles = function() {
console.log('hi');
};
}
};
});
controller
angular.module("test.controllers").controller("testController", function($scope, $http) {
$scope.getUsers = function() {
// i need to call getRoles method here
$scope.getRoles()
}
});
in html
<manage-access get-roles="getRoles"></manage-access>
If the function is not dependent on the directive elements, move that to a service pass it to both directive and the testcontroller.
I wan to call a function which returns value and I want to use that value as ng-model.
the returned value from function should be displayed in a dialog.
I see my dialog empty - No Data.
here is my code:
my-dialog is a directive to show dialog which accepts templateurl and ng-model.
<my-dialog my-dlg-template-url="/app/ScheduleDlg.html" ng-model="ViewSchedule">
<button ng-click="openDialog()">Schedule</button>
</my-dialog>
here is the function to be called in ng-model.
$scope.ViewSchedule = function () {
console.log('ViewSchedule function call');
.....
return obj.Schedule();
};
here is the directive:
return {
require: 'ngModel',
replace: true,
transclude: false,
priority: 100,
restrict: 'E',
scope: true,
link: function ($scope, $element, $attrs, $ctrl) {
var getDialogTemplate = $attrs.myDlgTemplateUrl;
$scope.openDialog = function (confirmationAction) {
var modalInstance = $modal.open({
backdrop: 'static',
templateUrl: getDialogTemplate,
controller: "myDialogCtrl",
resolve: {
dialogData: function () {
return {
dlgData: $attrs.ngModel
};
}
}
});
modalInstance.result.then(function () {
return confirmationAction();
});
};
}
};
}])
.controller('myDialogCtrl', ['$scope', '$modal', '$modalInstance', 'dialogData', function ($scope, $modal, $modalInstance, dialogData) {
$scope.dialogData = dialogData.dlgData;
$scope.onOk = function () {
$modalInstance.close();
};
$scope.onCancel = function () {
$modalInstance.dismiss('cancel');
};
}])
Here is the dialog template :
<tr ng-repeat="item in dialogData">
<td>{{item.$index}}</td>
<td>{{item.StartDate}}</td>
<td>{{item.EndDate}}</td>
</tr>
ng-model establishes a 2 way data binding only needed if you are planning to alter the model if not a simple scope definition with one way binding or a reference bound would do it
you currently have
scope:true
you can do
scope:{
watchfor:'#result'
}
and inside the directive set a watcher
scope.$watch('watchfor',function(val){})
in your direcitve declaration you could have.
<my-dialog my-dlg-template-url="/app/ScheduleDlg.html" result="ViewSchedule()"> </my-dialog>
and set this in your directive template
<button ng-click="openDialog()">Schedule</button>
unless you want it linked to your parent scope.
I'm unit testing one of my directives. Its basic structure is like this
angular.module('MyApp')
.directive('barFoo', function () {
return {
restrict: 'E',
scope: {},
controller: function ($scope, $element) {
this.checkSomething = function() { .... }
},
link: function(scope, element) { .... }
}
});
In my unit test I want to test the function 'checkSomething', so I tried
var element = $compile('<barFoo></barFoo>')(scope);
var controller = element.controller()
...
However, controller is undefined. Is it possible to access the controller of the directive ?
the glue is your scope so you can do
controller: function ($scope, $element) {
this.checkSomething = function() { .... }
$scope.controller = this;
},
but i think it would be best practice to attach every function to the scope like
controller: function ($scope, $element) {
$scope.checkSomething = function() { .... }
},
and then its
var element = $compile('<barFoo></barFoo>')(scope);
var checksomthingResult = scope.checkSomething ()