I have following directive:
app.directive('remoteDirective', ['$location', 'playlistService', 'videoService', function ($location, playlistService, videoService) {
return {
restrict: 'A',
link: function (scope, el, attrs) {
$('body').on('keydown', function (evt)
{
if (evt.keyCode === 38) //Up Arrow
{
scope.currentChannel.number++;
$('#modal1').openModal();
videoService.playVideo(playlistService.getChannel(scope.currentChannel.number).file);
scope.currentChannel.name = scope.playlist[scope.currentChannel.number].title;
scope.$apply();
}
else if (evt.keyCode === 40) //Down Arrow
{
scope.currentChannel.number--;
$('#modal1').openModal();
videoService.playVideo(playlistService.getChannel(scope.currentChannel.number).file);
scope.currentChannel.name = scope.playlist[scope.currentChannel.number].title;
scope.$apply();
}
else if (evt.keyCode === 13) //Enter
{
$('.button-collapse').sideNav('show');
}
else if (evt.keyCode === 27) //Esc
{
$location.path('settings');
scope.$apply();
}
});
}
};
}]);
And i Use it in my main controller like this
<div class="valign-wrapper" style="width: 100%; height: 100%" remote-directive >...</div>
Problem is, that this directive fires in all controller, not only in my main... How to solve? I want to have another actions for theese keys in other controllers...
Related
I create a directive in angularjs to change the text in my angular month view but when I switch my view from week to go back to month it doesn't show my data.
<script id="customMonthCell.html" type="text/ng-template">
<div size-elt class="cal-month-day {{day.cssClass}}">
<span
class="pull-right"
data-cal-date
ng-click="vm.calendarCtrl.dateClicked(day.date)"
ng-bind="day.label">
</span>
<small style="position: absolute; bottom: 10px; left: 5px">{{monthCalendarDayDivWidth}}
<div style="display:inline-block;margin-bottom: 5px;" ng-repeat="(petitTitle, events) in day.groups track by petitTitle">
<span ng-if="events.length > 1 && monthCalendarDayDivWidth > 130">
{{events[0].description}}
</span>
<span ng-if="events.length > 1 && monthCalendarDayDivWidth <= 130">
{{littleTitle}}
</span>
</div>
</small>
</div>
</script>
tabs.directive('sizeElt', ['$window', function ($window) {
return {
link: link,
restrict: 'A'
};
function link(scope, element, attrs) {
angular.element($window).bind('resize', function () {
scope.windowWidth = $window.innerWidth;
scope.monthCalendarDayDivWidth = element[0].offsetWidth
scope.$apply();
});
angular.element($window).bind('load', function () {
scope.windowWidth = $window.innerWidth;
scope.monthCalendarDayDivWidth = element[0].offsetWidth
scope.$apply();
});
}
}]);
This is when I load my page
this is when I click to week view and come back to month view
It's like monthCalendarDayDivWidth is not defined but if I force it when I switch the view it still doesn't work
$scope.monthCalendarDayDivWidth = $scope.windowWidth > 1080 ? 140 : 110
I modify my directive so when I switch the view in my calendar I the data can be visible
tabs.directive('sizeElt', ['$window', function ($window) {
return {
link: link,
restrict: 'A'
};
function link(scope, element, attrs) {
angular.element($window).bind('resize', function () {
scope.windowWidth = $window.innerWidth;
scope.monthCalendarDayDivWidth = element[0].offsetWidth
scope.$apply();
});
if (element.offsetWidth !== 0 || element.offsetHeight !== 0) {
setTimeout(function () {
scope.windowWidth = $window.innerWidth;
scope.monthCalendarDayDivWidth = element[0].offsetWidth
scope.$apply();
}, 0);
}
}
}]);
Below is my controller scope function :
MyApp.controller("MyController", function ($scope, MyService) {
$scope.hposition = "";
$scope.selectedRow = 0;
$scope.pSearch = {};
$scope.selectH = function (index, hId, myModel) {
$scope.selectedRow = index;
var resultList = MyService.selectH(hId, $scope.hposition, myModel);
resultList.then(function (response) {
$scope.myModel= response.data;
$("#divlookup").dialog('close');
})
} });
And I have a directive for keyboard events - keydown, keyup and keypress.
MyApp.directive('arrowSelector', ['$document', function ($document) {
return {
restrict: 'A',
link: function (scope, elem, attrs, ctrl) {
$document.bind('keydown', function (e) {
//if (elemFocus) {
if (e.keyCode == 38 || e.keyCode == 37) {
console.log(scope.selectedRow);
if (scope.selectedRow == 0) {
return;
}
scope.selectedRow--;
scope.$apply();
e.preventDefault();
}
if (e.keyCode == 40 || e.keyCode == 39) {
if (scope.selectedRow == scope.hlist.length - 1) {
return;
}
scope.selectedRow++;
scope.$apply();
e.preventDefault();
}
if (e.keyCode == 13) {
var resultList = scope.selectH(hId, $scope.hposition, myModel);
resultList.then(function (response) {
$scope.myModel= response.data;
$("#divlookup").dialog('close');
});
scope.$apply();
e.preventDefault();
}
});
}
};}]);
I tried calling the function scope.selectH(), but it is not working.
How can I call my selectH function when e.keyCode==13? Is there any other better way to do keyboard up and down arrow events ?
You just need to add scope in your directive like scope: { someCtrlFn: '&callbackFn' },
and add it to your html where you have used this directive like
<div ng-controller="MyCtrl">
<div my-directive callback-fn="ctrlFn(arg1)"></div>
Whole example as here
One more thing is that you can directly call your service from your directive and get response there by injecting service provider.
MyApp.directive('arrowSelector', ['$document','MyService', function ($document) { return {
restrict: 'A',
link: function (scope, elem, attrs, ctrl) { $document.bind('keydown', function (e) {
//if (elemFocus) {
if (e.keyCode == 38 || e.keyCode == 37) {
console.log(scope.selectedRow); if (scope.selectedRow == 0) {
return;
}
scope.selectedRow--;
scope.$apply();
e.preventDefault();
} if (e.keyCode == 40 || e.keyCode == 39) {
if (scope.selectedRow == scope.hlist.length - 1) {
return;
}
scope.selectedRow++;
scope.$apply();
e.preventDefault();
}
if (e.keyCode == 13) { var resultList = MyService.selectH(hId, $scope.hposition, myModel);
resultList.then(function (response) {
$scope.myModel= response.data;
$("#divlookup").dialog('close'); });
scope.$apply();
e.preventDefault();
}
});} };}]);
I have one function defined in $rootScope which has some value. I have created one directive to show value from there. I am not getting any value there.
<last-data-update-message type="info" update-for='stats'></last-data-update-message>
$rootScope.Helpers = {
getLastUpdateStatus: function(type) {
if (!_.isEmpty(Helpers.lastUpdateDetails)) {
if (type == 'requests') {
return Helpers.lastUpdateDetails.last_request_generated;
} else if (type == "stats") {
return Helpers.lastUpdateDetails.last_stats_executed || ((new Date()).getTime() - 2 * 60 * 60 * 1000);
} else if (type == "response") {
return Helpers.lastUpdateDetails.last_response_recieved;
} else {
return Helpers.lastUpdateDetails.last_stats_executed || ((new Date()).getTime() - 2 * 60 * 60 * 1000);
}
}
}
}
mymodule.directive('lastDataUpdateMessage', ["$rootScope", '$compile', function($rootScope, $compile) {
return {
restrict: 'AE',
replace: true,
template: function(element, attrs) {
if (element && element[0]) {
var targetElem = element[0];
console.log(attrs)
console.log("type", attrs.type)
console.log("for", attrs.updateFor);
console.log(attrs.updateFor);
return '<div class="alert alert-info fade in margin-0" style="margin-top:10px !important">' +
'<i class="fa-fw fa fa-info"></i>' +
'<strong>Information!</strong> The below report relies on data that is computed in batch. The computaitons were last updated about <span am-time-ago="$rootScope.Helpers.getLastUpdateStatus(' + attrs.updateFor + ')"></span>.' +
'</div>';
}
},
link: function(element) {
}
}
Any help will be appreciated.
Few Mistakes in your code.
1) You can't access Any angular variable in dom. :)
2) if a function defined on $rootScope or $scope, if called from dom by interpolation, then in function argument you can pass only those variable which are defined on $scope not Attrs, which is second mistake. :)
I have just little modified your code to make it work.
Please modified the return statement, based on your requirement.
Hope, I was able to answer your question. :)
app.directive('lastDataUpdateMessage', ['$rootScope', '$compile', function ($rootScope, $compile) {
return {
restrict: 'AE',
replace: true,
template: function (element, attrs) {
if (element && element[0]) {
return '<div class="alert alert-info fade in margin-0" style="margin-top:10px !important">' +
'<i class="fa-fw fa fa-info"></i>' +
'<strong>Information!</strong> The below report relies on data that is computed in batch.'+
'The computaitons were last updated about <span>{{Helpers.getLastUpdateStatus()}}</span>.' +
'</div>';
}
},
link: function (scope, element, attrs) {
scope.type = attrs.updateFor;
scope.Helpers = {
getLastUpdateStatus: function () {
if (scope.type == 'requests') {
return 'requests';
} else if (scope.type == "stats") {
return "stats Test";
} else if (scope.type == "response") {
return "response";
} else {
return "OOPS! Type is empty";
}
}
}
}
}
}])
I can move up and down with the keyboard keys but i cannot get the enter event correct
**Controller**
$scope.myFunction = function()
{
alert('sadsad');
alert('hi');
}
**Also i added directive like this**
.directive('ngEnter', function ()
{
restrict:'use strict';
return {
link: function (scope, elements, attrs) {
elements.bind('keydown keypress', function (event) {
if (event.which === 13) {
scope.$apply(function () {
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
}
};
});
**Below is the view code on which i m calling directive and function**
<tr class="find"ng-repeat="busServices in " ng-click="setSelected(busServices.bus_travel_id,this.busServices,$event)" ng-class="{selectedsd:busServices.bus_travel_id === idSelected}" ng-mouseover="ShowHideBoarding($event,this.busServices,true)" ng-mouseleave="ShowHideBoarding($event,false)" ng-init="($first) ? setSelected(busServices.bus_travel_id,this.busServices) : ''" ng-enter="myFunction()"></tr>
ng-enter doesnt get called at all.
what can i do so that ng enter can work.
Try something like this
.directive('ngEnter', function () {
return function (scope, element, attrs) {
element.bind("keypress", function (event) {
if(event.keyCode === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
The restrict option can be omitted.
EDIT: You will have to add an attribute to your <tr> so that they can be focussed and receive key* events:
<tr tabindex="0" ....>
Replace 0 with other numbers for more of your focussable <tr>
I already have this code that I came up with:
In my outer controller:
$scope.key = function ($event) {
$scope.$broadcast('key', $event.keyCode)
}
In my inner controller (I have more than one like this)
$scope.$on('key', function (e, key) {
if (key == 13) {
if (ts.test.current) {
var btn = null;
if (ts.test.userTestId) {
btn = document.getElementById('viewQuestions');
} else {
btn = document.getElementById('acquireTest');
}
$timeout(function () {
btn.focus();
btn.click();
window.setTimeout(function () {
btn.blur();
}, 500);
})
}
}
});
Is there another way that I could simplify this using some features of AngularJS that I have not included here?
Please check this gist, https://gist.github.com/EpokK/5884263
You can simply create a directive ng-enter and pass your action as paramater
app.directive('ngEnter', function() {
return function(scope, element, attrs) {
element.bind("keydown keypress", function(event) {
if(event.which === 13) {
scope.$apply(function(){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
HTML
<input ng-enter="myControllerFunction()" />
You may change the name ng-enter to something different, because ng-** is a reserved by Angular core team.
Also I see that your controller is dealing with DOM, and you should not. Move those logic to other directive or to HTML, and keep your controller lean.
if (ts.test.userTestId) {
btn = document.getElementById('viewQuestions'); //NOT in controller
} else {
btn = document.getElementById('acquireTest'); //NOT in controller
}
$timeout(function () {
btn.focus(); //NOT in controller
btn.click(); //NOT in controller
window.setTimeout(function () { // $timeout in $timeout, questionable
btn.blur(); //NOT in controller
}, 500);
})
What i've done in the past is a directive which just listens for enter key inputs and then executes a function that is provided to it similar to an ng-click. This makes the logic stay in the controller, and will allow for reuse across multiple elements.
//directive
angular.module('yourModule').directive('enterHandler', [function () {
return{
restrict:'A',
link: function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
var key = event.which ? event.which : event.keyCode;
if (key === 13) {
scope.$apply(function () {
scope.$eval(attrs.enterHandler);
});
event.preventDefault();
}
});
}
}
}]);
then your controller becomes
$scope.eventHandler = function(){
if (ts.test.current) {
var btn = ts.test.userTestId
? document.getElementById('viewQuestions')
: document.getElementById('acquireTest');
$timeout(function () {
btn.focus();
btn.click();
window.setTimeout(function () {
btn.blur();
}, 500);
})
}
}
and your markup can then be
<div enter-handler="eventHandler()" ></div>