Angular directive does not work if we change name - angularjs

I am seeing a strange behaviour when using angular directive.
In the code below
HTML
<body ng-app="loadTweetsModule">
<div tweets> Load </div>
<div loadTweets> loadTweets </div>
</body>
Javascript
var loadTweetsModule = angular.module("loadTweetsModule",[]);
loadTweetsModule.directive('tweets',function(){
return {
link : function(scope,element){
element.bind("mouseenter", function(){
console.log("tweets");
});
}
};
});
loadTweetsModule.directive('loadTweets',function(){
return {
link : function(scope,element){
element.bind("mouseenter", function(){
console.log("loadTweets");
});
}
};
});
JSFiddle Link
The two directive loadTweets and tweets are the same except for the name. The directive tweets works as expected but loadTweets does not work. I am not able to find out the reason for this behaviour. Can somebody explain this?

if you write in js loadTweets you should write in html load-tweets
from http://docs.angularjs.org/guide/directive
Directives have camel cased names such as ngBind. The directive can be
invoked by translating the camel case name into snake case with these
special characters :, -, or _. Optionally the directive can be
prefixed with x-, or data- to make it HTML validator compliant. Here
is a list of some of the possible directive names: ng:bind, ng-bind,
ng_bind, x-ng-bind and data-ng-bind.

Related

Directive inside a angular-translate translation

I'm using angular-translate for i18n and want to use a directive inside a translation:
var translations = {
TEST_1: 'Hello from Test',
TEST_2: 'Hello from <user></user>'
};
app.directive('user', function() {
return {
template: 'Test'
};
});
Full plnkr example: http://plnkr.co/edit/jCCcvx7IEaAYUwyaQ7uH?p=preview
So
<p translate="TEST_1"></p>
<p translate="TEST_2"></p>
should be the same. The first (without directive) works, the second doesn't. It transcludes <user></user>, but Angular doesn't seem to be aware of it and doesn't do its directive magic.
Try to use the translate-compile directive:
<p translate="TEST_2" translate-compile></p>
From the docs:
Starting with version 2, the translation itself can be post processed
in context of the current scope (using $compile). This means any
directive used in a translation value itself will now work as
expected.

angularjs-- declenching events

Please, how can I change this code into angularJs
$('a.product_add').on('click', function(event){
event.preventDefault();
var collectionHolder = $('#task_tags');
var prototype = collectionHolder.attr('data-prototype');
form = prototype.replace(/__name__/g, collectionHolder.children().length);
collectionHolder.append(form);
});
First of all you need to show us what you've tried, but I'll write something here to help you
You should make a directive because you're using jquery code. Read more about directives here
AngularJS directives are extended HTML attributes with the prefix ng-.
The ng-app directive initializes an AngularJS application.
The ng-init directive initializes application data.
The ng-model directive binds the value of HTML controls (input,
select, textarea) to application data.
Example of a directive
app.directive('myDirective', function(){
function link($scope,$elem,$attrs){
$elem.on('click', function(event){
// click event code here
});
}
return {
link:link,
scope:{},
restrict:'A'
}
})
Example of usage for myDirective:
<a class='product_add' my-directive>link</a>
We can use angular custom directives.
Now you can access the element in the directive and do the same operations in the directive.
<directive-element ng-click=appendFunction()></directive-element>

ng-bind-html strips elements attributes

I'm trying to interpolate a string that contains some markup in a template.
In the controller:
$scope.message = "Hello moto <a ui-sref='home.test'>click</a>";
Template:
<div ng-bind-html="message.text"></div>
which renders as:
<div ng-bind-html="message.text" <div="" class="ng-binding">Hello moto <a>click</a></div>
Trying to use the following filter does not help either; the text is simpy escaped for either of the commented choices:
angular.module('test-filters', ['ngSanitize'])
.filter('safe', function($sce) {
return function(val) {
return $sce.trustAsHtml(val);
//return $sce.trustAsUrl(val);
//return $sce.trustAsResourceUrl(val);
};
});
How can I interpolate my string without escaping it nor stripping attributes?
Edit: Plunker http://plnkr.co/edit/H4O16KgS0mWtpGRvW1Es?p=preview (updated with sylwester's version that has reference to ngSanitize
Let have a look here http://jsbin.com/faxopipe/1/edit it is sorted now.
It didn't work because there was another directive inside a tag 'ui-sref',
so you have to use $sce service.
in your js please add method:
$scope.to_trusted = function(html_code) {
return $sce.trustAsHtml(html_code);
and in view :
<p ng-bind-html="to_trusted(message)"></p>
In scenario where you are using ui.router path you must need to use $compile in combination with $sce for your dynamic html so that ui-sref work properly. If you don't do that you'll just see a Link which actually do not work.
e.g <span> Hello moto <a ui-sref='home.test'> Link </a> </span>
//You must need to add boundary conditions, this is just for demonstration
$scope.to_trusted = function(someHTML) {
var compiledVal = $compile(someHTML)($scope);
var compiledHTML = compiledVal[0].outerHTML;
return $sce.trustAsHtml(compiledHTML);
}
And you use like this,
<p ng-bind-html="to_trusted(message)"></p>
Note that your message has to be a valid HTML starting from "<" so if you pass a non HTML to $compile you'll get jqlite error. I used <span> to handle your case.
You missed reference to angular-sanitize.js and you have inject it as well to angular.app
var app = angular.module('plunker', ['ngSanitize']);
the simplest option in to bind html is ng-bind-html :
<li>link ng-html-bind <div ng-bind-html="message"></div></li>
please see Plunkr

How to show html in angularjs template instead of string?

I have a variable in my scope:
$scope.myvar = "Hello<br><br>World"
In my template I use:
<div>{{myvar}}</div>
The issue is myvar shows the literal text, whereas I want it to show the line breaks. How to do this? Note that I want to make it such that if I in the future, myvar gets updated with other HTML, then what is shown on the page should be the "compiled" html as opposed to the literal string with the html tags in it.
You can use ngBindHtml for that.
Keep in mind that due to Angular's Strict Conceptual Escaping the content needs to be either sanitized (using the additonal module ngSanitize) or explicitely "trustedAsHtml" (using $sce.trustAsHtml()). The latter is supposed to be used only for content you know is safe (e.g. nothing user defined) and is not recommended anyway.
Note: ngSanitize is an non-core module and should be included separately:
<script src=".../angular.min.js"></script>
<script src=".../angular-sanitize.min.js"></script>
Examples:
/* Using ngSanitize */
angular.module('app', ['ngSanitize'])
.controller('myCtrl', function ($scope) {
$scope.myHtml = 'Hello<br /><br />world !';
});
/* Using $sce.trustAsHtml() */
angular.module('app', [])
.controller('myCtrl', function ($sce, $scope) {
$scope.myHtml = $sce.trustAsHtml('Hello<br /><br />world !');
});
Note that ngSanitize will filter "non-appropriate" content, while $sce.trustAsHtml will allow anything.
See, also, this short demo.
Use ng-bind-html within <div>. Here is the example:
In your html file :
<div ng-controller="ngBindHtmlCtrl">
<div ng-bind-html="myvar"></div>
</div>
In your js:
angular.module('ngBindHtmlExample', ['ngSanitize'])
.controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
$scope.myvar = 'Hello<br><br>World';
}]);
Example taken from AngularJs doc.
You can use ng-bind-html to bind to HTML directly. Here's the official documentation
#ExpertSystem is correct or if you're lazy like me you could do:
lrApp.directive('bindHtml', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
scope.$watch(attrs.bindHtml,function(nv,ov){
elem.html(nv);
});
}
};
});
1) Add the angular-sanitize.js library. This functionality used to be a part of the main library, but the Angular team has been splitting off sections to make it more modular.
2) Use the ng-bind-html tag:
<p ng-bind-html="myvar">

How can I generate on the fly directives in AngularJS?

I want to be able to take an array of strings, and then create directives based upon those strings. Either element or attribute will work fine but can't seem to get it working.
<div ng-repeat="module in modules.directives">
<div {{module.directive}}></div>
</div>
<div ng-repeat="module in modules.directives">
<{{module.directive}}></{{module.directive}}>
</div>
<div ng-repeat="module in modules.directives">
<{{module.directive}} />
</div>
Can't get any of these to work. Any ideas?
You could define a directive that would proxy another directive like so
<div proxy="'ng-if'" proxy-value="'foo'"></div>
<div ng-init="n='ng-if'; v='foo';" proxy="n" proxy-value="v"></div>
that would both be equivalent to
<div ng-if="foo"></div>
the proxy directive definition would be
app.directive('proxy', function ($parse, $injector) {
return function (scope, element, attrs) {
var nameGetter = $parse(attrs.proxy);
var name = nameGetter(scope);
var value = undefined;
if (attrs.proxyValue) {
var valueGetter = $parse(attrs.proxyValue);
value = valueGetter(scope);
}
var directive = $injector.get(name + 'Directive')[0];
if (value !== undefined) {
attrs[name] = value;
}
return directive.compile(element, attrs, null)(scope, element, attrs);
};
});
This is actually kind of a fun directive to write once in a life. :-) but it lacks a lot of the native directive features (for instance template, templateUrl, controller, etc). All those features are available in the original Angular source code in a private function called applyDirectivesToNode, so it is easy to copy/paste some parts, but ugly... I have written a demo matching your usecase here.
Another solution, if you don't mind your proxied directive does not share the same element as the proxy directive's one, would be to $compile a dynamic template at runtime that you would include. Here is a demo.
ng-include can help you. The approach would be to define a template for each of the directives. Something like this
<script type="text/ng-template" class="template" id="test-module">
<test-module></test-module>
</script>
Then in ng-repeat do
<div ng-repeat="module in modules.directives">
<ng-include src="module.directive">
</div
If the template id matches with module.directive that directive would get rendered.

Resources