AngularJS: apply filter for ngStyle - angularjs

Good day for everyone!
I have a problem with understanding AngularJS. Can I use my custom filter within ngStyle directive? Why it can't change opacity of span tag at the same time when I change value in input (but it change value in markup)? How I can realize this behaviour without direct using controller scope?
My raw code:
HTML:
<div ng-app="app">
<div ng-controller="AppCtrl">
<input type="number" ng-model="slider" max="10" min="1">
<span ng-style="{'opacity': '{{slider | filter}}'}">TEXT</span>
</div>
</div>
JS:
(function () {
angular
.module('app', [])
.controller('AppCtrl', ['$scope', function ($scope) {
$scope.slider = 6;
}])
.filter('filter', function () {
return function (input) {
return 0.1 * input;
};
});
})();
My code at JSFiddle: http://jsfiddle.net/zkdkLac3/

Answering the general question, yes, generally you can use an user created filter in generic angular expressions. You might be having issues with ng-attr due to a parsing error (probably a bug in the angular parser). You can still use filters in ng-attr with
<span ng-style="{ 'opacity': (slider | opacity) }">TEXT</span>
ng-attr though is most beneficial for binding to style objects directly
<span ng-style="sliderStyle">TEXT</span>
you can also style directly by using
<span style="opacity: {{slider|opacity}}">TEXT</span>
with the below filter:
app.filter('opacity', function () {
return function (input) {
return 0.1 * input;
};
});
Working jsfiddle
Whichever solution is better mainly depends on where you plan to re-use things. Filters are available across all scopes, but this one in particular might only make sense for a given controller. Don't forget that reuse can be accomplished with directives (which can have a controller) as well.

Related

Can we write multiple calling functions in ng-click?

I know that we can give multiple classes in class directive by giving one space after declaring a class.In the same way can we write multiple passing elements and calling functions in the ng-click directive?
You have 2 options :
Create a third method that wrap both methods. Advantage here is that
you put less logic in your template.
Otherwise if you want to add 2 calls in ng-click you can add ';' after method1('test') like this
ng-click="method1('test'); method2('first','second');"
See here : http://jsfiddle.net/banshi/5kwn0an8/3/
You can use the following code to call multiple functions at a time
<button ng-click="method1(); method2();">
Submit
</button>
Yes you can. separate two functions by semicolon
<div ng-click="functionOne();functionTwo()"> </div>
angular.module("app", [])
.controller("ctrl", function($scope) {
$scope.functionOne = function() {
console.log("functionOne")
}
$scope.functionTwo = function() {
console.log("functionTwo")
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div ng-click="functionOne();functionTwo();"> click</div>
</div>

How to test for the existence of a function in ngIf

I'm trying to hide/show some HTML based on the existence of a function
<div ng-if="!!someFunc"> .... </div>
<div ng-if="someFunc !== undefined"> .... </div>
DEMO
Now the issue is that it doesn't matter if someFunc exists or not, it is always shown. Is there some way to make this work or should I create an other (boolean) variable on the scope ?
UPDATE: I've reproduced the issue here this time with angular v1.3.14
As others have pointed out now, in Angular 1.0, ng-if does not exist. If you have to stay with Angular 1.0, try ng-show instead.
EDIT: I wanted to make it clear that while ng-if and ng-show will both achieve what you are looking for in this case, they do behave differently behind the scenes. In short, when an ng-if expression evaluates to "false", the element will be removed from the DOM. When an ng-show expression evaluates to false, it simply changes the display property of your element. You can read more in detail here.
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
//$scope.test = function () {};
}
<div ng-controller="MyCtrl">
Is there a test function: {{!!test}}
<div ng-show="!!test">CLOSE</div>
</div>
It's something wrong with your AngularJs (too old may be).
I've updated it to new(1.3.14) and it works -
http://jsfiddle.net/HB7LU/15068/
Without any code change:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
//$scope.test = function () {};
}
You fiddle is using angular 1.0.1 which doesn't even contain ng-if (introduced in version 1.1.5). Update the external resource to a newer version or use one of the predefined fiddle frameworks (e.g. angular 1.2).
Both of those attempts work. Something must be wrong with your fiddle. Here's a full example:
var app = angular.module('app', []);
app.controller('Ctrl', function($scope) {
//$scope.someFunc = function() {};
});
<div ng-app="app" ng-controller="Ctrl">
<div>Some func: {{ someFunc ? 'yup' : 'nope' }}</div>
<div ng-if="!!someFunc">Has some func</div>
<div ng-if="someFunc !== undefined">Has some func</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"></script>

Avoiding too many Angularjs Directives

I have the following directive:
.directive('myDirective', function() {
restrict: 'A',
templateUrl: 'app/templates/someTemplate/html',
});
in my template (someTemplate.html) I have the following:
<div>
<div>Some div</div>
<input type="button" value="button" />
</div>
I want to add behavior to the button and div. I can go the route of adding directives like so:
<div>
<div div-click>Some div</div>
<input type="button" value="button" button-click />
</div>
and adding more directives and binding click events via element.bind(... but is there a best practice? Should I be adding behavior in the 'myDirective' containing those elements? via jQuery or jQlite . The clickable elements inside the template are not meant to be resuable..so should I just use jQuery to find those elements and bind event listeners to them? I can see how their can be a directives explosion by constantly using the directive route, what is the best practice?
The question for me would be on what exactly the directives should be for.
It sounds to me, as if you are trying to wrap functionality that you know from other frameworks like jQuery into directives. this leads to stuff like:
var app = angular.module("module.directives", []);
app.directive('myDirective', function() {
restrict: 'A',
templateUrl: 'app/templates/someTemplate/html',
link: function(scope, el) {
el.on("click", function() { console.log(42); });
}
});
While certainly possible, this is (at least for me) considered "bad" style.
The difference with Angular is, that it does not use the DOM as the "Model" part of the framework, like jQuery or Prototype do. Coming from these libraries this is something to wrap your head around, but actually, for starters, it boils down to this:
Work with the scope and let the changes to the scope be reflected in the DOM.
The reflection part is actually the short and easy one: Angular does this out of the box (i.e. "most of the time").
Reconsidering your example with the click - Angular provides excellent event handlers in the form of directives. ng-click is a very good example for this:
<div>
<div ng-click="method()">Some div</div>
<input type="button" value="button" ng-click="method2()" />
</div>
This directive takes an expression - it looks a bit like the old days, where you would bind javascript directly to elements, like this:
here
It's way different though - Angular will look for the names method and method2 on the current scope you are in. Which scope you are currently in depends on the circumstances (I heavily suggest the docs at this point)
For all of our intents and purposes, lets say, you configure a controller inside your directive from earlier:
var app = angular.module("module.directives", []);
app.directive('myDirective', function() {
restrict: 'A',
templateUrl: 'app/templates/someTemplate/html',
controller: ['$scope', function(scope) {
scope.active = false;
scope.method = function() { console.log(42); };
scope.method2 = function() { scope.active = !scope.active };
}]
});
You can define this in many places, even as late as during the link phase of a directive. You can also create an extra controller in a separate module. But let's just stick with this for a moment:
In the template - when you click on your div the scope's method will be called. Nothing fancy, just console output. method2 is a little bit more interesting - it changes the active variable on the scope. And you can use this to your advantage:
<div>
<div ng-click="method()">Some div</div>
<input type="button" value="button" ng-click="method2()" />
<span ng-show="active">Active</span>
</div>
When you click on your button, the span will be turned on and of - the ng-show directive handles this for you.
This has gotten a bit longer than expected - I hope though, that this sheds some light on the "best practises" (which are quite dependent on what you actually want to accomplish).

AngularJS prevent default select directive

In my case AngularJS's select is not a good fit - (with ng-repeat approach <option> values can only be strings and with ng-options I can't properly set the initial selected value).
What can I do to stop angular from applying select directive everywhere he sees <select> element ?
The reason I am asking this question, is because I want to apply a custom directive on select element, that would perform something similar like the original one, so they would be conflicting.
Is this what you need?
HTML:
<div ng-app="angularApp">
<div ng-controller="testCtrl">
<select ng-model="initialSelectedValue" ng-options="option for option in [1,2,3]"></select>
</div>
</div>
Javascript:
angular.module('angularApp', []);
function testCtrl($scope)
{
$scope.initialSelectedValue = 2;
}
I created the following jsfiddle for it.

AngularJs - Access to DOM element inside ng-repeat

I have the next template:
<div ng-repeat="friend in friends | filter:filterFriendsHandler">
{{friend.name}}
</div>
and in my controller i have:
$scope.filterFriendsHandler = function(friend){
//HERE I WANT TO ACCESS TO FRIEND DOM ELEMENT; to do something like this:
//$(friendElement).text('foo');
}
Thanks
I'm going to answer the specific question here, yes I understand this isn't the "angular" way of doing things. If you want to do things the "correct" way, then don't do this, use a directive. There, disclaimers aside, here's how to do it:
Basically, what you want to do is give the DOM element an ID based on the $index or a unique value in your ng-repeat object. Here, I'll just use $index.
<div ng-repeat="friend in friends" id="friend_{{$index}}" ng-bind-html="doSomethingBadToTheDom('friend_' + $index)">
{{friend.title}}
</div>
Then, inside your controller, just query the DOM for the element with that ID:
$scope.doSomethingBadToTheDom = function(ele_id) {
var element = document.getElementById(ele_id);
element.innerHTML = "I'm abusing angular";
}
We're using ng-bind-html here because the DOM element will exist when your controller function executes, in the case of something like ng-init, it won't.
Again, this goes against everything angular stands for, so if you're trying to follow angular best practices, don't do this.
I've run into situations where the technique is useful though, especially when dealing with non-angular libraries, or those times when the "angular way" is more trouble than it's worth.
You need to use a directive for that
<div ng-app="test-app" ng-controller="MyController">
<div ng-repeat="friend in friends" nop>
{{friend.title}}
</div>
</div>
JS
app.directive('nop', function(){
return {
link: function(scope, elm){
console.log('eee', elm, arguments);
elm.css('color', 'red');
}
}
});
demo: Fiddle

Resources