I'm trying to compile directive via angular service but unfortunately it doesn't work.
The idea is to show errors in popups.
I've modified $exceptionHandler service:
crm.factory('$exceptionHandler', function(popup) {
return function(exception) {
popup.open({message: exception});
}
});
The popup service looks like this:
crm.factory('popup', function ($document) {
return {
open: function (data) {
var injector = angular.element(document).injector(),
$compile = injector.get('$compile'),
template = angular.element('<popup></popup>');
// var ctmp = $compile(template.contents());
$compile(template.contents());
$document.find('body').append(template);
}
};
});
And I don't think that this was a good idea to hard code $compile service (but I haven't any ideas how to realize this in angular):
$compile = injector.get('$compile')
Popup directive:
crm.directive('popup', function () {
return {
restrict: 'E',
replace: true,
templateUrl: '/public/js/templates/common/popup.html',
link: function() {
console.log('link()');
},
controller: function () {
console.log('ctrl()');
}
};
});
May be there are some other ways to do this?
Thanks.
You can inject $compile directly into your service, also you're not quite using $compile correctly:
//commented alternative lines for allowing injection and minification since reflection on the minified code won't work
//crm.factory('popup', ['$document', '$compile', function ($document, $compile) {
crm.factory('popup', function ($document, $compile) {
return {
open: function (data) {
var template = angular.element('<popup></popup>'),
compiled = $compile(template);
$document.find('body').append(compiled);
}
};
});
//closing bracket for alternative definition that allows minification
//}]);
Related
I have a directive for users to like (or "fave") posts in my application. Throughout my controllers I use $rootScope.$emit('name-of-function', some-id) to update user data when they like a new post, as this is reflected throughout my application. But I can't seem to use $rootScope.$emit in the directive. I receive an error
$rootScope.$emit is not a function
Presumably the $rootScope.$on event which corresponds with this command has not been called yet, so this function does not yet exist? What can be done about this? Is there a better way to arrange this?
var module = angular.module('directives.module');
module.directive('postFave', function (contentService, $rootScope) {
return {
restrict: 'E',
templateUrl: 'directives/post-fave.html',
scope: {
contentId: '#',
slug: '#'
},
link: function ($scope, $rootScope, element) {
$scope.contentFavToggle = function (ev) {
contentId = $scope.contentId;
contentService.contentFavToggle(contentId, ev).then(function (response) {
$rootScope.$emit('dataUpdated', $scope.slug);
if (response) {
$scope.favourite[contentId] = response;
} else {
$scope.favourite[contentId] = null;
}
});
};
console.log("track fave directive called");
}
};
});
from controller:
var dataUpdatedListener = $rootScope.$on('dataUpdated', function (event, slug) {
dataService.clearData(slug);
dataControllerInit();
});
How can I access this rootscope function from within the directive? Thanks.
FYI - "link" has been used in the directive because this is related to an instance of an HTML element which will be used a number of times on the page
link has the following signature, there is no need to add $rootScope injection into link function:
function link(scope, element, attrs, controller, transcludeFn) { ... }
Remove it from link and it will work.
I will explain what exactly I'm trying to do before explaining the issue. I have a Directive which holds a form, and I need to access that form from the parent element (where the Directive is used) when clicking on a submit button to check fi the form is valid.
To do this, I am trying to use $scope.$parent[$attrs.directiveName] = this; and then binding some methods to the the Directive such as this.isValid which will be exposed and executable in the parent.
This works fine when running locally, but when minifying and building my code (Yeoman angular-fullstack) I will get an error for aProvider being unknown which I traced back to a $scopeProvider error in the Controller.
I've had similar issues in the past, and my first thought was that I need to specifically say $inject for $scope so that the name isn't lost. But alas.....no luck.
Is something glaringly obvious that I am doing wrong?
Any help appreciated.
(function() {
'use strict';
angular
.module('myApp')
.directive('formDirective', formDirective);
function formDirective() {
var directive = {
templateUrl: 'path/to/template.html',
restrict: 'EA',
scope: {
user: '='
},
controller: controller
};
return directive;
controller.$inject = ['$scope', '$attrs', 'myService'];
function controller($scope, $attrs, myService) {
$scope.myService = myService;
// Exposes the Directive Controller on the parent Scope with name Directive's name
$scope.$parent[$attrs.directiveName] = this;
this.isValid = function() {
return $scope.myForm.$valid;
};
this.setDirty = function() {
Object.keys($scope.myForm).forEach(function(key) {
if (!key.match(/\$/)) {
$scope.myForm[key].$setDirty();
$scope.myForm[key].$setTouched();
}
});
$scope.myForm.$setDirty();
};
}
}
})();
Change the directive to a component and implement a clear interface.
Parent Container (parent.html):
<form-component some-input="importantInfo" on-update="someFunction(data)">
</form-component>
Parent controller (parent.js):
//...
$scope.importantInfo = {data: 'data...'};
$scope.someFunction = function (data) {
//do stuff with the data
}
//..
form-component.js:
angular.module('app')
.component('formComponent', {
template:'<template-etc>',
controller: Controller,
controllerAs: 'ctrl',
bindings: {
onUpdate: '&',
someInput: '<'
}
});
function Controller() {
var ctrl = this;
ctrl.someFormThing = function (value) {
ctrl.onUpdate({data: value})
}
}
So if an event in your form triggers the function ctrl.someFormThing(data). This can be passed up to the parent by calling ctrl.onUpdate().
I am trying to inject services to the below directive which is used link function instead of controller.
(function() {
angular
.module("myApp")
.directive('myDirective',['$scope','myService','myData',function($scope,myService,myData) {
return {
restrict'AE',
replace:'true',
templateUrl :'/myApp/directive/my-directive',
scope: {
userId: "#"
}
},
link:function(scope,elem,attr)
{
//Code for link function goes here ...
scope.myUsersArray [];
scope.getUserDetails = function()
{
//code for getUserdetails goes here...
}
}
}]);
})();
When i run this code, i am getting exception like [$injector:unpr] Unkown Provider <_ $scope error. If i remove the injected services, i am not getting any error. Error throws at angular.js file so i don't have any clue to fix it :(
You have several syntax issues. Your code should look like this:
.directive('myDirective', ['$scope', 'myService', 'myData', function($scope, myService, myData) {
return {
restrict: 'AE',
replace: 'true',
templateUrl: '/myApp/directive/my-directive',
scope: {
userId: "#"
},
link: function(scope, elem, attr) {
//Code for link function goes here ...
scope.myUsersArray = [];
scope.getUserDetails = function() {
//code for getUserdetails goes here...
};
}
};
}]);
You may have more problems as its not evident as to why you are injecting $scope, myService, and myData
I have my JavaScript with Angularjs like this :
...
var propertiesModule = angular.module('xxx.properties', []);
propertiesModule.controller('PropertiesCtrl', ['$scope', '$routeParams', 'PropertiesService', 'ApplicationService', 'PlatformService', 'Page', function ($scope, $routeParams, PropertiesService, ApplicationService, PlatformService, Page) {
...
}]);
I want to call a jQuery functionality like this
...
$("input[type=button]").click(function () {
$("#wrapper tr").prettyTextDiff({
cleanup: $("#cleanup").is(":checked")
});
});
...
I put in end of my file but the functionality is not executed, why?
use directives for handling dom. and angular has its own methods for handling dom, using jquery is a bad idea. here is some code to help
app.directive('myDomDirective', function () {
return {
link: function ($scope, element, attrs) {
element.bind('click', function () {
element.html('You clicked me!');
// do your stuff
});
}
};
});
and a link to help you learn
angular directives
I am rather new to angular, and trying to integrate it with google earth's javascript API.
I have done some work with on both, but never try to use them together. My motivation is to use the google earth module in an angular fashion, with controllers etc to manipulate the map.
http://www.ng-newsletter.com/posts/d3-on-angular.html
I want the google module to be available as with the d3 module in the link above, through a factory that loads the script. Then be able use the google module when the script is loaded.
I have gotten this to work with the d3 module:
angular.module('d3', [])
.factory('d3Service', ['$document', '$window', '$q', '$rootScope',
function($document, $window, $q, $rootScope) {
var d = $q.defer(),
d3service = {
d3: function() { return d.promise; }
};
function onScriptLoad() {
// Load client in the browser
$rootScope.$apply(function() { d.resolve($window.d3); });
}
var scriptTag = $document[0].createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.async = true;
scriptTag.src = 'http://d3js.org/d3.v3.min.js';
scriptTag.onreadystatechange = function () {
if (this.readyState == 'complete') onScriptLoad();
}
scriptTag.onload = onScriptLoad;
var s = $document[0].getElementsByTagName('body')[0];
s.appendChild(scriptTag);
return {
d3: function(){ return d.promise; }
};
}]);
Which then is available through directives:
.directive('d3Bars', ['$window', '$timeout', 'd3Service',
function($window, $timeout, d3Service) {
return {
restrict: 'A',
scope: {
data: '=',
label: '#',
onClick: '&'
},
link: function(scope, ele, attrs) {
d3Service.d3().then(function(d3) {
//code...
}}
}]);
I have tried to rewrite this to load the google loader JS module https://developers.google.com/loader/:
and then replacing "d3" with "google". and ofc the scripTag.src variable. Should this be correct?
function onScriptLoad() {
// Load client in the browser
$rootScope.$apply(function() { d.resolve($window.google); });
}
I then have a simple directive where I want to use the google JS object to load the earth api.
the "getApi"-module is similar to "d3service" in the d3 factory above.
.directive('mapFrame' ['$window', '$timeout', 'getApi',
function($window, $timeout, getApi) {
return {
restrict: 'E',
scope: {},
link: function(scope, elements, attrs) {
getApi.google().then(function(google) {
console.log(google);
google.load("earth", "1");
//more code..
});
}
}
}])
in the html-file:
<div map-frame></div>
This way of doing it works with d3. I loads the script into the DOM, and can display some charts, which doesn't seem to happen with the google module. Looks like the directive never invokes the factory, since the javascript is never loaded into the DOM..
What is it that I'am missing, or isn't it even possible ?
Thanks!