Trying to load the RoyalSlider as a Directive. Here's my directive, which works though I'm not sure exactly why, on first load but not on subsequent loads:
app.directive('royalSlider', ['$timeout', function($timeout) {
$(".royalSlider").royalSlider({
keyboardNavEnabled: true,
arrowsNav: true,
arrowsNavHideOnTouch: true,
imageScaleMode: 'fill',
slidesSpacing: 0
});
}]);
with the error:
TypeError: Cannot read property 'compile' of undefined
Assuming the issue is loading when all content is finished, I changed it to this:
app.directive('royalSlider', ['$timeout', function($timeout) {
return {
link: function ($scope, element, attrs) {
$scope.$on('$viewContentLoaded', function () {
$(".royalSlider").royalSlider({
keyboardNavEnabled: true,
arrowsNav: true,
arrowsNavHideOnTouch: true,
imageScaleMode: 'fill',
slidesSpacing: 0
});
})
}
}
}]);
And Nothing happens. $timeout is also in there because I've tried that trick too, to no avail.
Try this
app.directive('royalSlider', ['$timeout', function($timeout) {
return {
link: function ($scope, element, attrs) {
$scope.$apply($(".royalSlider").royalSlider({
keyboardNavEnabled: true,
arrowsNav: true,
arrowsNavHideOnTouch: true,
imageScaleMode: 'fill',
slidesSpacing: 0
}));
}
}
}]);
Or
app.directive('royalSlider', ['$timeout', function($timeout) {
return {
link: function ($scope, element, attrs) {
$(".royalSlider").royalSlider({
keyboardNavEnabled: true,
arrowsNav: true,
arrowsNavHideOnTouch: true,
imageScaleMode: 'fill',
slidesSpacing: 0
});
$scope.$apply();
}
}
}]);
I already have 2 situations where directives and services/factories didn't play well.
The scenario is that I have (had) a directive that has dependency injection of a service, and from the directive I ask the service to make an ajax call (with $http).
In the end, in both cases the ng-repeat did not file at all, even when I gave the array an initial value.
I even tried to make a directive with a controller and an isolated-scope. Only when I have moved everything to a controller then it worked like magic. One of them was the royal slider.
Here is my code
app.service('AjaxService', ['$log', '$http', function ($log, $http) {
var me = this;
me.CallHttpAjaxAndMapSearch = function (url, targetObjext, propertyName, callback, splitObject) {
$http.get(url)
.success(function(data){
//etc., mapping to selectedArray
if (propertyName) {
targetObjext[propertyName] = selectedArray;
}
else {
targetObjext['selectedArray'] = selectedArray;
}
if (callback) {
callback();
}
});
};
}]);
app.service('slidersService', ['$log', '$http', 'AjaxService', function ($log, $http, AjaxService) {
var me = this;
me.initRoyalSlider = function (url, element, arrayName, sliderOptions, splitObject) {
me[arrayName] = [];
var successCallback = function slidersService_successCallback() {
setTimeout(function slidersService_successCallback_Timeout() {
$log.log('setTimeout for ' + arrayName);
element.royalSlider(sliderOptions);
}, 0);
};
AjaxService.CallHttpAjaxAndMapSearch(url, me, arrayName, successCallback, splitObject);
};
}]);
app.controller('royalSlider', function ($scope, $attrs, $log, slidersService) {
var arrName = $attrs.royalSlider;
var options = JSON.parse($attrs.royalSliderOptions);
var element = $attrs.$$element;
$scope.svc = slidersService;
slidersService.initRoyalSlider($attrs.royalSliderUrl, element, arrName, options, $attrs.splitObject);
});
And the HTML
<div class="slides royalSlider rsMinW "
ng-controller="royalSlider"
royal-slider="mainSlider"
royal-slider-options='{"loop":true,"autoPlay":{"enabled":true,"pauseOnHover":true,"delay":3000},"arrowsNav":false,"controlNavigation":"bullets"}'
royal-slider-url="/_api/search/query?bla bla">
<div ng-repeat="slide in svc.mainSlider">
Related
I want to create a table directive, I wanted to know how to pass a callback to for example: "Calling a delete function that is not in the Controller", I was wanting to pass as a callback using parameters, but for some time I am hitting my head with it. When I can return the callback through the "link" I can not return the values, and the controller can not.
Imagem when I use link , but don't back values of callback
Image when I use Controller
View DashBoard
<div crud-table options='vm.options' callback='vm.myCallBack(response)'></div>
Controller DashBoard
(function() {
'use strict';
angular
.module('senhalivre')
.controller('DashboardMikrotikCtrl', DashboardMikrotikCtrl);
DashboardMikrotikCtrl.$inject = [];
function DashboardMikrotikCtrl() {
var vm = this;
vm.myCallBack = myCallBack;
vm.options = {
enabled : true,
msg : 'DashBoard',
// Configs etc.....
}
//////////////////
function myCallBack(response){
console.log('Callback !!! ');
console.log(response);
}
}
})();
Directive
(function() {
'use strict';
angular
.module('senhalivre')
.directive('crudTable', crudTable);
crudTable.$inject = [];
function crudTable() {
var directive = {
bindToController: true,
controller: crudTableCtrl,
templateUrl : './views/crud/crudTable.html',
controllerAs: 'vm',
link: link,
restrict: 'EA',
scope: {
options : '=',
callback : '&callback'
}
};
return directive;
////////////////
function link(scope, element, attrs, ctrl) {
scope.vm.callback({test : 'something'});
// Work
}
}
crudTableCtrl.$inject = [];
function crudTableCtrl() {
var vm = this;
vm.callback({test : 'something'});
// :(
}
})();
You need to provide the property 'response' in the parameter-object when calling the callback:
function link(scope, element, attrs, ctrl) {
scope.vm.callback({response: 'some response text'});
}
or
function crudTableCtrl() {
this.callback({response: 'something'});
}
I've got a d3.js chart directive in Angular which needs to stay up to date with the latest data provided. What appears to be happening is that Angular is throwing an infinite digest error (why?) when new data is sent from my server, and I can't figure out why.
directive
(function() {
var app = angular.module('app');
app.directive('chart', ["$window", function($window) {
return {
replace: true,
restrict: 'E',
scope: {
data: '=',
settings: "="
},
link: function($scope, elem, attrs) {
$scope.$watch('data', function(newValue) {
render(newValue);
}, true);
function render(data) {
// complex d3 manipulation here
}
},
templateUrl: '/js/templates/chart.html'
}
}]);
})();
directive HTML binding
<chart class="dataplot" data="telemetryPlots.altitudeVsTime.data" settings="telemetryPlots.altitudeVsTime.settings" width="100%" height="400px"></chart>
parent controller
(function() {
var app = angular.module('app', []);
app.controller('myController', ["$scope", "myService", "telemetryPlotCreator", function($scope, myService, telemetryPlotCreator) {
(function() {
missionService.telemetry($scope.slug).then(function(response) {
$scope.telemetryPlots = {
altitudeVsTime: telemetryPlotCreator.altitudeVsTime(response.data)
}
});
})();
}]);
app.service('telemetryPlotCreator', [function() {
this.altitudeVsTime = function(telemetryCollection) {
return {
data: telemetryCollection.filter(function(telemetry) {
return telemetry.altitude != null;
}).map(function(telemetry) {
return { timestamp: telemetry.timestamp, altitude: telemetry.altitude };
}),
settings: {
extrapolate: true,
xAxisKey: 'timestamp',
xAxisTitle: 'Time (T+s)',
yAxisKey: 'altitude',
yAxisTitle: 'Altitude (km)',
chartTitle: 'Altitude vs. Time',
yAxisFormatter: function(d) {
return d / 1000;
}
}
}
};
}]);
app.service('myService', ["$http", function($http) {
// http service
}]);
})();
I'm not seeing my mistake here, as far as I can tell there's nothing that should be retriggering a digest apart from when necessary. What mistake am I making?
I have a directive as the following:
app.directive('fileInput', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind('change', function () {
$parse(attrs.fileInput)
.assign(scope, element[0].files)
scope.$apply();
});
scope.$watch('files', function () {
console.log(scope.files);
});
},
controller: function ($scope, $element, $attrs) {
$element.bind('change', function () {
$parse($attrs.fileInput)
.assign($scope, $element[0].files)
$scope.$apply();
});
$scope.$watch('files', function () {
console.log($scope.files);
});
}
}
EDIT
and this is controller:
controllers.controller('RegisterCtrl', ['$scope', '$routeParams', '$location', '$http', 'Restangular', 'ServiceRepository',
function($scope, $routeParams, $location, $http, Restangular, ServiceRepository)
{
$scope.regService = function () {
$scope.error = {};
$scope.submitted = true;
var fd = new FormData();
fd.append("model", angular.toJson($scope.services));
console.log($scope.files);
}
}
And this is view file
<input type="file" id="boarding-picture_where_sleeping" class="form-control" file-input="files" multiple>
Additional info, regService() method is called when submitting the form
and when I debug $scope.files, it's available in console tab. but in my controller, it's undefined
so how to sync it between the directive and controller
Thanks
it's working now. the problem was caused I used 2 nested directives :)
Thanks guys
I would use scope and bindToController attributes in the directive definition, like in the following snippet from this blog:
app.directive('someDirective', function () {
return {
scope: {
name: '='
},
controller: function () {
this.name = 'Pascal';
},
controllerAs: 'ctrl',
bindToController: true,
template: '<div>{{ctrl.name}}</div>'
};
});
It requires use of the controllerAs syntax too, but you should be using that anyway as it is much more clear than passing $scope around everywhere and dealing with prototypical inheritance. This is recommended in John Papa's AngularJS Style Guide
I was just reading here about accessing one directive's controller from within another directive via the require option:
http://jasonmore.net/angular-js-directives-difference-controller-link/
The directive droppable and dashboard declarations in on my view - on two different divs:
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12" data-droppable drop="handleDrop">
<div id="dash" dashboard="dashboardOptions" class="dashboard-container"></div>
</div>
</div>
However I can't seem to get it to work. My dashboardCtrl param below is NULL.
Here in my droppable directive, I use the REQUIRE option:
.directive('droppable', function () {
return {
scope: {
drop: '&',
},
//****************** dashboard directive is optionally requested ************
require: '?dashboard',
link: function (scope, element, attributes, dashboardCtrl) {
el.addEventListener('drop', function (e) {
if (e.preventDefault) { e.preventDefault(); }
this.classList.remove('over');
var item = document.getElementById(e.dataTransfer.getData('Text'));
this.appendChild(item.cloneNode(true));
// *** CALL INTO THE dashboardCtrl controller ***
dashboardCtrl.addWidgetInternal();
return false;
}, false);
}
}
});
and the dashboard directive :
angular.module('ui.dashboard')
.directive('dashboard', ['WidgetModel', 'WidgetDefCollection', '$modal', 'DashboardState', '$log', function (WidgetModel, WidgetDefCollection, $modal, DashboardState, $log) {
return {
restrict: 'A',
templateUrl: function (element, attr) {
return attr.templateUrl ? attr.templateUrl : 'app/shared/template/dashboard.html';
},
scope: true,
controller: ['$scope', '$attrs', function (scope, attrs) {
// ommitted for brevity
}],
link: function (scope) {
scope.addWidgetInternal = function (event, widgetDef) {
event.preventDefault();
scope.addWidget(widgetDef);
};
};
}
}]);
However, my dashboardCtrl parameter is NULL. Please help me to figure out how to use require.
I actually need to call the addWidget() function, which is within the link option; but I suppose I can copy or move that into the controller option.
thank you !
Bob
Here is an example of "parent" directive dashboard requiring droppable, and communication between the two making use of require and passing dashboardCtrl
Here is a good article to see directive to directive communication
Fiddle example also built from your previous question
JSFiddle
app.directive('droppable', [function () {
return {
restrict: 'A',
require: 'dashboard',
link: function (scope, elem, attrs, dashboardCtrl) {
dashboardCtrl.controllerSpecificFunction('hello from child directive!');
scope.addWidgetInternal = function(message) {
console.log(message);
}
}
}
}]);
app.directive('dashboard', [function () {
return {
restrict: 'A',
controller: function ($scope) {
$scope.handleDrop = function(message) {
$scope.addWidgetInternal(message)
}
this.controllerSpecificFunction = function(message) {
console.log(message);
}
}
}
}]);
Edit
Based on discussion, here is a solution for what I currently understand the problem to be
Parent directive dashboard optionally requires child directive droppable and there needs to be communication between the two
<div dashboard>
<button id="dash" droppable ng-click="handleDrop($event)">Handle Drop</button>
</div>
app.directive('droppable', [function () {
return {
restrict: 'A',
require: '^?dashboard',
link: function (scope, elem, attrs, dashboardCtrl) {
scope.handleDrop = function($event) {
dashboardCtrl.addWidgetInternal($event);
}
}
}
}]);
app.directive('dashboard', [function () {
return {
restrict: 'A',
controller: function ($scope) {
this.addWidgetInternal = function($event) {
console.log($event);
}
}
}
}]);
Updated JSFiddle
I'm quite new to AngularJS and I'm trying to understand a few things.
First of all, I have my controller of which I will place a snippet here:
var OfficeUIRibbon = angular.module('OfficeUIRibbon');
// Defines the OfficeUIRibbon controller for the application.
OfficeUIRibbon.controller('OfficeUIRibbon', ['$scope', '$http', function($scope, $http) {
var ribbon = this;
ribbon.setApplicationMenuAsActive = function() {
ribbon.applicationMenuActive = true;
}
}
Then I have a directive:
var OfficeUIRibbon = angular.module('OfficeUIRibbon');
OfficeUIRibbon.directive('ribbonApplicationMenu', function() {
return {
restrict: 'E',
replace: false,
scope: {
data: '#'
},
templateUrl: function(element, attributes) {
return attributes.templateurl;
}
}
});
The directive is called like this:
<ribbon-application-menu templateUrl="/OfficeUI.Beta/Resources/Templates/ApplicationMenu.html" data="/OfficeUI.Beta/Resources/JSon/Ribbon/ribbon.json"></ribbon-application-menu>
This does all work and in my template for the directive, the following is placed:
<div id="application" id="applicationMenuHolder" ng-controller="OfficeUIRibbon as OfficeUIRibbon" ng-show="OfficeUIRibbon.applicationMenuActive"...
From inside another element, when I execute a click a function on my controller is executed:
ng-click="OfficeUIRibbon.setApplicationMenuAsActive()"
Here's the directive from the other element:
OfficeUIRibbon.directive('ribbon', function() {
return {
restrict: 'E',
replace: false,
scope: {
data: '#'
},
templateUrl: function(element, attributes) {
return attributes.templateurl;
}
}
});
This function does change the property "applicationMenuActive" on the ribbon itself, which should make the item in the directive template show up.
However, this is not working. I'm guessing I need to watch this property so the view get's updated accordingly.
Anyone has an idea on how this could be done?