binding a click event on a directive's child element - javascript

more angular confusion. namely, why cannot i bind a child element of a directive to a click event?
app.directive('expandingTile', [function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.bind('click', function() {
console.log('elem hit!');
});
elem.find('div#CloseBtn').bind('click', function() {
console.log('found child hit!')
});
}
}
}]);

Try using this
link: function (scope, element) {
$timeout(function () {
element.on('click', '#Id', function () {
console.log('inside event handler of the first child)
})
})
}
And Don't forget to inject $timeout in directive

Related

Is there any way to do this with a directive?

I have no problem getting the $scope function referenced in the directive attribute to run. The problem is I need to capture the element that was touched in the directive and pass it to the function in the attribute. I haven't figure out how to do that. Isolating the scope in the directives will throw an error because there's 2 directives trying to act on the same element.
With the below code I am getting $event as undefined and an error of course. Any way to achieve what I want? Or maybe there's a better way?
<li class="list-group-item row" data-touchstart="darkenBackground($event)" data-touchend="lightenBackground($event)">
..
angular.module('myNotes')
.directive('touchstart', [function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('touchstart', function(e) {
e.preventDefault();
scope.$apply(attrs.touchstart);
});
}
};
}]);
angular.module('myNotes')
.controller('notesCtrl', ['$scope', 'Site',
function($scope, Site) {
Site.setTitle('My Notes');
Site.setActiveNavLink('myNotes');
$scope.darkenBackground = function($event) {
angular.element($event.currentTarget)
.css('background-color', '#eee');
};
$scope.lightenBackground = function($event) {
angular.element($event.currentTarget)
.css('background-color', '#fff');
}
}]);
Here's the issue:
scope.$apply(attrs.touchstart);
When you call scope.$apply directly on an angular expression (which is what attrs.touchstart is), it will automatically evaluate that expression against scope, so scope.$event (which is undefined) is passed to the callback.
To pass the event to the callback, you can use the second parameter (called "locals") of scope.$eval to temporarily include an $event property on the scope while evaluating the expression.
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('touchstart', function (e) {
e.preventDefault();
scope.$apply(function () {
scope.$eval(attrs.touchstart, {$event: e});
});
});
}
};
I got it working like so, but I'm not sure if it's the best/proper approach:
<li class="list-group-item row" data-touchstart="darkenBackground(event)">
...
angular.module('myNotes')
.directive('touchstart', [function () {
return {
restrict: 'A',
scope: {
touchstart: '&'
},
link: function (scope, elem, attrs) {
elem.bind('touchstart', function(e) {
e.preventDefault();
scope.$apply(scope.touchstart({event: e}));
});
}
};
}]);
angular.module('myNotes')
.controller('notesCtrl', ['$scope', 'Site',
function($scope, Site) {
Site.setTitle('My Notes');
Site.setActiveNavLink('myNotes');
$scope.darkenBackground = function(event) {
var elem = angular.element(event.currentTarget);
elem.css('background-color', '#eee');
elem.bind('touchend', function (e) {
$scope.lightenBackground(e);
})
};
$scope.lightenBackground = function(event) {
angular.element(event.currentTarget)
.css('background-color', '#fff');
};
}]);

pass parameter to angular directive on click

I am trying to get parameter on click using directive.I want to get child data in the click event for checking has child or not.
.....
html
div ng-app="treeApp">
<ul>
<treeparent></treeparent>
</ul>
js
(function () {
var treeApp = angular.module('treeApp', []);
treeApp.directive('treeparent', function () {
return {
restrict: 'E',
template: "<button addchild child='m'>ajith</button><div id='new'></div>"
}
});
treeApp.directive('addchild', function ($compile) {
return {
scope: {
'child':'='
},
link: function (scope, element, attrs) {
debugger;
element.bind("click", function (scope,attrs) {
debugger;
//here i want to get hild ie 'm'
angular.element(document.getElementById('new')).append("<div><button button class='btn btn-default'>new one</button></div>");
});
}
}
});
})();
plz help me
So, i think scope.child is undefined becouse it is overlaps in declaring event.
You can define variable before event binding
link: function (scope, element, attrs) {
var child = scope.child;
element.bind("click", function (scope,attrs) {
// here you can use child
console.log('child', child);
});
}
or declare different argument names
link: function ($scope, $element, attrs) {
element.bind("click", function (scope,attrs) {
// here you can use $scope.child
console.log('$scope.child', $scope.child);
});
}
Is a callback has scope and attrs argument? May be it has only one $event argument?
link: function (scope, element, attrs) {
element.bind("click", function ($event) {
// here you can use child
console.log('child', scope.child);
});
}
Example for call method from directive in parent scope
parent template
<test-dir data-method="myFunc"></test-dir>
<button ng-click="myFunc('world')">click me</button>
or
<button test-dir data-method="myFunc" ng-click="myFunc('world')">click me</button>
directive
.directive('testDir', function() {
return {
scope: {
method: '=',
},
controller : function($scope) {
$scope.method = function(text) {
alert('hello '+text);
};
},
};
})

change controller $scope from a directive

I have a controller:
function myController($scope) {
$scope.clicked = false;
}
and a directive:
function myDirective() {
return {
restrict: 'E',
link: function(scope, elem, attrs) {
elem.bind('click', function() {
// need to update controller $scope.clicked value
});
},
template: '<div>click me</div>';
replace: true;
}
}
and I´m using it like this:
<div ng-controller="myController">
<my-directive></my-directive>
</div>
How can I change the controller value of $scope.clicked ?
thanks!
As you don't use isolated scope in your directive, you can use scope.$parent.clicked to access the parent scope property.
link: function(scope, elem, attrs) {
elem.bind('click', function() {
scope.$parent.clicked = ...
});
},
I would not recommend using scope.$parent to update or access the parent scope values, you can two way bind the controller variable that needs to be updated into your directive, so your directive becomes:
function myDirective() {
return {
restrict: 'E',
scope: {
clicked: '='
},
link: function(scope, elem, attrs) {
elem.bind('click', function() {
// need to update controller $scope.clicked value
$scope.clicked = !$scope.clicked;
});
},
template: '<div>click me</div>';
replace: true;
}
}
now pass this clicked from parent:
<div ng-controller="myController as parentVm">
<my-directive clicked="parentVm.clicked"></my-directive>
</div>
function myController() {
var parentVm = this;
parentVm.clicked = false;
}
I would recommend reading up on using controllerAs syntax for your controller as that would really solidify the concept of using two way binding here.
I like to use $scope.$emit for such purposes. It allows to send data from directive to the controller.
You should create custom listener in your controller:
$scope.$on('cliked-from-directive', function(event, data){
console.log(data)
})
As you can see, now you have full access to your controller scope and you can do whatever you want. And in your directive just to use scope.$emit
link: function(scope, elem, attrs) {
elem.bind('click', function() {
scope.$emit('cliked-from-directive', {a:10})
});
Here I've created jsfiddle for you

Angular directive event not triggered in compile function

I have tried alot but didn't got success, how can i trigger ng-click in such scenario where it is bind in compile function?
function() {
return {
restrict: 'EA',
compile: function(element, attr) {
return function(scope, element, attr) {
element.html('<div ng-click="save()"></div>');
}
},
controller : function($scope){
$scope.save = function(){
console.log('save');
}
}
};
}
])
Use the link and $compile to produce the results you require:
return {
restrict: 'EA',
link: function (scope, element) {
element.html('<div ng-click="save()">save</div>');
$compile(element.contents())(scope);
},
controller: function ($scope) {
$scope.save = function () {
console.log('save');
}
}
}

AngularJS - Directive wrapping without losing connection to controller

Is there a way for not losing connection to the current controller when you are wrapping data with a directive ?
My problem is, that the directive within the wrapped template has no connection to the outside controller any more and so I can not execute the function.
Wrapping Directive:
myApp.directive('wrapContent', function() {
return {
restrict: "E",
scope: {
model: "=",
datas: "="
},
templateUrl: "./any/template.php",
link: function(scope, element, attr) {
// any
}
};
});
Directive within the wrapped Template
myApp.directive('doAction', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
$(elem).click(function(e) {
scope.$apply(attrs.doAction);
});
}
}
});
Conroller:
lmsApp.controller('OutsideController', function ($scope){
$sope.sayHello = function() {
alert("hello");
};
});
HTML where I want to execute the function (template.php):
<div>
<do-action="sayHello()"></do-action>
</div>
How I call the wrapContent directive which is outside (Updated):
<div ng-controller="OutsideController">
<wrap-content model="any" datas="data_any"></wrap-content>
</div>
How can I execute the sayHello() function?
Thank you for your help! I would appreciate every answer.
wrapContent directive will be processed with the scope of controller.
DoAction directive will be processed with the isolateScope of wrapContent directive.
Solution1:
Get a reference to the sayHello function in wrapContent using '&' and execute it in event handler.
Solution2:
Instead of using scope in your event handler, use scope.$parent.
You should pass sayHallo function to your parent directive using &
myApp.directive('wrapContent', function() {
return {
restrict: "E",
scope: {
model: "=",
datas: "=",
sayHallo: "&"
},
templateUrl: "./any/template.php",
link: function(scope, element, attr) {
// any
}
};
});
HTML
<div ng-controller="OutsideController">
<wrap-content model="any" datas="data_any" sayHallo="sayHallo()"></wrap-content>
</div>
Then in your child directive, you will have sayHallo in your scope, to call it just do it this:
myApp.directive('doAction', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
scope.sayHallo();
}
}
});
And you dont need pass it again. So your child directive should looks like this:
<div>
<do-action></do-action>
</div>
UPDATE
If you want to use all your parent model functions,without passing each function. In your child directive,just use scope.model to have access to model attributes and functions.
myApp.directive('doAction', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
scope.model.sayHallo();
}
}
});

Categories

Resources