AngularJS - Add attribute at runtime - angularjs

I'm working on an AngularJS app. I'm trying to add the autofocus attribute to an element at runtime. The reason I want to do this is so I can set this attribute on one of several elements. How do you add an HTML attribute to an element via an AngularJS directive?
Thank you!

You can use the $set method on the $compile.directive.Attributes object. See the documentation here. This will create a new attribute which AngularJS will recognize. Remember to use the normalized (camelCase) version of the attribute. You can do it in the link function of your directive.

That's directive:
(function(){
angular.module('ng').directive('dynamicAutoFocus', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
scope.$watch(attrs.dynamicAutoFocus, function(id){
if(angular.isDefined(id)){
var target = document.getElementById(id);
if(target){
target.focus();
}
}
});
}
};
});
})();
Plunker

Related

Dynamically add angular attributes to an element from a directive

I'm trying to build a directive that change loading status on buttons for slow ajax calls. Basically the idea is to set an attribute "ng-loading" to a button element, and let the directive add the rest of stuff.
This is the html code:
<button class="btn btn-primary" name="commit" type="submit" ng-loading="signupLoading">
Submit
</button>
And this is the directive code:
.directive('ngLoading', ['$compile', function($compile) {
return {
restrict: 'A',
replace: false,
terminal: true,
link: function(scope, element, attrs) {
element.attr('ng-class', '{loading:' + attrs['ngLoading'] +'}');
element.attr('ng-disabled', attrs['ngLoading']);
element.append(angular.element('<img class="loading-icon" src="/assets/images/loading-icon.gif"/>'));
$compile(element.contents())(scope);
}
};
}]);
It all looks correct in the rendered HTML, but the attributes added from the directive is not funcioning at all. I can move those attributes to the HTML code and everything works great, but that's quite some redundant code in many places.
I referenced the post Angular directive to dynamically set attribute(s) on existing DOM elements but it does not solve my problem.
Any comment/suggestion are welcome. Thanks in advance.
You don't need to recompile that directive if all you want is some DOM manipulation, you can add and remove class in regards to the changes of a scope property. You can use $watch instead.
JAVASCRIPT
.directive('ngLoading', function() {
return function(scope, element, attrs) {
var img = angular.element('<img class="loading-icon" src="/assets/images/loading-icon.gif"/>');
element.append(img);
scope.$watch(attrs.ngLoading, function(isLoading) {
if(isLoading) {
img.removeClass('ng-hide');
element.addClass('loading');
element.attr('disabled', '');
} else {
img.addClass('ng-hide');
element.removeClass('loading');
element.removeAttr('disabled');
}
});
};
});
Note: Your code doesn't work because it compiles the contents of the elements, not the element itself, where you attach the attributes you have implemented.
try $compile(elem)(scope); and it should work properly, but I don't recommend it because each element with such directive will have to re-compile again.
UPDATE:
before using $compile remove the attribute 'ngLoading' to the element to prevent infinite compilation.
elem.removeAttr('ng-loading');
$compile(elem)(scope);

Selectize & AngularJS not playing along with Select box (Multiple options)

I've been trying to implement Selectize with AngularJS (1.2.4). I'm using this directive to interface with the plugin and everything is working smoothly until now. When using the ngModel from a normal select box It works fine, and returns the expected object but when I try to use it with the multiple attribute, it won't set the model.
I've inspected the DOM and appears the script removes unselected options from the hidden select and that might be messing with the angular binding.
I've created a Plunkr to demonstrate the behaviour.
http://plnkr.co/It6C2EPFHTMWOifoYEYA
Thanks
As mentioned in the comments above, your directive must listen to changes in the selectize plugin and then inform angular of what happened via ng-model.
First, your directive needs to ask for an optional reference to the ngModel controller with the following:
require: '?ngModel'.
It is injected into your link function as an argument in the 4th position:
function(scope,element,attrs,ngModel){}
Then, you must listen for changes in selectize with
$(element).selectize().on('change',callback)
and inform ngModel with ngModel.$setViewValue(value)
Here is a modified version of your directive. It should get you started.
angular.module('angular-selectize').directive('selectize', function($timeout) {
return {
// Restrict it to be an attribute in this case
restrict: 'A',
// optionally hook-in to ngModel's API
require: '?ngModel',
// responsible for registering DOM listeners as well as updating the DOM
link: function(scope, element, attrs, ngModel) {
var $element;
$timeout(function() {
$element = $(element).selectize(scope.$eval(attrs.selectize));
if(!ngModel){ return; }//below this we interact with ngModel's controller
//update ngModel when selectize changes
$(element).selectize().on('change',function(){
scope.$apply(function(){
var newValue = $(element).selectize().val();
console.log('change:',newValue);
ngModel.$setViewValue(newValue);
});
});
});
}
};
});
Also:
plunker
angular docs for ngModelController

Angular Directive Passing Template Name in as an attribute

if I wanted to pass into angular an attribute which is a template name stored on the templateCache, would doing something like the following be a good approach?
app.directive('myPopup', function() {
var directive = {
link: link,
scope {
'template': '#'
}
template: $templateCache.get(template);
restrict: 'E'
};
return directive;
function link(scope, element, attrs) {
}
});
Or should it be done on the compile statement, I guess so for performace??
I'm looking to ultimately wrap a bootstrap popover and then be able to provided html content through a template attribute allowing me to reuse popovers by providing different templates.
Can anyone offer any suggestions for the best course of action?
Thanks

How to use addClass method in angularjs

I have an angularjs directive restricted to class. How can I add this by using addClass method in angularjs
directive
app.directive('number', function() {
return {
restrict: 'C',
link: function () {
}
};
});
code
<div id="test"></div>
I know it is possible by using jQuery like the following.
$( "#test" ).addClass( "number" );
Please help me in doing it by using angularjs
You don't need to use .addClass() angular provide ng-class directive to add class conditionally.
ng-class="{number:[condition]}"
it will add class number whenever your condition return true
yes but your directive will not be used by this I misunderstood your question previously.
You should add ng-class="yourClass" to element on view and add in your controller
$scope.yourClass = "your-new-class", not in directive
try this
link: function (lEmel) {
lElem.addClass("Foo");
}

AngularJS: accessing the ngTouch service from a directive?

I really love how the new ng-click directive in Angular now automatically includes functionality for touch events. However, I am wondering if it is possible to access that touch-event service from my custom directive? I have lots of directives that require that I bind a click event to the given element, but I'm simply doing that using the typical jquery syntax (ex: element.on('click', function(){ ... })). Is there a way that I can bind an ng-click event to an element within a directive? Without having to manually put a ng-click tag on my element in the HTML of my view...?
I want to be able to harness the power of both click and touch events. I could obviously import a library (such as HammerJS or QuoJS) but I would prefer not to have to do that, especially since Angular is already doing it.
I can access the $swipe service and bind different elements to that, but is there a similar service for ngTouch?
For reference, this is an example of when I would want to do this:
mod.directive('datepicker', ['$timeout', function($timeout){
return {
link: function(scope, elem, attrs){
var picker = new DatePicker();
elem.on('click', function(e){
picker.show();
});
// I would rather do something like:
// elem.on('ngTouch', function(){ ... });
//
// or even:
// $ngTouch.bind(elem, {'click': ..., 'touch': ...});
}
}
}]);
UPDATE: As noted by below, the source code for the ng-click directive is here. Can anyone see a way to harness that code and turn it into a "bindable" service?
I don't think that's quite the right approach. I'd approach this by using a template within your directive and then using ngTouch within that.
mod.directive('datepicker', ['$timeout', function ($timeout) {
return {
template: '<div ng-touch="doSomethingUseful()"></div>',
link: function (scope, elem, attrs) {
var picker = new DatePicker();
scope.doSomethingUseful = function () {
// Your code.
}
}
}
}]);
UPDATE
Full example with additional attributes on the directive element:
http://codepen.io/ed_conolly/pen/qJDcr

Resources