I want to dynamically define a directive after page load.
For example running this at some point any page load should output 'in a link' for every <a> element:
angular.module('myApp').directive('a', function() {
console.log('defining the directive');
return {
restrict: 'E',
controller: function() {
console.log('in a link');
}
};
});
Related
I'm using two directives in this HTML code:
<div animations>
<h2>Title</h2>
<span class="animateBtn">Animate!</span>
<info-section></info-section>
</div>
The first, is an Attribute Directive:
angular.module('app').directive('animations', ['$window', ($window: any) => {
return {
restrict: "A",
link: function ($scope: any, element: any, attrs: any) {
angular.element(document).ready(() => {
let animateBtns = angular.element(element[0].querySelector('.animateBtn'));
if (animateBtns && animateBtns.length) {
for (let i = 0, animateBtnsLength = animateBtns.length; i < animateBtnsLength; i++) {
let currentBtn = animateBtns[i];
currentBtn.addEventListener("click", function () {
.... other code....
});
}
}
..... other code .....
});
}
};
}])
So, it simply does a querySelector to select all buttons that, at the click, have to start a certain function.
And it works. The problem is that the second directive also contains an "animateBtn":
.directive('infoSection', function() {
return {
replace: true,
restrict: 'E',
template: '<div><span class="animateBtn">Animate with this too</span></div>'
}
});
The problem is that in the first directive (even if I user (document).ready()), the selector returns just one element (the span under the title), and it doesn't include the "animateBtn" of the second directive.
Here you can find the full code: PLNKR
With AngularJS one uses directives to attach code to elements instead of query selectors:
app.directive("animateBtn", function($window) {
return {
restrict: 'C',
link: postLink
};
function postLink (scope, elem, attrs) {
elem.on('click', function() {
.... other code....
});
.... other code....
}
})
The above directive will attach the click handler and associated code to each element with the class animateBtn when the element is added to the DOM by the AngularJS framework.
if a write a function inside "animations" directive, how can I trigger it inside "animatBtn" directive? I mean, in your code, inside the first line of "..... other code...." how can I call a function written in the "animations" directive?
Use the require property of the DDO to access the controller of the animations directive:
app.directive("animateBtn", function($window) {
return {
restrict: 'C',
link: postLink,
require: '^animations'
};
function postLink (scope, elem, attrs, animations) {
elem.on('click', function() {
.... other code....
});
//call animations API
animations.someMethod(args);
}
})
In the animations directive:
app.directive("animations", function() {
return {
controller: ctrl
}
function ctrl($element, $scope) {
this.someMethod = function(args) {
//code here
};
}
})
For more information, see AngularJS Comprehensive Directive API Reference - require
The onLongPress directive was working before I had to make an adjustment to my directives structures.
Now it's not working and I can't find why, perhaps someone can help me find my error.
The onLongPress should call a method from the controller assigned to the view, it doesn't, but if I add a $scope.someFn = function(); inside the directive, it works, but I need to call a method from the view's controller.
How can I solve this?
The example is the next:
<my-tabs>
<tab-one></tab-one>
<tab-two></tab-two>
...
</my-tabs>
Inside each of this tabs I have lists.
Example inside template:
<ul>
<li ng-click="doSomething()" on-long-press="doOtherthing()">
Some nice item.
</li>
</ul>
Directives are as follow:
tabOne
app.directive('tabOne', function() {
return {
restrict: 'E',
scope: false,
transclude: false,
templateUrl: 'templates/tab-one.html'
};
});
myTabs
app.directive('myTabs', function() {
return {
restrict: 'E',
templateUrl: 'templates/my-tabs.html',
scope: {
myMenues: '=',
selectedTab: '=',
general: '=',
userPoints: '=',
changetab: '&ngClick'
},
controller: function($scope) {
// Some code to add functionality. Nothing fancy.
}
};
});
onLongPress
app.directive('onLongPress', function($timeout) {
return {
restrict: 'A',
link: function($scope, $elm, $attrs) {
$elm.bind('touchstart', function(evt) {
// Locally scoped variable that will keep track of the long press
$scope.longPress = true;
// We'll set a timeout for 600 ms for a long press
$timeout(function() {
if ($scope.longPress) {
// If the touchend event hasn't fired,
// apply the function given in on the element's on-long-press attribute
$scope.$apply(function() {
$scope.$eval($attrs.onLongPress)
});
}
}, 600);
});
$elm.bind('touchend', function(evt) {
// Prevent the onLongPress event from firing
$scope.longPress = false;
// If there is an on-touch-end function attached to this element, apply it
if ($attrs.onTouchEnd) {
$scope.$apply(function() {
$scope.$eval($attrs.onTouchEnd)
});
}
});
}
};
});
UPDATE:
If I add $scope.doOtherthing = function() {}; into myTabs directive it works, but as I said, I need to get that function from the view's controller :/
Thanks.
I have a grid with button that has k-grid-cancel-changes class. I would like to create a directive that will attach a click event to that button and call method on the page scope
.directive('kGridCancelChanges', function () {
return {
restrict: 'C',
scope: {
onCancelChanges: "&"
},
controller: function ($scope, $element, $attrs, $location) {
$element.click(function () {
$scope.onCancelChanges();
});
}
}
});
When I press button I can see $scope.onCancelChanges() fired from my directive but it never reaches function on the page scope.
$scope.onCancelChanges = function () {
alert('test');
}
I would appreciate any suggestions
If you want to call a function in the scope it has to be provided like this:
<button class="k-grid-cancel-changes" on-cancel-changes="onCancelChanges()">test</button>
Demo: http://plnkr.co/edit/8vQ1wmdriGrDFGZwhqW2?p=preview
If for some reason you can't modify HTML code (say, it's rendered dynamically by Kendo) and can't add attribute, then you can only access the function to call via $parent scope reference:
$scope.$parent.onCancelChanges();
Demo: http://plnkr.co/edit/tpEEZs9VQunKXABud9yN?p=preview
And finally, if it's not principal to have isolated scope for your directive then you can simply call the function as it's the same scope:
.directive('kGridCancelChanges', function() {
return {
restrict: 'C',
controller: function($scope, $element, $attrs, $location) {
$element.click(function() {
$scope.onCancelChanges();
});
}
}
});
Demo: http://plnkr.co/edit/0OmlCJ6SgYU2GQRyBgYj?p=preview
You can create you directive like this:
app.directive('myDir', function () {
return {
restrict: 'C',
scope: {
foo: '&'
},
link: function(scope,elem){
elem.on('click',function(){
scope.foo();
});
}};
});
or use controller function instead of link if you need:
controller: function($scope,$element){
$element.on('click',function(){
$scope.foo();
});
}};
Note that angular's jqLite has no element.click function.
Here is fiddle:
http://jsfiddle.net/cxo77xb4/2/
I need to design dynamic Menu , menu items will be loaded from json . and when menu clicked i want to apply different template on them .
I was palnning to use Directives but i wonder how can i use template while appending Element in Controller .I want to use template beacuse i dont want hardcoded thing , i want to call template file.
enter link description here
how can i pass attributes to template in above fiddle?
Any other suuggestion please let me know !!
app.directive("helloWorld", function() {
return {
restrict: "E",
scope: {
name: "#name"
},
template: "<button ng-click='click()'>Click me</button>",
controller: function($scope, $element){
$scope.clicked = 0;
$scope.click = function(){
alert("Element clicked");
$element.append('yes i did it');
}
}
};
});
You can use $http to download your template and after $compile to compile it:
app.directive("helloWorld", function($http, $compile) {
return {
restrict: "E",
scope: {
name: "#name"
},
link: function(scope, element, attrs) {
$http.get("yourTemplate").then(function(template) {
$compile(template)(scope);
element.append(template);
});
}
};
});
I have this in my index.html:
<div class="content">
<div data-ng-include="'views/title.html'"></div>
<div data-ng-view=""></div>
</div>
<div data-ng-include="'views/chat.html'"></div>
Whenever the controller/route changes, the html is inserted into data-ng-view.
However, I have an Angular directive which executes a Javascript function (callMyJSFunction) when it sees that there is a class 'chat-window' attached to a div in chat.html:
angular.module('myApp').directive('chatWindow', function () {
return {
restrict: 'C',
link: function(scope, element, attrs) {
element.callMyJSFunction({
hostname: 'www.domain.com',
data: 'other data'
});
}
}
});
What I want to happen is that every time the view changes, this Javascript function is called again. How do I do this?
Note that I don't want to move the chat.html into every html file - there are 20+ different views!
You can use the viewContentLoaded event that is emitted from the ngView directive.
In your directive, you could do this:
angular.module('myApp').directive('chatWindow', ['$rootScope', function($rootScope) {
return {
restrict: 'C',
link: function(scope, element, attrs) {
element.callMyJSFunction({
hostname: 'www.domain.com',
data: 'other data'
});
$rootScope.$on('$viewContentLoaded', function() {
element.callMyJSFunction(...);
});
}
}
}]);