AngularJS ng-attr- is not working - angularjs

I need to set multiple attribute for select tag dynamically.
According to this documentation:
https://www.thinkingmedia.ca/2015/03/conditionally-add-a-html-element-attribute-value-in-angularjs/#using-the-ngattr
This should work:
<select ng-attr-multiple="param.MultiValue">
and become
<select multiple>
if param.MultiValue evaluates to true, otherwise - without multiple attribute.
Doesn't work, I get select tag without multiple attribute regardless.
Even if I use
<select ng-attr-multiple="true">
Any idea why?
Thanks.

Web browsers are sometimes picky about what values they consider valid for attributes. ng-attr is for binding arbitrary attributes, select does not "know" that ng-attr-multiple is trying to set the multiple attribute, it just reacts on multiple directly.
Instead I would suggest you to write a wrapper directive which will add the multiple attribute to your element.
For more information on this see this documentation link:
https://docs.angularjs.org/guide/interpolation
Issue link:
https://github.com/angular/angular.js/issues/13570
var mymodule = angular.module('myApp', []);
function sampleController($scope, $timeout) {
$scope.addAttribute = true;
}
mymodule.controller('sampleController', sampleController)
.directive('multipleAttr', function() {
return {
'restrict': 'A',
'compile': function() {
return {
'pre': function($s, $el, attrs) {
if (attrs.multipleAttr === 'true' || attrs.multipleAttr === true) {
$el.attr('multiple', true);
}
}
}
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="sampleController">
<select multiple-attr="{{addAttribute}}">
<option>Hi</option>
<option>Hello</option>
<option>Hey</option>
</select>
</div>
</div>

Related

Angular 2 way binding doesn't work with template even though I'm not using primatives

I can't figure out what's wrong with my code. I'm following the example of this fiddle in order to bind the two inputs. What I'm trying to do is just a little more involved- I'd like to load a certain template based on an attribute passed into the directive. I can't figure out what's wrong over here.
This is my html
<!-- template -->
<script type="text/ng-template" id="X-template.html">
<button ng-click='clickMe()'><b>Check model</b></button>
Directive: <input ng-model="this.test"></input>
</script>
<div ng-controller="MyCtrl">
<my-directive type="X"></my-directive>
No Directive:<input ng-model="this.test"></input>
{{this.test}}
</div>
And my JS:
var app = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.this= {test : "asdf"};
$scope.clickMe = function() {
alert($scope.this.test);
}
}
app.directive('myDirective', function() {
return {
restrict: 'E',
compile: function(element, attrs) {
element.append('<div ng-include="\'' + attrs.type + '-template.html\'"></div>');
}
}
});
The issue is with trying to use this, which is a reserved keyword in JavaScript, as a property name.
Try using a different property name. I changed your example to use foo in the link below.
http://jsfiddle.net/01h3ne4y/

How can I use ng-repeat to generate custom html tags or directive?

I am trying to create some custom tag using angularjs with ng-repeat but its not working, its giving tag name in double quotation marks.
Good result is: shouldn't show <div> or another tags.
I have a demo version here : http://plnkr.co/edit/aT2UjMIGGLvnCGFxXC3a?p=preview
or you can use code snippet
my code is:
angular.module('myApp', [])
.controller('MainCtrl', function($scope) {
$scope.items = [
{
"name":"directive1"
},
{
"name":"directive2"
},
{
"name":"div"
}
];
})
.directive("showitems", function(){
return {
restrict: "E",
template: '<div class="item" ng-repeat="item in items"><div class="item-title">{{item.name}}</div><div class="item-body"><{{item.name}}></{{item.name}}></div></div>'
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MainCtrl">
<showitems></showitems>
</div>
AFAIK, doing something like <{{item.name}}></{{item.name}}> will never work in angular since the markups aren't treated as new DOM elements. A much better, and more manageable approach is to write directives for all possible types you'd want to render as DOM elements.
Also, to know more about DOM manipulations from within a directive, read up about $compile: here
An alternate way of doing this would be something like this in your directive template:
<directive1 ng-if="directiveType == 'directive1'"></directive1>
<directive2 ng-if="directiveType == 'directive1'"></directive2>
<directive3 ng-if="directiveType == 'directive1'"></directive3>
And in your controller/directive, you must declare directiveType to the type of directive you want to render.
Instead of wrapping {{item.name}} into its own tag, make a customTag directive. This can take a string (the tag name) and create and compile an element with it.
.directive("customTag", function ($compile) {
return {
restrict: "A",
link: function (scope, element, attrs) {
//pass customTag in as part of the directive attribute
var customTag = attrs.customTag;
if (!customTag) return;
var customElem = angular.element("<" + customTag + "></" + customTag + ">");
//replace your custom element directive with the compiled one
element.replaceWith($compile(customElem)(scope));
}
}
}
Then in your template.html:
<div class="item" ng-repeat="item in items">
<div class="item-title">{{item.name}}</div>
<div class="item-body">
<!-- This will use customTag directive to create element item.name -->
<div data-custom-tag="{{item.name}}"></div>
</div>
</div>
A div tag (or any non-directive) wouldn't be too useful because it doesn't get any innerHTML or behavior like directive1 and directive2 would get. This of course is a simple example, you may want to put some more checks or restrictions in there, but this should get you started.
See fiddle here that builds on your example.

How to use a dynamic value with ngClass

I'm trying to apply a class name that's the same as a scope variable.
For example:
<div ng-class="{item.name : item.name}">
So that the value of item.name is added to the class. This doesn't seem to do anything though. Any suggestions on how to do this?
Thanks!
EDIT:
This is actually being done within a select, using ng-options. For example:
<select ng-options="c.code as c.name for c in countries"></select>
Now, I want to apply a class name that has the value of c.code
I found the following directive, which seems to work, but not with interpolation of the value:
angular.module('directives.app').directive('optionsClass', ['$parse', function ($parse) {
'use strict';
return {
require: 'select',
link: function(scope, elem, attrs, ngSelect) {
// get the source for the items array that populates the select.
var optionsSourceStr = attrs.ngOptions.split(' ').pop(),
// use $parse to get a function from the options-class attribute
// that you can use to evaluate later.
getOptionsClass = $parse(attrs.optionsClass);
scope.$watch(optionsSourceStr, function(items) {
// when the options source changes loop through its items.
angular.forEach(items, function(item, index) {
// evaluate against the item to get a mapping object for
// for your classes.
var classes = getOptionsClass(item),
// also get the option you're going to need. This can be found
// by looking for the option with the appropriate index in the
// value attribute.
option = elem.find('option[value=' + index + ']');
// now loop through the key/value pairs in the mapping object
// and apply the classes that evaluated to be truthy.
angular.forEach(classes, function(add, className) {
if(add) {
angular.element(option).addClass(className);
}
});
});
});
}
};
}]);
Better later than never.
<div ng-class="{'{{item.name}}' : item.condition}">
yes. ' and {{ for classname.
I'm on angular 1.5.5 and none of these solutions worked for me.
It is possible to use the array and map syntax at once though it's only shown in the last example here
<div ng-class="[item.name, {'other-name' : item.condition}]">
Simply using the variable should be sufficient:
<div ng-class="item.name" />
This is also documented in the official documentation.
I think you missed the concept.
A conditional css class looks like this:
<div ng-class="{'<css_class_name>': <bool_condition>}">
And I dont think you want:
<div ng-class="{'true': true}">
You probally want to use:
<div ng-class="item.name"></div>
Angularjs Apply class with condition:
<div ng-class="{true:'class1',false:'class2'}[condition]" >
This can be useful in some cases:
HTML:
<div ng-class="getCssClass()"></div>
JS:
$scope.getCssClass = function () {
return { item.name: item.name };
};

AngularJS - How to show custom directives based on condition

I have to show a custom directive (i.e. task-moveable) based on some condition. I have to only show the task-movable attribute for tasks which is not completed yet. Is there any way we can do this in Angularjs?
HTML Code:
<div class="gantt-body-background" ng-repeat="row in gantt.rows" task-moveable>
....
</div>
Thanks in advance.
You could make a tweak such that your taskMoveable directive can observe a value assigned to it. From there do an $eval on the value of the taskMoveable attribute to get your boolean.
As an example:
app.directive('taskMoveable', function () {
return {
controller: function ($scope, $element, $attrs) {
$scope.taskMoveable = {};
$attrs.$observe('taskMoveable', function (value) {
if (value) {
$scope.taskMoveable.amIMoveable = $scope.$eval(value);
}
});
},
template: '<span ng-bind="taskMoveable.amIMoveable"></span>'
};
});
See my plunk here for a more detailed example:
http://plnkr.co/edit/0nK4K9j3SmNnz8PgRYfR
You could use ng-if for that whole element. Something like this.
<div class="gantt-body-background" ng-repeat="row in gantt.rows" ng-if="thing.stuff" task-moveable>
....
</div>
Then that div would only be in the DOM if thing.stuff was truthy.

Binding the placeholder to the model causes ng-change to execute on load in IE

Using angularjs, if I bind the placeholder of an input to its model, the change event is fired when the document loads in IE. This does not appear to be correct and I'm not seeing this behavior in other browsers.
JS Fiddle
Html:
<div ng-app="angularjs-starter" data-ng-controller="MainCtrl">
<div data-ui-view="viewMain">
<input
placeholder="{{theValue}}"
data-ng-model="theValue"
data-ng-change="valueChanged(theValue)" />
</div>
Javascript:
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.valueChanged = function(theValue) {
alert("Value Change Called On Load in IE.");
};
});
It's possible to use the built-in ng-attr-placeholder directive as well.
ng-attr-placeholder="{{theValue}}"
I know this is old but just in case anyone else runs in to this I created a small directive that goes around putting a dynamic value in the placeholder and instead have it assign when it changes:
.directive('dynamicPlaceholder',
function() {
return {
restrict: 'A',
link: function ($scope, element, attrs) {
attrs.$observe('dynamicPlaceholder', function(value) {
element.attr('placeholder', value);
});
}
};
});
Then to use this all you need to do is use dynamic-placeholder instead of placeholder:
<input ng-model='someValue' dynamic-placeholder='{{someDynamicPlaceholder}}' />
Not sure what is causing the problem in IE though

Resources