How to use a service from directive to call a function? - javascript

controller
angular.module('myApp')
.controller('myCtrl', [ '$mdDialog', '$mdMedia', 'viewDialog', myCtrl]);
..
function myCtrl( $mdDialog, $mdMedia, viewDialog) {
$scope.viewItem = function(ev,id) {
viewDialog.ITEM(ev,id)
};
}
html
<div ng-controller="myCtrl">
<md-list-item ng-repeat="item in myarr">
<a my-view-dialog">
<h4> {{item.id}} </h4>
</a>
</md-list-item>
</div>
When I call the function directly form controller the modal window works fine on click
using the directive
My directive
angular.module('myApp')
.directive('myViewDialog', function ($parse) {
return {
compile: function(tElm,tAttrs){
var exp = $parse('viewItem($event,item.id)')
return function (scope,elm){
elm.bind('click',function(){
exp(scope);
});
};
}
};;
});
Now I want to remove the controller dependency and directly call the viewDialog service from the directive it does not work.
here is code for service injection
angular.module('myApp')
.directive('myViewDialog', function ($parse, viewDialog) {
return {
compile: function(tElm,tAttrs){
var exp = $parse('viewDialog.ITEM($event,item.id)')
return function (scope,elm){
elm.bind('click',function(){
exp(scope);
});
};
}
};;
});

Instead of
.directive('myViewDialog', function ($parse, viewDialog)
Try
.directive('myViewDialog', [ '$parse', 'viewDialog', function ($parse, viewDialog)

angular.module('myApp')
.directive('myViewDialog',['viewDialog','$parse', function (viewDialog,$parse) {
return {
compile: function(tElm,tAttrs){
var exp = $parse('viewDialog.ITEM($event,item.id)')
return function (scope,elm,attr,ctrl){
elm.bind('click',function(){
exp(scope);
});
};
}
};;
}]);

Related

$watch on array in service not working in directive

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>

AngularJS $rootScope.$emit not Firing the Method

I want to fire a directive based on demand using a service. Below is the directive code.
var app = angular.module('MyModule').service('DOMService', ['$rootScope', function ($rootScope) {
this.Manipulate = function () {
$rootScope.$emit('manipulateDOM');
};
}]).directive('domDirective', ['$rootScope', function ($rootScope) {
return {
restrict: 'EA',
replace: 'false',
scope: true,
link: function (scope, elm, attrs) {
$rootScope.$on("manipulateDOM", function () {
alert("Entered......");
// element.find('#DirectiveLable').css('background-color', 'red')
// element.find('#DirectiveLable').css('height', '100')
});
},
};
}]);
My HTML like below
<div id="example">
<div id="grid"></div>
<dom-directive>
<label id="DirectiveLable">Click Here</label>
</dom-directive>
</div>
I am calling the service like below inside my Angular Controller
angular.module('MyModule').controller('CitizenRelationAccordionController', ['$scope', '$q', '$attrs', 'DOMService',
function ($scope, $q, $attrs, DOMService) {
DOMService.Manipulate();
}
]);
Issue is that eventhough DOMService is firing, it's not invoking the directive method where alert has written
I think that you missed the [] in the module declaration: here is a working example from what you wrote.
Hope this could help,
Dario

Calling a Directive from another Directive

Please consider this tryout on Plunkr.
I have a simple set up:
<body ng-app="myApp">
<div ng-controller="myController">
<parent-directive></parent-directive>
<child-directive></child-directive>
</div>
</body>
With the parent directive defined like:
app.directive("parentDirective", [
"$compile",
function (
$compile) {
return {
scope: {
person: "="
},
restrict: "E",
template: "<h3>I'm a parent</h3>",
controller: [
"$scope",
function ($scope) {
// --- PRIVATE --- //
var self = {};
$scope.ClickMe = function() {
alert('Parent clicked');
};
}],
link: function ($scope, $elem, $attrs) {
}
};
}]);
And child directive defined like:
app.directive("childDirective", [
"$compile",
function (
$compile) {
return {
scope: {
person: "="
},
restrict: "E",
require: "^?parentDirective",
template: "<h3>I'm a child, click <button ng-click='ClickMe()'>here</button></h3>",
controller: [
"$scope",
function ($scope) {
// --- PRIVATE --- //
var self = {};
$scope.ClickMe = function() {
alert('child clicked');
$scope.parentDirective.ClickMe();
};
}],
link: function ($scope, $elem, $attrs) {
}
};
}]);
The child click is handled, but the click defined on the `parent', returns undefined:
TypeError: Cannot read property 'ClickMe' of undefined
looking at the console.
Any idea what's going wrong?
Any idea what's going wrong?
You cannot require a sibling directive.
The required directives controller methods dont get exposed automagically onto your scope.
You should expose methods on the controller itself, not on the assigned $scope.
You can require a directive that is defined on the same element as the requiring directive, or on a parent element.
<child-directive parent-directive></child-directive>
<parent-directive>
<child-directive></child-directive>
</parent-directive>
When you require the controller (aka. exposed API) of another directive, it doesn't magically end up on the $scope of the requiring directive.
It does however end up in your link function as the fourth argument.
Like so:
.directive('child', function () {
return {
require: '?^parentDirective',
link: function (scope, el, attrs, parentDirectiveController) {
scope.clickMe = function () {
parentDirectiveController.clickMe();
};
}
};
});
Expose the methods you want available in other directives onto this instead of $scope, as the $scope way of doing it won't work the way you intend it to when you have isolated scopes.
.directive('parent',
controller: function () {
this.clickMe = function () {};
}
}
To get your example working;
<parent>
<child></child>
</parent>
.directive('parent', function () {
return {
controller: function () {
this.clickMe = function () {};
}
};
}
.directive('child', function () {
return {
require: '^?parent',
link: function (scope, el, attrs, parentCtrl) {
scope.clickMe = function () {
parentCtrl.clickMe();
};
} 
};
});
Simplified (& working) version of your plunker: http://plnkr.co/edit/nao4EvbptQm7gDKkmZS2?p=preview
Put your child directive in your parent directive template. Then use $scope.$parent.ClickMe(). Here's what it would look like.
Simple setup:
<body ng-app="myApp">
<div ng-controller="myController">
<parent-directive></parent-directive>
</div>
</body>
Parent directive:
app.directive("parentDirective", [
function () {
return {
scope: {},
restrict: "E",
template: "<h3>I'm a parent</h3><child-directive></child-directive>",
controller: [
"$scope",
function ($scope) {
$scope.ClickMe = function() {
alert('Parent clicked');
};
}
]
};
}
]);
Child directive:
app.directive("childDirective", [
function () {
return {
restrict: "E",
template: "<h3>I'm a child, click <button ng-click='ClickMe()'>here</button></h3>",
controller: [
"$scope",
function ($scope) {
$scope.ClickMe = function() {
alert('child clicked');
$scope.$parent.ClickMe();
};
}
]
};
}
]);
I might be thinking about your problem a little differently but I would take a look at $broadcast. The idea is you can broadcast an event and have "n" number of directives in your case listening for that event.
http://plnkr.co/edit/wBmX2TvC3yMXwItfxkgl
brodcast:
$scope.ClickMe = function() {
alert('child clicked');
$rootScope.$broadcast('child-click');;
};
listen:
$scope.$on('child-click', function (event, args) {
alert('Parent clicked');
});

$scope.$apply() not calling function

I have a need for a custom click directive, which executes the passed code using scope.$apply().
$(elem).on('click', function(){
scope.$apply(attrs.wdClick);
});
This works fine if I pass something like wd-click="something = !something". But when I try to call a $rootScope function it does not work, however it does work when using the default ng-click.
wd-click="$root.someFunction()" //this does not call the function but ng-click does
I have tried updating the directive to make it work
$(elem).on('click', function(){
$rootScope.$apply(attrs.wdClick);
});
But this does not work either. Any ideas?
attrs.wdClick is a string, so passing it to $apply won't do anything. To call the function you can pass the string to $eval
scope.$apply(function() {
scope.$eval(attrs.wdClick)
});
You should wrap your code in function(){}
scope.$apply(function(){
attrs.wdClick() // this is some sunction I suppose
});
Would you want to call your rootscope method in an another controller? If I understand correctly, try to use this way :
angular.module('app', [])
.controller('Ctrl', function Ctrl1($scope, $rootScope) {
$rootScope.blah = 'Hello';
$scope.yah = 'World'
})
.directive('myTemplate', function() {
return {
restrict: 'E',
templateUrl: 'my-template.html',
scope: {},
controller: ["$scope", "$rootScope", function($scope, $rootScope) {
console.log($rootScope.blah);
console.log($scope.yah);
$scope.test = function(arg) {
console.log(arg);
}
}]
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="Ctrl">
<my-template></my-template>
</div>
<!-- my-template.html -->
<script type="text/ng-template" id="my-template.html">
<label ng-click="test($root.blah)">Click</label>
</script>
</div>
Also you can try on jsfiddle,
http://jsfiddle.net/mg74b/24/
Is there a reason you are trying to use attrs instead of a scope property? Also, you should use $timeout instead of $apply.
angular
.module('app', [])
.directive('myDirective', myDirective);
myDirective.$inject = ['$timeout'];
function myDirective($timeout) {
return {
restrict: 'E',
templateUrl: 'my-template.html',
scope: {
wdClick: '='
},
link: linkFn
};
function linkFn(scope, element) {
element.on('click', function () {
$timeout(scope.wdClick);
});
}
}

ngBindHtml not Rendering Sanitized HTML

I've got a simple angular app, and I'm trying to inject some html into the page using ngBindHtml. However, it's not being injected. Here's my HTML:
<main id="main" ng-bind-html="oreGen | trust"></main>
And here's my angular app:
angular.module('programApp', ['programApp.controllers','programApp.filters','ngSanitize']);
angular.module('programApp.controllers', [])
.controller('programController', ['$scope', '$filter', function($scope, $filter){
$scope.oreGen = '<div class="oreFunction" ng-click="collectFunction(\'parenthesis\', 1)">test text</div>';
$scope.collectFunction = function(value1, value2){
alert(value1 + value2);
};
}]);
angular.module('programApp.filters', []).filter('trust', ['$sce', function($sce){
return function(text) {
return $sce.trustAsHtml(text);
};
}]);
When the page is loaded, nothing appears inside the main element.
Here's a codepen: http://codepen.io/trueScript/pen/MwbVpO?editors=101
You can see the div being ngBinded does not appear. Why is this?
You can use a directive instead a filter. Please look at this JSFiddle
HTML:
<div ng-app="myApp" ng-controller="programController">
<dir id="main" content="oreGen"></dir>
</div>
JS:
angular.module('myApp', [])
.controller('programController', ['$scope', '$filter', function ($scope, $filter) {
$scope.oreGen = '<dir class="oreFunction" ng-click="collectFunction(\'parenthesis\', 1)">test text</dir>';
$scope.collectFunction = function (value1, value2) {
alert(value1 + value2);
};
}])
.directive('dir', function ($compile, $parse) {
return {
restrict: 'E',
link: function (scope, element, attr) {
scope.$watch(attr.content, function () {
element.html($parse(attr.content)(scope));
$compile(element.contents())(scope);
}, true);
}
}
});

Categories