How to trigger an AngularJS directive every time the view changes? - javascript

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(...);
});
}
}
}]);

Related

Query selector in nested AngularJS Directives

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

Angular directive not applied on change of the value

I have a directive like
testApp.directive('changeValue', function(){
alert("coming");
return {
restrict: 'E',
link: function (scope, element, attrs) {
element.text(attrs.val);
},
replace: true
};
});
and I have my views as follows
<change-value val="{{test.val}}"/>
When I refresh my page, I could see the values and I get the alerts. But when the value is changed I don't get it applied to the directive but it binds to the view as I could see it being changed outside when simply called like
<span>{{test.val}}</span>
I am not sure how this works. Thanks in Advance!
In your code, the link function is executed only once so the value is updated only when the directive instance is created. Since you want to have a watch of its value and keep updating the text you can use $observe()
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.test = {
val: "Welcome"
};
});
app.directive('changeValue', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
attrs.$observe('val', function() {
element.text(attrs.val);
})
},
replace: true
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="my-app" ng-controller="AppController">
<change-value val="{{test.val}}"></change-value>
<input ng-model="test.val" />
</div>

AngularJS: Longpress directive not working with function in controller's view on nested directives

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.

Angular directive's link function not being called

I've got a problem with AngularJS directive link function. It's not beeing called and it doesn't throw any error. Also the template in directive's return is not rendering :( Where should be problem? Thank you for answers!
angular.module('sampleApp.game').directive('gameCanvas', function($injector) {
console.log('Directive is working'); // this works,
function linkFn(scope, ele, attrs) {
console.log('Link function doesnt working :('); // but this not :(
};
return {
scope: {},
template: '<div class="blabla"></div>',
link: linkFn
}
});
My html template file
<div class="jumbotron text-center">
<h1>Play a game!</h1>
<p>{{ tagline }}</p>
<div class="game-canvas"></div>
</div>
By default, directives are for Element and Attribute ('EA') only. Define the restrict attribute as 'C'. Best practice is to always define it explicitly.
angular.module('sampleApp.game').directive('gameCanvas', function($injector) {
console.log('Directive is working'); // this works,
function linkFn(scope, ele, attrs) {
console.log('Link function doesnt working :('); // but this not :(
};
return {
scope: {},
restrict: 'C', //'EA' by default
template: '<div class="blabla"></div>',
link: linkFn
}
});
Documented by Angular here - https://docs.angularjs.org/api/ng/service/$compile#directive-definition-object.

Dynamically define an Angular directive

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');
}
};
});

Categories